mirror of
https://github.com/Ponce/slackbuilds
synced 2024-11-25 10:03:03 +01:00
8728 lines
284 KiB
Diff
8728 lines
284 KiB
Diff
diff -Nur stardict-3.0.1.orig//src/gconf_file.cpp stardict-3.0.1/src/gconf_file.cpp
|
|
--- stardict-3.0.1.orig//src/gconf_file.cpp 2007-07-10 02:16:04.000000000 -0500
|
|
+++ stardict-3.0.1/src/gconf_file.cpp 2010-05-24 00:53:36.371667435 -0500
|
|
@@ -22,6 +22,8 @@
|
|
# include "config.h"
|
|
#endif
|
|
|
|
+#include <memory>
|
|
+
|
|
#include <glib/gi18n.h>
|
|
|
|
#include "gconf_file.hpp"
|
|
diff -Nur stardict-3.0.1.orig//src/gconf_file.cpp~ stardict-3.0.1/src/gconf_file.cpp~
|
|
--- stardict-3.0.1.orig//src/gconf_file.cpp~ 1969-12-31 18:00:00.000000000 -0600
|
|
+++ stardict-3.0.1/src/gconf_file.cpp~ 2007-07-10 02:16:04.000000000 -0500
|
|
@@ -0,0 +1,224 @@
|
|
+/*
|
|
+ * This file part of StarDict - A international dictionary for GNOME.
|
|
+ * http://stardict.sourceforge.net
|
|
+ * Copyright (C) 2005-2006 Evgeniy <dushistov@mail.ru>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 3 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU Library General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
+ */
|
|
+
|
|
+#ifdef HAVE_CONFIG_H
|
|
+# include "config.h"
|
|
+#endif
|
|
+
|
|
+#include <glib/gi18n.h>
|
|
+
|
|
+#include "gconf_file.hpp"
|
|
+
|
|
+gconf_file::gconf_file(const std::string& path)
|
|
+{
|
|
+ cfgname=path;
|
|
+ if ((gconf_client = gconf_client_get_default())==NULL)
|
|
+ g_warning("Cannot connect to gconf.\n");
|
|
+ else
|
|
+ gconf_client_add_dir(gconf_client, cfgname.c_str(), GCONF_CLIENT_PRELOAD_RECURSIVE, NULL);
|
|
+}
|
|
+
|
|
+gconf_file::~gconf_file()
|
|
+{
|
|
+ for (std::vector<guint>::iterator it=notification_ids.begin();
|
|
+ it!=notification_ids.end(); ++it)
|
|
+ gconf_client_notify_remove(gconf_client, *it);
|
|
+
|
|
+ if (!gconf_client)
|
|
+ return;
|
|
+ gconf_client_remove_dir(gconf_client, cfgname.c_str(), NULL);
|
|
+ g_object_unref(gconf_client);
|
|
+}
|
|
+
|
|
+bool gconf_file::read_bool(const gchar *sect, const gchar *key, bool& val)
|
|
+{
|
|
+ if (!gconf_client)
|
|
+ return false;
|
|
+
|
|
+ std::string real_key(std::string(sect)+"/"+key);
|
|
+
|
|
+ GConfValue *gval=gconf_client_get(gconf_client, real_key.c_str(), NULL);
|
|
+ if (!gval)
|
|
+ return false;
|
|
+ val=gconf_value_get_bool(gval);
|
|
+ gconf_value_free(gval);
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+bool gconf_file::read_int(const gchar *sect, const gchar *key, int& val)
|
|
+{
|
|
+ if (!gconf_client)
|
|
+ return false;
|
|
+ std::string real_key(std::string(sect)+"/"+key);
|
|
+ GConfValue *gval=gconf_client_get(gconf_client, real_key.c_str(), NULL);
|
|
+ if (!gval)
|
|
+ return false;
|
|
+ val=gconf_value_get_int(gval);
|
|
+ gconf_value_free(gval);
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+bool gconf_file::read_string(const gchar * sect, const gchar *key, std::string& val)
|
|
+{
|
|
+ if (!gconf_client)
|
|
+ return false;
|
|
+
|
|
+ std::string real_key(std::string(sect)+"/"+key);
|
|
+ gchar *gconf_val = gconf_client_get_string(gconf_client, real_key.c_str(), NULL);
|
|
+ if (gconf_val!=NULL)
|
|
+ val=gconf_val;
|
|
+
|
|
+ g_free(gconf_val);
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+bool gconf_file::read_strlist(const gchar * sect, const gchar * key, std::list<std::string>& slist)
|
|
+{
|
|
+ if (!gconf_client)
|
|
+ return false;
|
|
+
|
|
+ std::string real_key(std::string(sect)+"/"+key);
|
|
+ GSList *gslist = gconf_client_get_list(gconf_client, real_key.c_str(), GCONF_VALUE_STRING, NULL);
|
|
+ if (!gslist)
|
|
+ return false;
|
|
+
|
|
+ slist.clear();
|
|
+ GSList *p = gslist;
|
|
+ while (p) {
|
|
+ slist.push_back(static_cast<char *>(p->data));
|
|
+ g_free(p->data);
|
|
+ p=g_slist_next(p);
|
|
+ }
|
|
+ g_slist_free(gslist);
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+void gconf_file::write_bool(const gchar *sect, const gchar *key, bool val)
|
|
+{
|
|
+ if (!gconf_client)
|
|
+ return;
|
|
+ gchar *real_key=g_strdup_printf("%s/%s", sect, key);
|
|
+ gconf_client_set_bool(gconf_client, real_key, val, NULL);
|
|
+ g_free(real_key);
|
|
+}
|
|
+
|
|
+void gconf_file::write_int(const gchar *sect, const gchar *key, int val)
|
|
+{
|
|
+ if (!gconf_client)
|
|
+ return;
|
|
+ gchar *real_key=g_strdup_printf("%s/%s", sect, key);
|
|
+ gconf_client_set_int(gconf_client, real_key, val, NULL);
|
|
+ g_free(real_key);
|
|
+}
|
|
+
|
|
+void gconf_file::write_string(const gchar *sect, const gchar *key, const std::string& val)
|
|
+{
|
|
+ if(!gconf_client)
|
|
+ return;
|
|
+ gchar *real_key=g_strdup_printf("%s/%s", sect, key);
|
|
+ gconf_client_set_string(gconf_client, real_key, val.c_str(), NULL);
|
|
+ g_free(real_key);
|
|
+}
|
|
+
|
|
+void gconf_file::write_strlist(const gchar *sect, const gchar *key, const std::list<std::string>& slist)
|
|
+{
|
|
+ if (!gconf_client)
|
|
+ return;
|
|
+
|
|
+ GSList *gslist = NULL;
|
|
+ for (std::list<std::string>::const_iterator p = slist.begin();
|
|
+ p!=slist.end(); ++p)
|
|
+ gslist = g_slist_append(gslist, const_cast<char *>(p->c_str()));
|
|
+
|
|
+ gchar *real_key=g_strdup_printf("%s/%s", sect, key);
|
|
+ gconf_client_set_list(gconf_client, real_key, GCONF_VALUE_STRING, gslist, NULL);
|
|
+ g_free(real_key);
|
|
+ g_slist_free(gslist);
|
|
+}
|
|
+
|
|
+static void gconf_client_notify_func(GConfClient *client, guint cnxn_id,
|
|
+ GConfEntry *entry, gpointer user_data)
|
|
+{
|
|
+ sigc::signal<void, const baseconfval*> *ch =
|
|
+ static_cast< sigc::signal<void, const baseconfval*> *>(user_data);
|
|
+ std::auto_ptr<baseconfval> cv;
|
|
+ switch (entry->value->type) {
|
|
+ case GCONF_VALUE_BOOL:
|
|
+ cv.reset(new confval<bool>);
|
|
+ static_cast<confval<bool> *>(cv.get())->val_ =
|
|
+ gconf_value_get_bool(entry->value);
|
|
+ break;
|
|
+ case GCONF_VALUE_INT:
|
|
+ cv.reset(new confval<int>);
|
|
+ static_cast<confval<int> *>(cv.get())->val_ =
|
|
+ gconf_value_get_int(entry->value);
|
|
+ break;
|
|
+ case GCONF_VALUE_STRING: {
|
|
+ cv.reset(new confval<std::string>);
|
|
+ const gchar *gconf_val = gconf_value_get_string(entry->value);
|
|
+ if (gconf_val)
|
|
+ static_cast<confval<std::string> *>(cv.get())->val_ =
|
|
+ gconf_val;
|
|
+ }
|
|
+ case GCONF_VALUE_LIST: {
|
|
+ confval<std::list<std::string> > *newval =
|
|
+ new confval<std::list<std::string> >;
|
|
+ cv.reset(newval);
|
|
+ GSList *gslist = gconf_value_get_list(entry->value);
|
|
+
|
|
+
|
|
+ GSList *p = gslist;
|
|
+ while (p) {
|
|
+ newval->val_.push_back(static_cast<char *>(p->data));
|
|
+ p = g_slist_next(p);
|
|
+ }
|
|
+
|
|
+ }
|
|
+ break;
|
|
+ default:
|
|
+ g_assert(false);
|
|
+ return;
|
|
+ }
|
|
+ ch->emit(cv.get());
|
|
+}
|
|
+
|
|
+static void gfree_func(gpointer data)
|
|
+{
|
|
+ sigc::signal<void, const baseconfval*> *bcv =
|
|
+ static_cast< sigc::signal<void, const baseconfval*> *>(data);
|
|
+ delete bcv;
|
|
+}
|
|
+
|
|
+void gconf_file::notify_add(const gchar *sect, const gchar *key,
|
|
+ const sigc::slot<void, const baseconfval*>& slot)
|
|
+{
|
|
+ std::string name = std::string(sect) + "/" + key;
|
|
+ sigc::signal<void, const baseconfval*> *ch =
|
|
+ new sigc::signal<void, const baseconfval*>;
|
|
+ ch->connect(slot);
|
|
+ guint id = gconf_client_notify_add(gconf_client, name.c_str(),
|
|
+ gconf_client_notify_func, ch,
|
|
+ gfree_func, NULL);
|
|
+ notification_ids.push_back(id);
|
|
+}
|
|
diff -Nur stardict-3.0.1.orig//src/inifile.cpp stardict-3.0.1/src/inifile.cpp
|
|
--- stardict-3.0.1.orig//src/inifile.cpp 2007-08-01 04:43:00.000000000 -0500
|
|
+++ stardict-3.0.1/src/inifile.cpp 2010-05-24 00:53:36.372667591 -0500
|
|
@@ -25,6 +25,7 @@
|
|
#include <vector>
|
|
#include <cerrno>
|
|
#include <cstring>
|
|
+#include <cstdlib>
|
|
#include <cstdio>
|
|
#include <glib/gi18n.h>
|
|
#include <glib/gstdio.h>
|
|
diff -Nur stardict-3.0.1.orig//src/inifile.cpp~ stardict-3.0.1/src/inifile.cpp~
|
|
--- stardict-3.0.1.orig//src/inifile.cpp~ 1969-12-31 18:00:00.000000000 -0600
|
|
+++ stardict-3.0.1/src/inifile.cpp~ 2007-08-01 04:43:00.000000000 -0500
|
|
@@ -0,0 +1,272 @@
|
|
+/*
|
|
+ * This file part of StarDict - A international dictionary for GNOME.
|
|
+ * http://stardict.sourceforge.net
|
|
+ * Copyright (C) 2005-2006 Evgeniy <dushistov@mail.ru>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 3 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU Library General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
+ */
|
|
+
|
|
+#ifdef HAVE_CONFIG_H
|
|
+# include "config.h"
|
|
+#endif
|
|
+
|
|
+#include <vector>
|
|
+#include <cerrno>
|
|
+#include <cstring>
|
|
+#include <cstdio>
|
|
+#include <glib/gi18n.h>
|
|
+#include <glib/gstdio.h>
|
|
+
|
|
+#include "utils.h"
|
|
+
|
|
+#include "inifile.hpp"
|
|
+
|
|
+static const guchar NEW_STRING_SEP = 1;
|
|
+static const guchar OLD_STRING_SEP = 0xFF;
|
|
+static const gchar *myversion = "1.0";
|
|
+
|
|
+typedef ResourceWrapper<GError, GError, g_error_free> MyGError;
|
|
+
|
|
+void inifile::create_empty()
|
|
+{
|
|
+ g_key_file_set_string(gkeyfile_, "stardict-private", "version",
|
|
+ myversion);
|
|
+ save();
|
|
+ g_key_file_free(gkeyfile_);
|
|
+}
|
|
+
|
|
+void inifile::convert_from_locale_enc()
|
|
+{
|
|
+ MyGError err;
|
|
+ glib::CharStr data;
|
|
+
|
|
+ if (!g_file_get_contents(fname_.c_str(), get_addr(data), NULL,
|
|
+ get_addr(err))) {
|
|
+ g_error(("Can not read %s, reason %s\n"), fname_.c_str(),
|
|
+ err->message);
|
|
+ exit(EXIT_SUCCESS);
|
|
+ }
|
|
+
|
|
+ glib::CharStr utfdata(g_locale_to_utf8(get_impl(data), -1, NULL, NULL,
|
|
+ NULL));
|
|
+ if (!utfdata) {
|
|
+ g_error(("Can not convert ini file content to current locale\n"));
|
|
+ exit(EXIT_SUCCESS);
|
|
+ }
|
|
+
|
|
+ if (!g_file_set_contents(fname_.c_str(), get_impl(utfdata), -1, get_addr(err))) {
|
|
+ g_error("can not save content of ini file %s, reason %s\n",
|
|
+ fname_.c_str(), err->message);
|
|
+ exit(EXIT_SUCCESS);
|
|
+ }
|
|
+}
|
|
+
|
|
+inifile::inifile(const std::string& path)
|
|
+{
|
|
+ fname_ = path;
|
|
+ bool done = false;
|
|
+ while (!done) {
|
|
+ gkeyfile_ = g_key_file_new();
|
|
+ g_key_file_set_list_separator(gkeyfile_, NEW_STRING_SEP);
|
|
+/* create file if not exist, because of g_key_file can not do that */
|
|
+ if (!g_file_test(path.c_str(),
|
|
+ GFileTest(G_FILE_TEST_EXISTS |
|
|
+ G_FILE_TEST_IS_REGULAR))) {
|
|
+ create_empty();
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ MyGError err;
|
|
+ if (!g_key_file_load_from_file(gkeyfile_, path.c_str(),
|
|
+ GKeyFileFlags(G_KEY_FILE_KEEP_COMMENTS |
|
|
+ G_KEY_FILE_KEEP_TRANSLATIONS),
|
|
+ get_addr(err))) {
|
|
+ if (err->code == G_KEY_FILE_ERROR_UNKNOWN_ENCODING) {
|
|
+ g_key_file_free(gkeyfile_);
|
|
+ convert_from_locale_enc();
|
|
+ continue;
|
|
+ }
|
|
+ g_error(("Can not open config file: %s, reason: %s\n"),
|
|
+ path.c_str(), err->message);
|
|
+ exit(EXIT_FAILURE);//just in case
|
|
+ }
|
|
+
|
|
+ glib::CharStr version(g_key_file_get_string(gkeyfile_, "stardict-private",
|
|
+ "version", get_addr(err)));
|
|
+ if (err) {
|
|
+ if (err->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND &&
|
|
+ err->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND) {
|
|
+ g_error(("internal error, reason: %s\n"),
|
|
+ err->message);
|
|
+ exit(EXIT_FAILURE);//just in case
|
|
+ }
|
|
+ create_empty();
|
|
+ continue;
|
|
+ }
|
|
+ if (strcmp(get_impl(version), myversion)) {
|
|
+ g_error(("unsupported ini file format\n"));
|
|
+ exit(EXIT_FAILURE);
|
|
+ }
|
|
+ done = true;
|
|
+ }
|
|
+
|
|
+}
|
|
+
|
|
+void inifile::save()
|
|
+{
|
|
+ gsize len;
|
|
+ MyGError err;
|
|
+ glib::CharStr data(
|
|
+ g_key_file_to_data(gkeyfile_, &len, get_addr(err)));
|
|
+
|
|
+ if (err) {
|
|
+ g_warning(("internal error, reason: %s\n"),
|
|
+ err->message);
|
|
+ return;
|
|
+ }
|
|
+ FILE *f = g_fopen(fname_.c_str(), "w");
|
|
+ if (!f) {
|
|
+ g_warning(("can not open file: %s\n"),
|
|
+ fname_.c_str());
|
|
+ return;
|
|
+ }
|
|
+ size_t writeb = fwrite(get_impl(data), 1, len, f);
|
|
+ fclose(f);
|
|
+ if (writeb < len)
|
|
+ g_warning(("write to %s failed, instead of %lu,"
|
|
+ " we wrote %lu\n"), fname_.c_str(), gulong(len), gulong(writeb));
|
|
+}
|
|
+
|
|
+inifile::~inifile()
|
|
+{
|
|
+ save();
|
|
+ g_key_file_free(gkeyfile_);
|
|
+}
|
|
+
|
|
+static bool report_error(GError *err, const gchar *sect, const gchar *key)
|
|
+{
|
|
+ bool res = false;
|
|
+ if (err->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND ||
|
|
+ err->code == G_KEY_FILE_ERROR_GROUP_NOT_FOUND)
|
|
+ res = true;
|
|
+ else
|
|
+ g_warning("Can not read %s/%s value,"
|
|
+ " reason %s\n", sect, key, err->message);
|
|
+ g_error_free(err);
|
|
+ return res;
|
|
+}
|
|
+
|
|
+bool inifile::read_bool(const gchar *sect, const gchar *key, bool& val)
|
|
+{
|
|
+ GError *err = NULL;
|
|
+
|
|
+ gboolean newval = g_key_file_get_boolean(gkeyfile_, sect, key, &err);
|
|
+ if (err)
|
|
+ return report_error(err, sect, key);
|
|
+
|
|
+ val = newval;
|
|
+ return true;
|
|
+}
|
|
+
|
|
+bool inifile::read_int(const gchar *sect, const gchar *key, int& val)
|
|
+{
|
|
+ GError *err = NULL;
|
|
+ gint newval = g_key_file_get_integer(gkeyfile_, sect, key, &err);
|
|
+ if (err)
|
|
+ return report_error(err, sect, key);
|
|
+
|
|
+ val = newval;
|
|
+ return true;
|
|
+}
|
|
+
|
|
+bool inifile::read_string(const gchar * sect, const gchar *key, std::string& val)
|
|
+{
|
|
+ GError *err = NULL;
|
|
+ gchar *newval = g_key_file_get_string(gkeyfile_, sect, key, &err);
|
|
+ if (err) {
|
|
+ g_free(newval);
|
|
+ return report_error(err, sect, key);
|
|
+ }
|
|
+ val = newval;
|
|
+ g_free(newval);
|
|
+ return true;
|
|
+}
|
|
+
|
|
+bool inifile::read_strlist(const gchar *sect, const gchar * key,
|
|
+ std::list<std::string>& slist)
|
|
+{
|
|
+ GError *err = NULL;
|
|
+ gchar **newval = g_key_file_get_string_list(gkeyfile_, sect, key,
|
|
+ NULL, &err);
|
|
+ if (err) {
|
|
+ g_strfreev(newval);
|
|
+ return report_error(err, sect, key);
|
|
+ }
|
|
+ slist.clear();
|
|
+ gchar **p = newval;
|
|
+ while (*p) {
|
|
+ slist.push_back(*p);
|
|
+ ++p;
|
|
+ }
|
|
+ g_strfreev(newval);
|
|
+ return true;
|
|
+}
|
|
+
|
|
+void inifile::write_bool(const gchar *sect, const gchar *key, bool val)
|
|
+{
|
|
+ g_key_file_set_boolean(gkeyfile_, sect, key, val);
|
|
+ expose_event(sect, key, val);
|
|
+}
|
|
+
|
|
+void inifile::write_int(const gchar *sect, const gchar *key, int val)
|
|
+{
|
|
+ g_key_file_set_integer(gkeyfile_, sect, key, val);
|
|
+ expose_event(sect, key, val);
|
|
+}
|
|
+
|
|
+void inifile::write_string(const gchar *sect, const gchar *key,
|
|
+ const std::string& val)
|
|
+{
|
|
+ g_key_file_set_string(gkeyfile_, sect, key, val.c_str());
|
|
+ expose_event(sect, key, val);
|
|
+}
|
|
+
|
|
+void inifile::write_strlist(const gchar *sect, const gchar *key,
|
|
+ const std::list<std::string>& slist)
|
|
+{
|
|
+ size_t len = slist.size();
|
|
+ std::vector<const gchar *> glib_list(len + 1);
|
|
+
|
|
+ std::list<std::string>::const_iterator it;
|
|
+ size_t i;
|
|
+
|
|
+ for (it = slist.begin(), i = 0; it != slist.end(); ++it, ++i)
|
|
+ glib_list[i] = it->c_str();
|
|
+ glib_list[i] = NULL;
|
|
+ g_key_file_set_string_list(gkeyfile_, sect, key, &glib_list[0], len);
|
|
+ expose_event(sect, key, slist);
|
|
+}
|
|
+
|
|
+void inifile::notify_add(const gchar *sect, const gchar *key,
|
|
+ const sigc::slot<void, const baseconfval*>& slot)
|
|
+{
|
|
+ std::string name = std::string(sect) + "/" + key;
|
|
+
|
|
+ ChangeEventsMap::iterator it =
|
|
+ change_events_map_.insert(
|
|
+ std::make_pair(name,
|
|
+ sigc::signal<void, const baseconfval*>())).first;
|
|
+ it->second.connect(slot);
|
|
+}
|
|
diff -Nur stardict-3.0.1.orig//src/lib/common.cpp stardict-3.0.1/src/lib/common.cpp
|
|
--- stardict-3.0.1.orig//src/lib/common.cpp 2007-09-24 21:27:24.000000000 -0500
|
|
+++ stardict-3.0.1/src/lib/common.cpp 2010-05-24 00:53:36.372667591 -0500
|
|
@@ -25,6 +25,8 @@
|
|
#endif
|
|
|
|
#include "common.hpp"
|
|
+#include <cstring>
|
|
+#include <cstdlib>
|
|
|
|
static void parse_description(const char *p, long len, std::string &description)
|
|
{
|
|
diff -Nur stardict-3.0.1.orig//src/lib/common.cpp~ stardict-3.0.1/src/lib/common.cpp~
|
|
--- stardict-3.0.1.orig//src/lib/common.cpp~ 1969-12-31 18:00:00.000000000 -0600
|
|
+++ stardict-3.0.1/src/lib/common.cpp~ 2007-09-24 21:27:24.000000000 -0500
|
|
@@ -0,0 +1,221 @@
|
|
+/*
|
|
+ * This file part of StarDict - A international dictionary for GNOME.
|
|
+ * http://stardict.sourceforge.net
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 3 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU Library General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * implementation of methods of common for dictionaries structures
|
|
+ */
|
|
+#ifdef HAVE_CONFIG_H
|
|
+# include "config.h"
|
|
+#endif
|
|
+
|
|
+#include "common.hpp"
|
|
+
|
|
+static void parse_description(const char *p, long len, std::string &description)
|
|
+{
|
|
+ description.clear();
|
|
+ const char *p1 = p;
|
|
+ while (p1 - p < len) {
|
|
+ if (*p1 == '<') {
|
|
+ p1++;
|
|
+ if ((*p1 == 'b' || *p1 == 'B') && (*(p1+1)=='r' || *(p1+1)=='R') && *(p1+2)=='>') {
|
|
+ description += '\n';
|
|
+ p1+=3;
|
|
+ } else {
|
|
+ description += '<';
|
|
+ }
|
|
+ } else {
|
|
+ description += *p1;
|
|
+ p1++;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+//looks not optimal, TODO: refactor
|
|
+bool DictInfo::load_from_ifo_file(const std::string& ifofilename,
|
|
+ bool istreedict)
|
|
+{
|
|
+ ifo_file_name=ifofilename;
|
|
+ gchar *buffer;
|
|
+ if (!g_file_get_contents(ifofilename.c_str(), &buffer, NULL, NULL))
|
|
+ return false;
|
|
+
|
|
+#define TREEDICT_MAGIC_DATA "StarDict's treedict ifo file\nversion="
|
|
+#define DICT_MAGIC_DATA "StarDict's dict ifo file\nversion="
|
|
+ const gchar *magic_data=istreedict ? TREEDICT_MAGIC_DATA : DICT_MAGIC_DATA;
|
|
+ if (!g_str_has_prefix(buffer, magic_data)) {
|
|
+ g_free(buffer);
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ bool is_dict_300 = false;
|
|
+ gchar *p1;
|
|
+ if (istreedict) {
|
|
+ p1 = buffer + sizeof(TREEDICT_MAGIC_DATA) -1;
|
|
+#define TREEDICT_VERSION_242 "2.4.2\n"
|
|
+ if (g_str_has_prefix(p1, TREEDICT_VERSION_242)) {
|
|
+ p1 += sizeof(TREEDICT_VERSION_242) -2;
|
|
+ } else {
|
|
+ g_print("Load %s failed: Unknown version.\n", ifofilename.c_str());
|
|
+ g_free(buffer);
|
|
+ return false;
|
|
+ }
|
|
+ } else {
|
|
+ p1 = buffer + sizeof(DICT_MAGIC_DATA) -1;
|
|
+#define DICT_VERSION_242 "2.4.2\n"
|
|
+#define DICT_VERSION_300 "3.0.0\n"
|
|
+ if (g_str_has_prefix(p1, DICT_VERSION_242)) {
|
|
+ p1 += sizeof(DICT_VERSION_242) -2;
|
|
+ } else if (g_str_has_prefix(p1, DICT_VERSION_300)) {
|
|
+ p1 += sizeof(DICT_VERSION_300) -2;
|
|
+ is_dict_300 = true;
|
|
+ } else {
|
|
+ g_print("Load %s failed: Unknown version.\n", ifofilename.c_str());
|
|
+ g_free(buffer);
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ gchar *p2,*p3;
|
|
+
|
|
+ if (is_dict_300) {
|
|
+ p2 = strstr(p1,"\nidxoffsetbits=");
|
|
+ if (p2) {
|
|
+ p2 = p2 + sizeof("\nidxoffsetbits=") -1;
|
|
+ if (g_str_has_prefix(p2, "64\n")) {
|
|
+ // TODO
|
|
+ g_print("Load %s failed: not supported presently.\n", ifofilename.c_str());
|
|
+ g_free(buffer);
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ p2 = strstr(p1,"\nwordcount=");
|
|
+ if (!p2) {
|
|
+ g_free(buffer);
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ p3 = strchr(p2+ sizeof("\nwordcount=")-1,'\n');
|
|
+ gchar *tmpstr = (gchar *)g_memdup(p2+sizeof("\nwordcount=")-1, p3-(p2+sizeof("\nwordcount=")-1)+1);
|
|
+ tmpstr[p3-(p2+sizeof("\nwordcount=")-1)] = '\0';
|
|
+ wordcount = atol(tmpstr);
|
|
+ g_free(tmpstr);
|
|
+
|
|
+ p2 = strstr(p1,"\nsynwordcount=");
|
|
+ if (p2) {
|
|
+ p3 = strchr(p2+ sizeof("\nsynwordcount=")-1,'\n');
|
|
+ gchar *tmpstr = (gchar *)g_memdup(p2+sizeof("\nsynwordcount=")-1, p3-(p2+sizeof("\nsynwordcount=")-1)+1);
|
|
+ tmpstr[p3-(p2+sizeof("\nsynwordcount=")-1)] = '\0';
|
|
+ synwordcount = atol(tmpstr);
|
|
+ g_free(tmpstr);
|
|
+ } else {
|
|
+ synwordcount = 0;
|
|
+ }
|
|
+
|
|
+ if (istreedict) {
|
|
+ p2 = strstr(p1,"\ntdxfilesize=");
|
|
+ if (!p2) {
|
|
+ g_free(buffer);
|
|
+ return false;
|
|
+ }
|
|
+ p3 = strchr(p2+ sizeof("\ntdxfilesize=")-1,'\n');
|
|
+ tmpstr = (gchar *)g_memdup(p2+sizeof("\ntdxfilesize=")-1, p3-(p2+sizeof("\ntdxfilesize=")-1)+1);
|
|
+ tmpstr[p3-(p2+sizeof("\ntdxfilesize=")-1)] = '\0';
|
|
+ index_file_size = atol(tmpstr);
|
|
+ g_free(tmpstr);
|
|
+ } else {
|
|
+ p2 = strstr(p1,"\nidxfilesize=");
|
|
+ if (!p2) {
|
|
+ g_free(buffer);
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ p3 = strchr(p2+ sizeof("\nidxfilesize=")-1,'\n');
|
|
+ tmpstr = (gchar *)g_memdup(p2+sizeof("\nidxfilesize=")-1, p3-(p2+sizeof("\nidxfilesize=")-1)+1);
|
|
+ tmpstr[p3-(p2+sizeof("\nidxfilesize=")-1)] = '\0';
|
|
+ index_file_size = atol(tmpstr);
|
|
+ g_free(tmpstr);
|
|
+
|
|
+ p2 = strstr(p1,"\ndicttype=");
|
|
+ if (p2) {
|
|
+ p2+=sizeof("\ndicttype=")-1;
|
|
+ p3 = strchr(p2, '\n');
|
|
+ dicttype.assign(p2, p3-p2);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ p2 = strstr(p1,"\nbookname=");
|
|
+
|
|
+ if (!p2) {
|
|
+ g_free(buffer);
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ p2 = p2 + sizeof("\nbookname=") -1;
|
|
+ p3 = strchr(p2, '\n');
|
|
+ bookname.assign(p2, p3-p2);
|
|
+
|
|
+ p2 = strstr(p1,"\nauthor=");
|
|
+ if (p2) {
|
|
+ p2 = p2 + sizeof("\nauthor=") -1;
|
|
+ p3 = strchr(p2, '\n');
|
|
+ author.assign(p2, p3-p2);
|
|
+ }
|
|
+
|
|
+ p2 = strstr(p1,"\nemail=");
|
|
+ if (p2) {
|
|
+ p2 = p2 + sizeof("\nemail=") -1;
|
|
+ p3 = strchr(p2, '\n');
|
|
+ email.assign(p2, p3-p2);
|
|
+ }
|
|
+
|
|
+ p2 = strstr(p1,"\nwebsite=");
|
|
+ if (p2) {
|
|
+ p2 = p2 + sizeof("\nwebsite=") -1;
|
|
+ p3 = strchr(p2, '\n');
|
|
+ website.assign(p2, p3-p2);
|
|
+ }
|
|
+
|
|
+ p2 = strstr(p1,"\ndate=");
|
|
+ if (p2) {
|
|
+ p2 = p2 + sizeof("\ndate=") -1;
|
|
+ p3 = strchr(p2, '\n');
|
|
+ date.assign(p2, p3-p2);
|
|
+ }
|
|
+
|
|
+ p2 = strstr(p1,"\ndescription=");
|
|
+ if (p2) {
|
|
+ p2 = p2 + sizeof("\ndescription=")-1;
|
|
+ p3 = strchr(p2, '\n');
|
|
+ parse_description(p2, p3-p2, description);
|
|
+ }
|
|
+
|
|
+ p2 = strstr(p1,"\nsametypesequence=");
|
|
+ if (p2) {
|
|
+ p2+=sizeof("\nsametypesequence=")-1;
|
|
+ p3 = strchr(p2, '\n');
|
|
+ sametypesequence.assign(p2, p3-p2);
|
|
+ }
|
|
+
|
|
+ g_free(buffer);
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
diff -Nur stardict-3.0.1.orig//src/lib/data.cpp stardict-3.0.1/src/lib/data.cpp
|
|
--- stardict-3.0.1.orig//src/lib/data.cpp 2007-09-20 20:09:52.000000000 -0500
|
|
+++ stardict-3.0.1/src/lib/data.cpp 2010-05-24 00:54:04.762542528 -0500
|
|
@@ -26,7 +26,8 @@
|
|
|
|
#include "data.hpp"
|
|
#include "getuint32.h"
|
|
-
|
|
+#include <stdio.h>
|
|
+#include <cstring>
|
|
|
|
DictBase::DictBase()
|
|
{
|
|
diff -Nur stardict-3.0.1.orig//src/lib/data.cpp~ stardict-3.0.1/src/lib/data.cpp~
|
|
--- stardict-3.0.1.orig//src/lib/data.cpp~ 1969-12-31 18:00:00.000000000 -0600
|
|
+++ stardict-3.0.1/src/lib/data.cpp~ 2007-09-20 20:09:52.000000000 -0500
|
|
@@ -0,0 +1,298 @@
|
|
+/*
|
|
+ * This file part of StarDict - A international dictionary for GNOME.
|
|
+ * http://stardict.sourceforge.net
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 3 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU Library General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
+ */
|
|
+
|
|
+/* implementation of class to work with dictionary data */
|
|
+#ifdef HAVE_CONFIG_H
|
|
+# include "config.h"
|
|
+#endif
|
|
+
|
|
+#include "kmp.h"
|
|
+
|
|
+#include "data.hpp"
|
|
+#include "getuint32.h"
|
|
+
|
|
+
|
|
+DictBase::DictBase()
|
|
+{
|
|
+ dictfile = NULL;
|
|
+ cache_cur =0;
|
|
+}
|
|
+
|
|
+DictBase::~DictBase()
|
|
+{
|
|
+ if (dictfile)
|
|
+ fclose(dictfile);
|
|
+}
|
|
+
|
|
+gchar* DictBase::GetWordData(guint32 idxitem_offset, guint32 idxitem_size)
|
|
+{
|
|
+ for (int i=0; i<WORDDATA_CACHE_NUM; i++)
|
|
+ if (cache[i].data && cache[i].offset == idxitem_offset)
|
|
+ return cache[i].data;
|
|
+
|
|
+ if (dictfile)
|
|
+ fseek(dictfile, idxitem_offset, SEEK_SET);
|
|
+
|
|
+ gchar *data;
|
|
+ if (!sametypesequence.empty()) {
|
|
+ gchar *origin_data = (gchar *)g_malloc(idxitem_size);
|
|
+
|
|
+ if (dictfile)
|
|
+ fread(origin_data, idxitem_size, 1, dictfile);
|
|
+ else
|
|
+ dictdzfile->read(origin_data, idxitem_offset, idxitem_size);
|
|
+
|
|
+ guint32 data_size;
|
|
+ gint sametypesequence_len = sametypesequence.length();
|
|
+ //there have sametypesequence_len char being omitted.
|
|
+ data_size = idxitem_size + sametypesequence_len; //Here is a bug fix of 2.4.8, which don't add sizeof(guint32) anymore.
|
|
+
|
|
+ //if the last item's size is determined by the end up '\0',then +=sizeof(gchar);
|
|
+ //if the last item's size is determined by the head guint32 type data,then +=sizeof(guint32);
|
|
+ switch (sametypesequence[sametypesequence_len-1]) {
|
|
+ case 'm':
|
|
+ case 't':
|
|
+ case 'y':
|
|
+ case 'l':
|
|
+ case 'g':
|
|
+ case 'x':
|
|
+ case 'k':
|
|
+ case 'w':
|
|
+ data_size += sizeof(gchar);
|
|
+ break;
|
|
+ case 'W':
|
|
+ case 'P':
|
|
+ data_size += sizeof(guint32);
|
|
+ break;
|
|
+ default:
|
|
+ if (g_ascii_isupper(sametypesequence[sametypesequence_len-1]))
|
|
+ data_size += sizeof(guint32);
|
|
+ else
|
|
+ data_size += sizeof(gchar);
|
|
+ break;
|
|
+ }
|
|
+ data = (gchar *)g_malloc(data_size + sizeof(guint32));
|
|
+ gchar *p1,*p2;
|
|
+ p1 = data + sizeof(guint32);
|
|
+ p2 = origin_data;
|
|
+ guint32 sec_size;
|
|
+ //copy the head items.
|
|
+ for (int i=0; i<sametypesequence_len-1; i++) {
|
|
+ *p1=sametypesequence[i];
|
|
+ p1+=sizeof(gchar);
|
|
+ switch (sametypesequence[i]) {
|
|
+ case 'm':
|
|
+ case 't':
|
|
+ case 'y':
|
|
+ case 'l':
|
|
+ case 'g':
|
|
+ case 'x':
|
|
+ case 'k':
|
|
+ case 'w':
|
|
+ sec_size = strlen(p2)+1;
|
|
+ memcpy(p1, p2, sec_size);
|
|
+ p1+=sec_size;
|
|
+ p2+=sec_size;
|
|
+ break;
|
|
+ case 'W':
|
|
+ case 'P':
|
|
+ sec_size = get_uint32(p2);
|
|
+ sec_size += sizeof(guint32);
|
|
+ memcpy(p1, p2, sec_size);
|
|
+ p1+=sec_size;
|
|
+ p2+=sec_size;
|
|
+ break;
|
|
+ default:
|
|
+ if (g_ascii_isupper(sametypesequence[i])) {
|
|
+ sec_size = get_uint32(p2);
|
|
+ sec_size += sizeof(guint32);
|
|
+ } else {
|
|
+ sec_size = strlen(p2)+1;
|
|
+ }
|
|
+ memcpy(p1, p2, sec_size);
|
|
+ p1+=sec_size;
|
|
+ p2+=sec_size;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ //calculate the last item 's size.
|
|
+ sec_size = idxitem_size - (p2-origin_data);
|
|
+ *p1=sametypesequence[sametypesequence_len-1];
|
|
+ p1+=sizeof(gchar);
|
|
+ switch (sametypesequence[sametypesequence_len-1]) {
|
|
+ case 'm':
|
|
+ case 't':
|
|
+ case 'y':
|
|
+ case 'l':
|
|
+ case 'g':
|
|
+ case 'x':
|
|
+ case 'k':
|
|
+ case 'w':
|
|
+ memcpy(p1, p2, sec_size);
|
|
+ p1 += sec_size;
|
|
+ *p1='\0';//add the end up '\0';
|
|
+ break;
|
|
+ case 'W':
|
|
+ case 'P':
|
|
+ memcpy(p1, &sec_size, sizeof(guint32));
|
|
+ p1 += sizeof(guint32);
|
|
+ memcpy(p1, p2, sec_size);
|
|
+ break;
|
|
+ default:
|
|
+ if (g_ascii_isupper(sametypesequence[sametypesequence_len-1])) {
|
|
+ memcpy(p1, &sec_size, sizeof(guint32));
|
|
+ p1 += sizeof(guint32);
|
|
+ memcpy(p1, p2, sec_size);
|
|
+ } else {
|
|
+ memcpy(p1, p2, sec_size);
|
|
+ p1 += sec_size;
|
|
+ *p1='\0';
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ g_free(origin_data);
|
|
+ memcpy(data, &data_size, sizeof(guint32));
|
|
+ } else {
|
|
+ data = (gchar *)g_malloc(idxitem_size + sizeof(guint32));
|
|
+ if (dictfile)
|
|
+ fread(data+sizeof(guint32), idxitem_size, 1, dictfile);
|
|
+ else
|
|
+ dictdzfile->read(data+sizeof(guint32), idxitem_offset, idxitem_size);
|
|
+ memcpy(data, &idxitem_size, sizeof(guint32));
|
|
+ }
|
|
+ g_free(cache[cache_cur].data);
|
|
+
|
|
+ cache[cache_cur].data = data;
|
|
+ cache[cache_cur].offset = idxitem_offset;
|
|
+ cache_cur++;
|
|
+ if (cache_cur==WORDDATA_CACHE_NUM)
|
|
+ cache_cur = 0;
|
|
+ return data;
|
|
+}
|
|
+
|
|
+bool DictBase::SearchData(std::vector<std::string> &SearchWords, guint32 idxitem_offset, guint32 idxitem_size, gchar *origin_data)
|
|
+{
|
|
+ int nWord = SearchWords.size();
|
|
+ std::vector<bool> WordFind(nWord, false);
|
|
+ int nfound=0;
|
|
+
|
|
+ if (dictfile)
|
|
+ fseek(dictfile, idxitem_offset, SEEK_SET);
|
|
+ if (dictfile)
|
|
+ fread(origin_data, idxitem_size, 1, dictfile);
|
|
+ else
|
|
+ dictdzfile->read(origin_data, idxitem_offset, idxitem_size);
|
|
+ gchar *p = origin_data;
|
|
+ guint32 sec_size;
|
|
+ int j;
|
|
+ if (!sametypesequence.empty()) {
|
|
+ gint sametypesequence_len = sametypesequence.length();
|
|
+ for (int i=0; i<sametypesequence_len-1; i++) {
|
|
+ switch (sametypesequence[i]) {
|
|
+ case 'm':
|
|
+ case 't':
|
|
+ case 'y':
|
|
+ case 'l':
|
|
+ case 'g':
|
|
+ case 'x':
|
|
+ case 'k':
|
|
+ case 'w':
|
|
+ case 'h':
|
|
+ for (j=0; j<nWord; j++)
|
|
+ // KMP() is faster than strstr() in theory. Really? Always be true?
|
|
+ //if (!WordFind[j] && strstr(p, SearchWords[j].c_str())) {
|
|
+ if (!WordFind[j] && KMP(p, strlen(p), SearchWords[j].c_str())!=-1) {
|
|
+ WordFind[j] = true;
|
|
+ ++nfound;
|
|
+ }
|
|
+
|
|
+ if (nfound==nWord)
|
|
+ return true;
|
|
+ sec_size = strlen(p)+1;
|
|
+ p+=sec_size;
|
|
+ break;
|
|
+ default:
|
|
+ if (g_ascii_isupper(sametypesequence[i])) {
|
|
+ sec_size = get_uint32(p);
|
|
+ sec_size += sizeof(guint32);
|
|
+ } else {
|
|
+ sec_size = strlen(p)+1;
|
|
+ }
|
|
+ p+=sec_size;
|
|
+ }
|
|
+ }
|
|
+ switch (sametypesequence[sametypesequence_len-1]) {
|
|
+ case 'm':
|
|
+ case 't':
|
|
+ case 'y':
|
|
+ case 'l':
|
|
+ case 'g':
|
|
+ case 'x':
|
|
+ case 'k':
|
|
+ case 'w':
|
|
+ case 'h':
|
|
+ sec_size = idxitem_size - (p-origin_data);
|
|
+ for (j=0; j<nWord; j++)
|
|
+ //if (!WordFind[j] && g_strstr_len(p, sec_size, SearchWords[j].c_str())) {
|
|
+ if (!WordFind[j] && KMP(p, sec_size, SearchWords[j].c_str())!=-1) {
|
|
+ WordFind[j] = true;
|
|
+ ++nfound;
|
|
+ }
|
|
+
|
|
+ if (nfound==nWord)
|
|
+ return true;
|
|
+ break;
|
|
+ }
|
|
+ } else {
|
|
+ while (guint32(p - origin_data)<idxitem_size) {
|
|
+ switch (*p) {
|
|
+ case 'm':
|
|
+ case 't':
|
|
+ case 'y':
|
|
+ case 'l':
|
|
+ case 'g':
|
|
+ case 'x':
|
|
+ case 'k':
|
|
+ case 'w':
|
|
+ case 'h':
|
|
+ for (j=0; j<nWord; j++)
|
|
+ if (!WordFind[j] && strstr(p, SearchWords[j].c_str())) {
|
|
+ WordFind[j] = true;
|
|
+ ++nfound;
|
|
+ }
|
|
+
|
|
+ if (nfound==nWord)
|
|
+ return true;
|
|
+ sec_size = strlen(p)+1;
|
|
+ p+=sec_size;
|
|
+ break;
|
|
+ default:
|
|
+ if (g_ascii_isupper(*p)) {
|
|
+ sec_size = get_uint32(p);
|
|
+ sec_size += sizeof(guint32);
|
|
+ } else {
|
|
+ sec_size = strlen(p)+1;
|
|
+ }
|
|
+ p+=sec_size;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
diff -Nur stardict-3.0.1.orig//src/lib/http_client.h stardict-3.0.1/src/lib/http_client.h
|
|
--- stardict-3.0.1.orig//src/lib/http_client.h 2007-08-30 04:23:32.000000000 -0500
|
|
+++ stardict-3.0.1/src/lib/http_client.h 2010-05-24 00:53:36.373667747 -0500
|
|
@@ -5,6 +5,7 @@
|
|
#include "sigc++/sigc++.h"
|
|
#include <string>
|
|
#include <vector>
|
|
+#include <cstring>
|
|
|
|
#ifndef _WIN32
|
|
# include <netdb.h>
|
|
diff -Nur stardict-3.0.1.orig//src/lib/pluginmanager.cpp stardict-3.0.1/src/lib/pluginmanager.cpp
|
|
--- stardict-3.0.1.orig//src/lib/pluginmanager.cpp 2007-10-09 22:26:45.000000000 -0500
|
|
+++ stardict-3.0.1/src/lib/pluginmanager.cpp 2010-05-24 00:53:36.374667481 -0500
|
|
@@ -1,6 +1,7 @@
|
|
#include "pluginmanager.h"
|
|
#include "file.hpp"
|
|
#include <string>
|
|
+#include <cstring>
|
|
|
|
StarDictPluginBaseObject::StarDictPluginBaseObject(const char *filename, GModule *module_, plugin_configure_func_t configure_func_):
|
|
plugin_filename(filename), module(module_), configure_func(configure_func_)
|
|
diff -Nur stardict-3.0.1.orig//src/lib/stardict_client.cpp stardict-3.0.1/src/lib/stardict_client.cpp
|
|
--- stardict-3.0.1.orig//src/lib/stardict_client.cpp 2007-10-31 03:32:11.000000000 -0500
|
|
+++ stardict-3.0.1/src/lib/stardict_client.cpp 2010-05-24 00:55:03.618667273 -0500
|
|
@@ -30,6 +30,9 @@
|
|
#include "getuint32.h"
|
|
|
|
#include "stardict_client.hpp"
|
|
+#include <stdio.h>
|
|
+#include <cstdlib>
|
|
+#include <cstring>
|
|
|
|
#define PROTOCOL_VERSION "0.3"
|
|
|
|
diff -Nur stardict-3.0.1.orig//src/lib/stardict_client.cpp~ stardict-3.0.1/src/lib/stardict_client.cpp~
|
|
--- stardict-3.0.1.orig//src/lib/stardict_client.cpp~ 1969-12-31 18:00:00.000000000 -0600
|
|
+++ stardict-3.0.1/src/lib/stardict_client.cpp~ 2007-10-31 03:32:11.000000000 -0500
|
|
@@ -0,0 +1,1263 @@
|
|
+/*
|
|
+ * This file part of StarDict - A international dictionary for GNOME.
|
|
+ * http://stardict.sourceforge.net
|
|
+ * Copyright (C) 2006 Hu Zheng <huzheng_001@163.com>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 3 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU Library General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
+ */
|
|
+
|
|
+#ifdef HAVE_CONFIG_H
|
|
+# include "config.h"
|
|
+#endif
|
|
+
|
|
+#include <glib.h>
|
|
+#include <glib/gi18n.h>
|
|
+
|
|
+#include "sockets.hpp"
|
|
+#include "md5.h"
|
|
+#include "getuint32.h"
|
|
+
|
|
+#include "stardict_client.hpp"
|
|
+
|
|
+#define PROTOCOL_VERSION "0.3"
|
|
+
|
|
+#define CODE_HELLO 220 /* text msg-id */
|
|
+#define CODE_GOODBYE 221 /* Closing Connection */
|
|
+#define CODE_OK 250 /* ok */
|
|
+#define CODE_TEMPORARILY_UNAVAILABLE 420 /* server unavailable */
|
|
+#define CODE_SYNTAX_ERROR 500 /* syntax, command not recognized */
|
|
+#define CODE_DENIED 521
|
|
+#define CODE_DICTMASK_NOTSET 522
|
|
+
|
|
+unsigned int STARDICT::Cmd::next_seq = 1;
|
|
+
|
|
+sigc::signal<void, const char *> StarDictClient::on_error_;
|
|
+sigc::signal<void, const struct STARDICT::LookupResponse *, unsigned int> StarDictClient::on_lookup_end_;
|
|
+sigc::signal<void, const struct STARDICT::LookupResponse *, unsigned int> StarDictClient::on_floatwin_lookup_end_;
|
|
+sigc::signal<void, const char *> StarDictClient::on_register_end_;
|
|
+sigc::signal<void, const char *> StarDictClient::on_getdictmask_end_;
|
|
+sigc::signal<void, const char *> StarDictClient::on_dirinfo_end_;
|
|
+sigc::signal<void, const char *> StarDictClient::on_dictinfo_end_;
|
|
+sigc::signal<void, int> StarDictClient::on_maxdictcount_end_;
|
|
+sigc::signal<void, std::list<char *> *> StarDictClient::on_previous_end_;
|
|
+sigc::signal<void, std::list<char *> *> StarDictClient::on_next_end_;
|
|
+
|
|
+static void arg_escape(std::string &earg, const char *arg)
|
|
+{
|
|
+ earg.clear();
|
|
+ while (*arg) {
|
|
+ if (*arg=='\\') {
|
|
+ earg+="\\\\";
|
|
+ } else if (*arg==' ') {
|
|
+ earg+="\\ ";
|
|
+ } else if (*arg=='\n') {
|
|
+ earg+="\\n";
|
|
+ } else {
|
|
+ earg+=*arg;
|
|
+ }
|
|
+ arg++;
|
|
+ }
|
|
+}
|
|
+
|
|
+STARDICT::Cmd::Cmd(int cmd, ...)
|
|
+{
|
|
+ this->seq = this->next_seq;
|
|
+ this->next_seq++;
|
|
+ this->reading_status = 0;
|
|
+ this->command = cmd;
|
|
+ va_list ap;
|
|
+ va_start( ap, cmd );
|
|
+ switch (cmd) {
|
|
+ case CMD_CLIENT:
|
|
+ {
|
|
+ const char *client_name = va_arg( ap, const char * );
|
|
+ std::string earg1, earg2;
|
|
+ arg_escape(earg1, PROTOCOL_VERSION);
|
|
+ arg_escape(earg2, client_name);
|
|
+ this->data = g_strdup_printf("client %s %s\n", earg1.c_str(), earg2.c_str());
|
|
+ break;
|
|
+ }
|
|
+ case CMD_REGISTER:
|
|
+ {
|
|
+ const char *user = va_arg( ap, const char * );
|
|
+ const char *passwd = va_arg( ap, const char * );
|
|
+ const char *email = va_arg( ap, const char * );
|
|
+ std::string earg1, earg2, earg3;
|
|
+ arg_escape(earg1, user);
|
|
+ arg_escape(earg2, passwd);
|
|
+ arg_escape(earg3, email);
|
|
+ this->data = g_strdup_printf("register %s %s %s\n", earg1.c_str(), earg2.c_str(), earg3.c_str());
|
|
+ break;
|
|
+ }
|
|
+ /*case CMD_CHANGE_PASSWD:
|
|
+ {
|
|
+ const char *user = va_arg( ap, const char * );
|
|
+ const char *old_passwd = va_arg( ap, const char * );
|
|
+ const char *new_passwd = va_arg( ap, const char * );
|
|
+ std::string earg1, earg2, earg3;
|
|
+ arg_escape(earg1, user);
|
|
+ arg_escape(earg2, old_passwd);
|
|
+ arg_escape(earg3, new_passwd);
|
|
+ this->data = g_strdup_printf("change_password %s %s %s\n", earg1.c_str(), earg2.c_str(), earg3.c_str());
|
|
+ break;
|
|
+ }*/
|
|
+ case CMD_AUTH:
|
|
+ this->auth = new AuthInfo();
|
|
+ this->auth->user = va_arg( ap, const char * );
|
|
+ this->auth->passwd = va_arg( ap, const char * );
|
|
+ break;
|
|
+ case CMD_LOOKUP:
|
|
+ {
|
|
+ std::string earg;
|
|
+ arg_escape(earg, va_arg( ap, const char * ));
|
|
+ this->data = g_strdup_printf("lookup %s 30\n", earg.c_str());
|
|
+ this->lookup_response = NULL;
|
|
+ break;
|
|
+ }
|
|
+ case CMD_PREVIOUS:
|
|
+ {
|
|
+ std::string earg;
|
|
+ arg_escape(earg, va_arg( ap, const char * ));
|
|
+ this->data = g_strdup_printf("previous %s 15\n", earg.c_str());
|
|
+ this->wordlist_response = NULL;
|
|
+ break;
|
|
+ }
|
|
+ case CMD_NEXT:
|
|
+ {
|
|
+ std::string earg;
|
|
+ arg_escape(earg, va_arg( ap, const char * ));
|
|
+ this->data = g_strdup_printf("next %s 30\n", earg.c_str());
|
|
+ this->wordlist_response = NULL;
|
|
+ break;
|
|
+ }
|
|
+ /*case CMD_QUERY:
|
|
+ {
|
|
+ std::string earg;
|
|
+ arg_escape(earg, va_arg( ap, const char * ));
|
|
+ this->data = g_strdup_printf("query %s\n", earg.c_str());
|
|
+ this->lookup_response = NULL;
|
|
+ break;
|
|
+ }*/
|
|
+ case CMD_SELECT_QUERY:
|
|
+ {
|
|
+ std::string earg;
|
|
+ arg_escape(earg, va_arg( ap, const char * ));
|
|
+ this->data = g_strdup_printf("selectquery %s\n", earg.c_str());
|
|
+ this->lookup_response = NULL;
|
|
+ break;
|
|
+ }
|
|
+ case CMD_SMART_QUERY:
|
|
+ {
|
|
+ std::string earg;
|
|
+ arg_escape(earg, va_arg( ap, const char * ));
|
|
+ int BeginPos = va_arg( ap, int );
|
|
+ this->data = g_strdup_printf("smartquery %s %d\n", earg.c_str(), BeginPos);
|
|
+ this->lookup_response = NULL;
|
|
+ break;
|
|
+ }
|
|
+ case CMD_DEFINE:
|
|
+ {
|
|
+ std::string earg;
|
|
+ arg_escape(earg, va_arg( ap, const char * ));
|
|
+ this->data = g_strdup_printf("define %s\n", earg.c_str());
|
|
+ this->lookup_response = NULL;
|
|
+ break;
|
|
+ }
|
|
+ case CMD_SET_DICT_MASK:
|
|
+ {
|
|
+ std::string earg;
|
|
+ arg_escape(earg, va_arg( ap, const char * ));
|
|
+ this->data = g_strdup_printf("setdictmask %s\n", earg.c_str());
|
|
+ break;
|
|
+ }
|
|
+ case CMD_GET_DICT_MASK:
|
|
+ this->data = g_strdup("getdictmask\n");
|
|
+ break;
|
|
+ /*case CMD_SET_COLLATE_FUNC:
|
|
+ {
|
|
+ std::string earg;
|
|
+ arg_escape(earg, va_arg( ap, const char * ));
|
|
+ this->data = g_strdup_printf("setcollatefunc %s\n", earg.c_str());
|
|
+ break;
|
|
+ }
|
|
+ case CMD_GET_COLLATE_FUNC:
|
|
+ this->data = g_strdup("getcollatefunc\n");
|
|
+ break;
|
|
+ case CMD_SET_LANGUAGE:
|
|
+ {
|
|
+ std::string earg;
|
|
+ arg_escape(earg, va_arg( ap, const char * ));
|
|
+ this->data = g_strdup_printf("setlanguage %s\n", earg.c_str());
|
|
+ break;
|
|
+ }
|
|
+ case CMD_GET_LANGUAGE:
|
|
+ this->data = g_strdup("getlanguage\n");
|
|
+ break;
|
|
+ case CMD_SET_EMAIL:
|
|
+ {
|
|
+ std::string earg;
|
|
+ arg_escape(earg, va_arg( ap, const char * ));
|
|
+ this->data = g_strdup_printf("setemail %s\n", earg.c_str());
|
|
+ break;
|
|
+ }
|
|
+ case CMD_GET_EMAIL:
|
|
+ this->data = g_strdup("getemail\n");
|
|
+ break;
|
|
+ case CMD_GET_USER_LEVEL:
|
|
+ this->data = g_strdup("getuserlevel\n");
|
|
+ break;*/
|
|
+ case CMD_MAX_DICT_COUNT:
|
|
+ this->data = g_strdup("maxdictcount\n");
|
|
+ break;
|
|
+ case CMD_DIR_INFO:
|
|
+ {
|
|
+ std::string earg;
|
|
+ arg_escape(earg, va_arg( ap, const char * ));
|
|
+ this->data = g_strdup_printf("dirinfo %s\n", earg.c_str());
|
|
+ break;
|
|
+ }
|
|
+ case CMD_DICT_INFO:
|
|
+ {
|
|
+ std::string earg;
|
|
+ arg_escape(earg, va_arg( ap, const char * ));
|
|
+ this->data = g_strdup_printf("dictinfo %s\n", earg.c_str());
|
|
+ break;
|
|
+ }
|
|
+ /*case CMD_USER_LEVEL:
|
|
+ {
|
|
+ std::string earg1, earg2, earg3;
|
|
+ arg_escape(earg1, va_arg( ap, const char * ));
|
|
+ arg_escape(earg2, va_arg( ap, const char * ));
|
|
+ arg_escape(earg3, va_arg( ap, const char * ));
|
|
+ this->data = g_strdup_printf("userlevel %s %s %s\n", earg1.c_str(), earg2.c_str(), earg3.c_str());
|
|
+ break;
|
|
+ }*/
|
|
+ case CMD_QUIT:
|
|
+ this->data = g_strdup("quit\n");
|
|
+ break;
|
|
+ }
|
|
+ va_end( ap );
|
|
+}
|
|
+
|
|
+STARDICT::LookupResponse::DictResponse::DictResponse()
|
|
+{
|
|
+ oword = NULL;
|
|
+}
|
|
+
|
|
+STARDICT::LookupResponse::DictResponse::~DictResponse()
|
|
+{
|
|
+ g_free(oword);
|
|
+ for (std::list<DictResult *>::iterator i = dict_result_list.begin(); i != dict_result_list.end(); ++i) {
|
|
+ delete *i;
|
|
+ }
|
|
+}
|
|
+
|
|
+STARDICT::LookupResponse::DictResponse::DictResult::DictResult()
|
|
+{
|
|
+ bookname = NULL;
|
|
+}
|
|
+
|
|
+STARDICT::LookupResponse::DictResponse::DictResult::~DictResult()
|
|
+{
|
|
+ g_free(bookname);
|
|
+ for (std::list<WordResult *>::iterator i = word_result_list.begin(); i != word_result_list.end(); ++i) {
|
|
+ delete *i;
|
|
+ }
|
|
+}
|
|
+
|
|
+STARDICT::LookupResponse::DictResponse::DictResult::WordResult::WordResult()
|
|
+{
|
|
+ word = NULL;
|
|
+}
|
|
+
|
|
+STARDICT::LookupResponse::DictResponse::DictResult::WordResult::~WordResult()
|
|
+{
|
|
+ g_free(word);
|
|
+ for (std::list<char *>::iterator i = datalist.begin(); i != datalist.end(); ++i) {
|
|
+ g_free(*i);
|
|
+ }
|
|
+}
|
|
+
|
|
+STARDICT::LookupResponse::~LookupResponse()
|
|
+{
|
|
+ if (listtype == ListType_List) {
|
|
+ for (std::list<char *>::iterator i = wordlist->begin(); i != wordlist->end(); ++i) {
|
|
+ g_free(*i);
|
|
+ }
|
|
+ delete wordlist;
|
|
+ } else if (listtype == ListType_Tree) {
|
|
+ for (std::list<WordTreeElement *>::iterator i = wordtree->begin(); i != wordtree->end(); ++i) {
|
|
+ g_free((*i)->bookname);
|
|
+ for (std::list<char *>::iterator j = (*i)->wordlist.begin(); j != (*i)->wordlist.end(); ++j) {
|
|
+ g_free(*j);
|
|
+ }
|
|
+ delete *i;
|
|
+ }
|
|
+ delete wordtree;
|
|
+ }
|
|
+}
|
|
+
|
|
+STARDICT::Cmd::~Cmd()
|
|
+{
|
|
+ if (this->command == CMD_AUTH) {
|
|
+ delete this->auth;
|
|
+ } else {
|
|
+ g_free(this->data);
|
|
+ }
|
|
+ if (this->command == CMD_LOOKUP || this->command == CMD_DEFINE || this->command == CMD_SELECT_QUERY || this->command == CMD_SMART_QUERY) {
|
|
+ delete this->lookup_response;
|
|
+ } else if (this->command == CMD_PREVIOUS || this->command == CMD_NEXT) {
|
|
+ if (this->wordlist_response) {
|
|
+ for (std::list<char *>::iterator i = this->wordlist_response->begin(); i != this->wordlist_response->end(); ++i) {
|
|
+ g_free(*i);
|
|
+ }
|
|
+ delete this->wordlist_response;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+StarDictCache::StarDictCache()
|
|
+{
|
|
+ str_pool.resize(str_pool_size);
|
|
+ for (size_t i = 0; i< str_pool_size; i++) {
|
|
+ str_pool[i] = NULL;
|
|
+ }
|
|
+ cur_str_pool_pos = 0;
|
|
+
|
|
+ lookup_response_pool.resize(lookup_response_pool_size);
|
|
+ for (size_t i = 0; i< lookup_response_pool_size; i++) {
|
|
+ lookup_response_pool[i] = NULL;
|
|
+ }
|
|
+ cur_lookup_response_pool_pos = 0;
|
|
+}
|
|
+
|
|
+StarDictCache::~StarDictCache()
|
|
+{
|
|
+ clean_all_cache();
|
|
+}
|
|
+
|
|
+void StarDictCache::clean_all_cache()
|
|
+{
|
|
+ for (std::vector<StrElement *>::iterator i = str_pool.begin(); i != str_pool.end(); ++i) {
|
|
+ if (*i) {
|
|
+ g_free((*i)->data);
|
|
+ delete *i;
|
|
+ *i = NULL;
|
|
+ }
|
|
+ }
|
|
+ clean_cache_lookup_response();
|
|
+}
|
|
+
|
|
+void StarDictCache::clean_cache_lookup_response()
|
|
+{
|
|
+ for (std::vector<LookupResponseElement *>::iterator i = lookup_response_pool.begin(); i != lookup_response_pool.end(); ++i) {
|
|
+ if (*i) {
|
|
+ delete ((*i)->lookup_response);
|
|
+ delete *i;
|
|
+ *i = NULL;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+char *StarDictCache::get_cache_str(const char *key_str)
|
|
+{
|
|
+ for (std::vector<StrElement *>::iterator i = str_pool.begin(); i != str_pool.end(); ++i) {
|
|
+ if (*i) {
|
|
+ if ((*i)->key == key_str)
|
|
+ return (*i)->data;
|
|
+ }
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+STARDICT::LookupResponse *StarDictCache::get_cache_lookup_response(const char *key_str)
|
|
+{
|
|
+ for (std::vector<LookupResponseElement *>::iterator i = lookup_response_pool.begin(); i != lookup_response_pool.end(); ++i) {
|
|
+ if (*i) {
|
|
+ if ((*i)->key == key_str)
|
|
+ return (*i)->lookup_response;
|
|
+ }
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+void StarDictCache::clean_cache_str(const char *key_str)
|
|
+{
|
|
+ for (std::vector<StrElement *>::iterator i = str_pool.begin(); i != str_pool.end(); ++i) {
|
|
+ if (*i) {
|
|
+ if ((*i)->key == key_str) {
|
|
+ g_free((*i)->data);
|
|
+ delete *i;
|
|
+ *i = NULL;
|
|
+ //return;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+void StarDictCache::save_cache_str(const char *key_str, char *data)
|
|
+{
|
|
+ if (str_pool[cur_str_pool_pos]) {
|
|
+ g_free(str_pool[cur_str_pool_pos]->data);
|
|
+ delete str_pool[cur_str_pool_pos];
|
|
+ }
|
|
+ str_pool[cur_str_pool_pos] = new StrElement();
|
|
+ str_pool[cur_str_pool_pos]->key = key_str;
|
|
+ str_pool[cur_str_pool_pos]->data = data;
|
|
+ cur_str_pool_pos++;
|
|
+ if (cur_str_pool_pos == str_pool_size)
|
|
+ cur_str_pool_pos = 0;
|
|
+}
|
|
+
|
|
+void StarDictCache::save_cache_lookup_response(const char *key_str, STARDICT::LookupResponse *lookup_response)
|
|
+{
|
|
+ if (lookup_response_pool[cur_lookup_response_pool_pos]) {
|
|
+ delete lookup_response_pool[cur_lookup_response_pool_pos]->lookup_response;
|
|
+ delete lookup_response_pool[cur_lookup_response_pool_pos];
|
|
+ }
|
|
+ lookup_response_pool[cur_lookup_response_pool_pos] = new LookupResponseElement();
|
|
+ lookup_response_pool[cur_lookup_response_pool_pos]->key = key_str;
|
|
+ lookup_response_pool[cur_lookup_response_pool_pos]->lookup_response = lookup_response;
|
|
+ cur_lookup_response_pool_pos++;
|
|
+ if (cur_lookup_response_pool_pos == lookup_response_pool_size)
|
|
+ cur_lookup_response_pool_pos = 0;
|
|
+}
|
|
+
|
|
+StarDictClient::StarDictClient()
|
|
+{
|
|
+ sd_ = -1;
|
|
+ channel_ = NULL;
|
|
+ in_source_id_ = 0;
|
|
+ out_source_id_ = 0;
|
|
+ is_connected_ = false;
|
|
+}
|
|
+
|
|
+StarDictClient::~StarDictClient()
|
|
+{
|
|
+ disconnect();
|
|
+}
|
|
+
|
|
+void StarDictClient::set_server(const char *host, int port)
|
|
+{
|
|
+ if (host_ != host || port_ != port) {
|
|
+ host_ = host;
|
|
+ port_ = port;
|
|
+ host_resolved = false;
|
|
+ clean_all_cache();
|
|
+ }
|
|
+}
|
|
+
|
|
+void StarDictClient::set_auth(const char *user, const char *md5passwd)
|
|
+{
|
|
+ if (user_ != user || md5passwd_ != md5passwd) {
|
|
+ user_ = user;
|
|
+ md5passwd_ = md5passwd;
|
|
+ clean_all_cache();
|
|
+ }
|
|
+}
|
|
+
|
|
+bool StarDictClient::try_cache(STARDICT::Cmd *c)
|
|
+{
|
|
+ if (c->command == STARDICT::CMD_LOOKUP || c->command == STARDICT::CMD_DEFINE || c->command == STARDICT::CMD_SELECT_QUERY || c->command == STARDICT::CMD_SMART_QUERY) {
|
|
+ STARDICT::LookupResponse *res = get_cache_lookup_response(c->data);
|
|
+ if (res) {
|
|
+ if (c->command == STARDICT::CMD_LOOKUP || c->command == STARDICT::CMD_DEFINE)
|
|
+ on_lookup_end_.emit(res, 0);
|
|
+ else if (c->command == STARDICT::CMD_SELECT_QUERY || c->command == STARDICT::CMD_SMART_QUERY)
|
|
+ on_floatwin_lookup_end_.emit(res, 0);
|
|
+ delete c;
|
|
+ return true;
|
|
+ } else {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+ if (c->command == STARDICT::CMD_PREVIOUS || c->command == STARDICT::CMD_NEXT) {
|
|
+ // Not implemented yet.
|
|
+ return false;
|
|
+ }
|
|
+ char *data = get_cache_str(c->data);
|
|
+ if (data) {
|
|
+ switch (c->command) {
|
|
+ case STARDICT::CMD_DIR_INFO:
|
|
+ on_dirinfo_end_.emit(data);
|
|
+ break;
|
|
+ case STARDICT::CMD_DICT_INFO:
|
|
+ on_dictinfo_end_.emit(data);
|
|
+ break;
|
|
+ case STARDICT::CMD_GET_DICT_MASK:
|
|
+ on_getdictmask_end_.emit(data);
|
|
+ break;
|
|
+ case STARDICT::CMD_MAX_DICT_COUNT:
|
|
+ on_maxdictcount_end_.emit(atoi(data));
|
|
+ break;
|
|
+ }
|
|
+ delete c;
|
|
+ return true;
|
|
+ } else {
|
|
+ return false;
|
|
+ }
|
|
+}
|
|
+
|
|
+void StarDictClient::send_commands(int num, ...)
|
|
+{
|
|
+ STARDICT::Cmd *c;
|
|
+ if (!is_connected_) {
|
|
+#ifdef _WIN32
|
|
+ c = new STARDICT::Cmd(STARDICT::CMD_CLIENT, "StarDict Windows");
|
|
+#else
|
|
+ c = new STARDICT::Cmd(STARDICT::CMD_CLIENT, "StarDict Linux");
|
|
+#endif
|
|
+ cmdlist.push_back(c);
|
|
+ if (!user_.empty() && !md5passwd_.empty()) {
|
|
+ c = new STARDICT::Cmd(STARDICT::CMD_AUTH, user_.c_str(), md5passwd_.c_str());
|
|
+ cmdlist.push_back(c);
|
|
+ }
|
|
+ }
|
|
+ va_list ap;
|
|
+ va_start( ap, num);
|
|
+ for (int i = 0; i< num; i++) {
|
|
+ c = va_arg( ap, STARDICT::Cmd *);
|
|
+ cmdlist.push_back(c);
|
|
+ }
|
|
+ va_end( ap );
|
|
+ if (!is_connected_) {
|
|
+ waiting_banner_ = true;
|
|
+ connect();
|
|
+ }
|
|
+}
|
|
+
|
|
+void StarDictClient::try_cache_or_send_commands(int num, ...)
|
|
+{
|
|
+ STARDICT::Cmd *c;
|
|
+ std::list<STARDICT::Cmd *> send_cmdlist;
|
|
+ va_list ap;
|
|
+ va_start( ap, num);
|
|
+ for (int i = 0; i< num; i++) {
|
|
+ c = va_arg( ap, STARDICT::Cmd *);
|
|
+ if (!try_cache(c)) {
|
|
+ send_cmdlist.push_back(c);
|
|
+ }
|
|
+ }
|
|
+ va_end( ap );
|
|
+ if (send_cmdlist.empty())
|
|
+ return;
|
|
+
|
|
+ if (!is_connected_) {
|
|
+#ifdef _WIN32
|
|
+ c = new STARDICT::Cmd(STARDICT::CMD_CLIENT, "StarDict Windows");
|
|
+#else
|
|
+ c = new STARDICT::Cmd(STARDICT::CMD_CLIENT, "StarDict Linux");
|
|
+#endif
|
|
+ cmdlist.push_back(c);
|
|
+ if (!user_.empty() && !md5passwd_.empty()) {
|
|
+ c = new STARDICT::Cmd(STARDICT::CMD_AUTH, user_.c_str(), md5passwd_.c_str());
|
|
+ cmdlist.push_back(c);
|
|
+ }
|
|
+ }
|
|
+ for (std::list<STARDICT::Cmd *>::iterator i = send_cmdlist.begin(); i!= send_cmdlist.end(); ++i) {
|
|
+ cmdlist.push_back(*i);
|
|
+ }
|
|
+ if (!is_connected_) {
|
|
+ waiting_banner_ = true;
|
|
+ connect();
|
|
+ }
|
|
+}
|
|
+
|
|
+void StarDictClient::write_str(const char *str, GError **err)
|
|
+{
|
|
+ int len = strlen(str);
|
|
+ int left_byte = len;
|
|
+ GIOStatus res;
|
|
+ gsize bytes_written;
|
|
+ while (left_byte) {
|
|
+ res = g_io_channel_write_chars(channel_, str+(len - left_byte), left_byte, &bytes_written, err);
|
|
+ if (res == G_IO_STATUS_ERROR) {
|
|
+ disconnect();
|
|
+ return;
|
|
+ }
|
|
+ left_byte -= bytes_written;
|
|
+ }
|
|
+ res = g_io_channel_flush(channel_, err);
|
|
+ if (res == G_IO_STATUS_ERROR) {
|
|
+ disconnect();
|
|
+ }
|
|
+ if (out_source_id_ == 0)
|
|
+ out_source_id_ = g_io_add_watch(channel_, GIOCondition(G_IO_OUT), on_io_out_event, this);
|
|
+}
|
|
+
|
|
+void StarDictClient::request_command()
|
|
+{
|
|
+ reading_type_ = READ_LINE;
|
|
+ if (cmdlist.empty()) {
|
|
+ cmdlist.push_back(new STARDICT::Cmd(STARDICT::CMD_QUIT));
|
|
+ }
|
|
+ STARDICT::Cmd *c = cmdlist.front();
|
|
+ switch (c->command) {
|
|
+ case STARDICT::CMD_AUTH:
|
|
+ {
|
|
+ struct MD5Context ctx;
|
|
+ unsigned char digest[16];
|
|
+ char hex[33];
|
|
+ int i;
|
|
+ MD5Init(&ctx);
|
|
+ MD5Update(&ctx, (const unsigned char*)cmd_reply.daemonStamp.c_str(), cmd_reply.daemonStamp.length());
|
|
+ MD5Update(&ctx, (const unsigned char*)(c->auth->passwd.c_str()), c->auth->passwd.length());
|
|
+ MD5Final(digest, &ctx );
|
|
+ for (i = 0; i < 16; i++)
|
|
+ sprintf( hex+2*i, "%02x", digest[i] );
|
|
+ hex[32] = '\0';
|
|
+ std::string earg1, earg2;
|
|
+ arg_escape(earg1, c->auth->user.c_str());
|
|
+ arg_escape(earg2, hex);
|
|
+ char *data = g_strdup_printf("auth %s %s\n", earg1.c_str(), earg2.c_str());
|
|
+ GError *err = NULL;
|
|
+ write_str(data, &err);
|
|
+ g_free(data);
|
|
+ if (err) {
|
|
+ on_error_.emit(err->message);
|
|
+ g_error_free(err);
|
|
+ return;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ default:
|
|
+ {
|
|
+ GError *err = NULL;
|
|
+ write_str(c->data, &err);
|
|
+ if (err) {
|
|
+ on_error_.emit(err->message);
|
|
+ g_error_free(err);
|
|
+ return;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ return;
|
|
+}
|
|
+
|
|
+void StarDictClient::clean_command()
|
|
+{
|
|
+ for (std::list<STARDICT::Cmd *>::iterator i=cmdlist.begin(); i!=cmdlist.end(); ++i) {
|
|
+ delete *i;
|
|
+ }
|
|
+ cmdlist.clear();
|
|
+}
|
|
+
|
|
+void StarDictClient::connect()
|
|
+{
|
|
+ if (host_resolved) {
|
|
+ on_resolved(this, true, sa);
|
|
+ } else {
|
|
+ Socket::resolve(host_, this, on_resolved);
|
|
+ }
|
|
+}
|
|
+
|
|
+void StarDictClient::on_resolved(gpointer data, bool resolved, in_addr_t sa_)
|
|
+{
|
|
+ StarDictClient *oStarDictClient = (StarDictClient *)data;
|
|
+ if (!resolved) {
|
|
+ static bool showed_once = false;
|
|
+ if (!showed_once) {
|
|
+ showed_once = true;
|
|
+ gchar *mes = g_strdup_printf("Can not reslove %s: %s\n",
|
|
+ oStarDictClient->host_.c_str(), Socket::get_error_msg().c_str());
|
|
+ on_error_.emit(mes);
|
|
+ g_free(mes);
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (oStarDictClient->host_resolved == false) {
|
|
+ oStarDictClient->sa = sa_;
|
|
+ oStarDictClient->host_resolved = true;
|
|
+ }
|
|
+
|
|
+ oStarDictClient->sd_ = Socket::socket();
|
|
+
|
|
+ if (oStarDictClient->sd_ == -1) {
|
|
+ std::string str = "Can not create socket: " + Socket::get_error_msg();
|
|
+ on_error_.emit(str.c_str());
|
|
+ return;
|
|
+ }
|
|
+ Socket::connect(oStarDictClient->sd_, sa_, oStarDictClient->port_, oStarDictClient, on_connected);
|
|
+}
|
|
+
|
|
+void StarDictClient::on_connected(gpointer data, bool succeeded)
|
|
+{
|
|
+ StarDictClient *oStarDictClient = (StarDictClient *)data;
|
|
+ if (!succeeded) {
|
|
+ static bool showed_once = false;
|
|
+ if (!showed_once) {
|
|
+ showed_once = true;
|
|
+ gchar *mes = g_strdup_printf("Can not connect to %s: %s\n",
|
|
+ oStarDictClient->host_.c_str(), Socket::get_error_msg().c_str());
|
|
+ on_error_.emit(mes);
|
|
+ g_free(mes);
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+#ifdef _WIN32
|
|
+ oStarDictClient->channel_ = g_io_channel_win32_new_socket(oStarDictClient->sd_);
|
|
+#else
|
|
+ oStarDictClient->channel_ = g_io_channel_unix_new(oStarDictClient->sd_);
|
|
+#endif
|
|
+
|
|
+ g_io_channel_set_encoding(oStarDictClient->channel_, NULL, NULL);
|
|
+
|
|
+ /* make sure that the channel is non-blocking */
|
|
+ int flags = g_io_channel_get_flags(oStarDictClient->channel_);
|
|
+ flags |= G_IO_FLAG_NONBLOCK;
|
|
+ GError *err = NULL;
|
|
+ g_io_channel_set_flags(oStarDictClient->channel_, GIOFlags(flags), &err);
|
|
+ if (err) {
|
|
+ g_io_channel_unref(oStarDictClient->channel_);
|
|
+ oStarDictClient->channel_ = NULL;
|
|
+ gchar *str = g_strdup_printf("Unable to set the channel as non-blocking: %s", err->message);
|
|
+ on_error_.emit(str);
|
|
+ g_free(str);
|
|
+ g_error_free(err);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ oStarDictClient->is_connected_ = true;
|
|
+ oStarDictClient->waiting_banner_ = true;
|
|
+ oStarDictClient->reading_type_ = READ_LINE;
|
|
+ oStarDictClient->in_source_id_ = g_io_add_watch(oStarDictClient->channel_, GIOCondition(G_IO_IN | G_IO_ERR), on_io_in_event, oStarDictClient);
|
|
+}
|
|
+
|
|
+void StarDictClient::disconnect()
|
|
+{
|
|
+ clean_command();
|
|
+ if (in_source_id_) {
|
|
+ g_source_remove(in_source_id_);
|
|
+ in_source_id_ = 0;
|
|
+ }
|
|
+ if (out_source_id_) {
|
|
+ g_source_remove(out_source_id_);
|
|
+ out_source_id_ = 0;
|
|
+ }
|
|
+
|
|
+ if (channel_) {
|
|
+ g_io_channel_shutdown(channel_, TRUE, NULL);
|
|
+ g_io_channel_unref(channel_);
|
|
+ channel_ = NULL;
|
|
+ }
|
|
+ if (sd_ != -1) {
|
|
+ Socket::close(sd_);
|
|
+ sd_ = -1;
|
|
+ }
|
|
+ is_connected_ = false;
|
|
+}
|
|
+
|
|
+gboolean StarDictClient::on_io_out_event(GIOChannel *ch, GIOCondition cond,
|
|
+ gpointer user_data)
|
|
+{
|
|
+ StarDictClient *stardict_client = static_cast<StarDictClient *>(user_data);
|
|
+ GError *err = NULL;
|
|
+ GIOStatus res = g_io_channel_flush(stardict_client->channel_, &err);
|
|
+ if (res == G_IO_STATUS_AGAIN) {
|
|
+ return TRUE;
|
|
+ } else if (err) {
|
|
+ on_error_.emit(err->message);
|
|
+ g_error_free(err);
|
|
+ }
|
|
+ stardict_client->out_source_id_ = 0;
|
|
+ return FALSE;
|
|
+}
|
|
+
|
|
+gboolean StarDictClient::on_io_in_event(GIOChannel *ch, GIOCondition cond,
|
|
+ gpointer user_data)
|
|
+{
|
|
+ StarDictClient *stardict_client = static_cast<StarDictClient *>(user_data);
|
|
+
|
|
+ if (!stardict_client->channel_) {
|
|
+ //g_warning("No channel available\n");
|
|
+ return FALSE;
|
|
+ }
|
|
+ if (cond & G_IO_ERR) {
|
|
+ /*gchar *mes =
|
|
+ g_strdup_printf("Connection failed to the dictionary server at %s:%d",
|
|
+ stardict_client->host_.c_str(), stardict_client->port_);
|
|
+ on_error_.emit(mes);
|
|
+ g_free(mes);*/
|
|
+ stardict_client->disconnect();
|
|
+ return FALSE;
|
|
+ }
|
|
+ GError *err = NULL;
|
|
+ gsize term, len;
|
|
+ gchar *line;
|
|
+ GIOStatus res;
|
|
+
|
|
+ for (;;) {
|
|
+ if (!stardict_client->channel_)
|
|
+ break;
|
|
+ bool result;
|
|
+ if (stardict_client->reading_type_ == READ_SIZE) {
|
|
+ gsize bytes_read;
|
|
+ res = g_io_channel_read_chars(stardict_client->channel_, stardict_client->size_data+(stardict_client->size_count-stardict_client->size_left), stardict_client->size_left, &bytes_read, &err);
|
|
+ if (res == G_IO_STATUS_ERROR || res == G_IO_STATUS_EOF) {
|
|
+ if (err) {
|
|
+ gchar *str = g_strdup_printf("Error while reading reply from server: %s", err->message);
|
|
+ on_error_.emit(str);
|
|
+ g_free(str);
|
|
+ g_error_free(err);
|
|
+ }
|
|
+ stardict_client->disconnect();
|
|
+
|
|
+ return FALSE;
|
|
+ }
|
|
+ stardict_client->size_left -= bytes_read;
|
|
+ if (stardict_client->size_left == 0)
|
|
+ result = stardict_client->parse(stardict_client->size_data);
|
|
+ else
|
|
+ break;
|
|
+ } else {
|
|
+ if (stardict_client->reading_type_ == READ_LINE)
|
|
+ g_io_channel_set_line_term(stardict_client->channel_, "\n", 1);
|
|
+ else if (stardict_client->reading_type_ == READ_STRING)
|
|
+ g_io_channel_set_line_term(stardict_client->channel_, "", 1);
|
|
+
|
|
+ res = g_io_channel_read_line(stardict_client->channel_, &line,
|
|
+ &len, &term, &err);
|
|
+ if (res == G_IO_STATUS_ERROR || res == G_IO_STATUS_EOF) {
|
|
+ if (err) {
|
|
+ gchar *str = g_strdup_printf("Error while reading reply from server: %s", err->message);
|
|
+ on_error_.emit(str);
|
|
+ g_free(str);
|
|
+ g_error_free(err);
|
|
+ }
|
|
+ stardict_client->disconnect();
|
|
+
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ if (!len)
|
|
+ break;
|
|
+
|
|
+ //truncate the line terminator before parsing
|
|
+ line[term] = '\0';
|
|
+ result = stardict_client->parse(line);
|
|
+ }
|
|
+ if (!result) {
|
|
+ stardict_client->disconnect();
|
|
+ return FALSE;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+int StarDictClient::parse_banner(gchar *line)
|
|
+{
|
|
+ int status;
|
|
+ status = atoi(line);
|
|
+ if (status != CODE_HELLO) {
|
|
+ if (status == CODE_TEMPORARILY_UNAVAILABLE) {
|
|
+ printf("Server temporarily unavailable!\n");
|
|
+ } else {
|
|
+ printf("Unexpected status code %d\n", status);
|
|
+ }
|
|
+ return 0;
|
|
+ }
|
|
+ char *p;
|
|
+ p = strrchr(line, ' ');
|
|
+ if (p) {
|
|
+ p++;
|
|
+ cmd_reply.daemonStamp = p;
|
|
+ }
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+int StarDictClient::parse_command_client(gchar *line)
|
|
+{
|
|
+ int status;
|
|
+ status = atoi(line);
|
|
+ if (status != CODE_OK) {
|
|
+ gchar *str = g_strdup_printf("Client denied: %s", line);
|
|
+ on_error_.emit(str);
|
|
+ g_free(str);
|
|
+ return 0;
|
|
+ }
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+int StarDictClient::parse_command_auth(gchar *line)
|
|
+{
|
|
+ int status;
|
|
+ status = atoi(line);
|
|
+ if (status != CODE_OK) {
|
|
+ gchar *str = g_strdup_printf(_("Authentication denied: %s"), line);
|
|
+ on_error_.emit(str);
|
|
+ g_free(str);
|
|
+ return 0;
|
|
+ }
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+int StarDictClient::parse_command_register(gchar *line)
|
|
+{
|
|
+ int status;
|
|
+ status = atoi(line);
|
|
+ if (status != CODE_OK) {
|
|
+ gchar *str = g_strdup_printf(_("Register failed: %s"), line);
|
|
+ on_error_.emit(str);
|
|
+ g_free(str);
|
|
+ return 0;
|
|
+ }
|
|
+ on_register_end_.emit(_("Register success!"));
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+int StarDictClient::parse_command_quit(gchar *line)
|
|
+{
|
|
+ int status;
|
|
+ status = atoi(line);
|
|
+ if (status != CODE_GOODBYE) {
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int StarDictClient::parse_command_setdictmask(gchar *line)
|
|
+{
|
|
+ int status;
|
|
+ status = atoi(line);
|
|
+ if (status != CODE_OK) {
|
|
+ gchar *str = g_strdup_printf("Set Dict Mask failed: %s", line);
|
|
+ on_error_.emit(str);
|
|
+ g_free(str);
|
|
+ return 0;
|
|
+ }
|
|
+ clean_cache_str("getdictmask\n");
|
|
+ clean_cache_lookup_response();
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+int StarDictClient::parse_command_getdictmask(STARDICT::Cmd* cmd, gchar *buf)
|
|
+{
|
|
+ if (cmd->reading_status == 0) {
|
|
+ int status;
|
|
+ status = atoi(buf);
|
|
+ if (status != CODE_OK) {
|
|
+ g_free(buf);
|
|
+ on_error_.emit(_("You haven't setup the account. Please open the \"Net Dict\" page in the Preferences dialog and register an account first."));
|
|
+ return 0;
|
|
+ }
|
|
+ g_free(buf);
|
|
+ cmd->reading_status = 1;
|
|
+ reading_type_ = READ_STRING;
|
|
+ } else if (cmd->reading_status == 1) {
|
|
+ on_getdictmask_end_.emit(buf);
|
|
+ save_cache_str(cmd->data, buf);
|
|
+ return 1;
|
|
+ }
|
|
+ return 2;
|
|
+}
|
|
+
|
|
+int StarDictClient::parse_command_dirinfo(STARDICT::Cmd* cmd, gchar *buf)
|
|
+{
|
|
+ if (cmd->reading_status == 0) {
|
|
+ int status;
|
|
+ status = atoi(buf);
|
|
+ if (status != CODE_OK) {
|
|
+ gchar *str = g_strdup_printf("Get dir info failed: %s", buf);
|
|
+ g_free(buf);
|
|
+ on_error_.emit(str);
|
|
+ g_free(str);
|
|
+ return 0;
|
|
+ }
|
|
+ g_free(buf);
|
|
+ cmd->reading_status = 1;
|
|
+ reading_type_ = READ_STRING;
|
|
+ } else if (cmd->reading_status == 1) {
|
|
+ on_dirinfo_end_.emit(buf);
|
|
+ save_cache_str(cmd->data, buf);
|
|
+ return 1;
|
|
+ }
|
|
+ return 2;
|
|
+}
|
|
+
|
|
+int StarDictClient::parse_command_dictinfo(STARDICT::Cmd* cmd, gchar *buf)
|
|
+{
|
|
+ if (cmd->reading_status == 0) {
|
|
+ int status;
|
|
+ status = atoi(buf);
|
|
+ if (status != CODE_OK) {
|
|
+ gchar *str = g_strdup_printf("Get dict info failed: %s", buf);
|
|
+ g_free(buf);
|
|
+ on_error_.emit(str);
|
|
+ g_free(str);
|
|
+ return 0;
|
|
+ }
|
|
+ g_free(buf);
|
|
+ cmd->reading_status = 1;
|
|
+ reading_type_ = READ_STRING;
|
|
+ } else if (cmd->reading_status == 1) {
|
|
+ on_dictinfo_end_.emit(buf);
|
|
+ save_cache_str(cmd->data, buf);
|
|
+ return 1;
|
|
+ }
|
|
+ return 2;
|
|
+}
|
|
+
|
|
+int StarDictClient::parse_command_maxdictcount(STARDICT::Cmd* cmd, gchar *buf)
|
|
+{
|
|
+ if (cmd->reading_status == 0) {
|
|
+ int status;
|
|
+ status = atoi(buf);
|
|
+ if (status != CODE_OK) {
|
|
+ gchar *str = g_strdup_printf("Get max dict count failed: %s", buf);
|
|
+ g_free(buf);
|
|
+ on_error_.emit(str);
|
|
+ g_free(str);
|
|
+ return 0;
|
|
+ }
|
|
+ g_free(buf);
|
|
+ cmd->reading_status = 1;
|
|
+ reading_type_ = READ_STRING;
|
|
+ } else if (cmd->reading_status == 1) {
|
|
+ on_maxdictcount_end_.emit(atoi(buf));
|
|
+ save_cache_str(cmd->data, buf);
|
|
+ return 1;
|
|
+ }
|
|
+ return 2;
|
|
+}
|
|
+
|
|
+int StarDictClient::parse_wordlist(STARDICT::Cmd* cmd, gchar *buf)
|
|
+{
|
|
+ if (cmd->reading_status == 0) { // Read code.
|
|
+ int status;
|
|
+ status = atoi(buf);
|
|
+ g_free(buf);
|
|
+ if (status != CODE_OK) {
|
|
+ return 0;
|
|
+ }
|
|
+ cmd->wordlist_response = new std::list<char *>;
|
|
+ cmd->reading_status = 1;
|
|
+ reading_type_ = READ_STRING;
|
|
+ } else if (cmd->reading_status == 1) {
|
|
+ if (*buf == '\0') {
|
|
+ g_free(buf);
|
|
+ if (cmd->command == STARDICT::CMD_PREVIOUS) {
|
|
+ on_previous_end_.emit(cmd->wordlist_response);
|
|
+ return 1;
|
|
+ } else {
|
|
+ on_next_end_.emit(cmd->wordlist_response);
|
|
+ return 1;
|
|
+ }
|
|
+ } else {
|
|
+ cmd->wordlist_response->push_back(buf);
|
|
+ }
|
|
+ }
|
|
+ return 2;
|
|
+}
|
|
+
|
|
+int StarDictClient::parse_dict_result(STARDICT::Cmd* cmd, gchar *buf)
|
|
+{
|
|
+ if (cmd->reading_status == 0) { // Read code.
|
|
+ int status;
|
|
+ status = atoi(buf);
|
|
+ g_free(buf);
|
|
+ if (status != CODE_OK) {
|
|
+ if (status == CODE_DICTMASK_NOTSET) {
|
|
+ on_error_.emit(_("You haven't chosen any dictionaries, please choose some by clicking \"Manage Dict\"->\"Network dictionaries\"->\"Add\"."));
|
|
+ return 1;
|
|
+ } else {
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+ cmd->lookup_response = new STARDICT::LookupResponse();
|
|
+ cmd->lookup_response->listtype = STARDICT::LookupResponse::ListType_None;
|
|
+ cmd->reading_status = 1;
|
|
+ reading_type_ = READ_STRING;
|
|
+ } else if (cmd->reading_status == 1) { // Read original word.
|
|
+ cmd->lookup_response->dict_response.oword = buf;
|
|
+ cmd->reading_status = 2;
|
|
+ } else if (cmd->reading_status == 2) { // Read book name.
|
|
+ if (*buf == '\0') {
|
|
+ g_free(buf);
|
|
+ if (cmd->command == STARDICT::CMD_DEFINE) {
|
|
+ on_lookup_end_.emit(cmd->lookup_response, cmd->seq);
|
|
+ save_cache_lookup_response(cmd->data, cmd->lookup_response);
|
|
+ cmd->lookup_response = NULL;
|
|
+ return 1;
|
|
+ } else if ( cmd->command == STARDICT::CMD_SELECT_QUERY || cmd->command == STARDICT::CMD_SMART_QUERY) {
|
|
+ on_floatwin_lookup_end_.emit(cmd->lookup_response, cmd->seq);
|
|
+ save_cache_lookup_response(cmd->data, cmd->lookup_response);
|
|
+ cmd->lookup_response = NULL;
|
|
+ return 1;
|
|
+ }
|
|
+ cmd->reading_status = 6;
|
|
+ reading_type_ = READ_STRING;
|
|
+ } else {
|
|
+ struct STARDICT::LookupResponse::DictResponse::DictResult *dict_result = new STARDICT::LookupResponse::DictResponse::DictResult();
|
|
+ dict_result->bookname = buf;
|
|
+ cmd->lookup_response->dict_response.dict_result_list.push_back(dict_result);
|
|
+ cmd->reading_status = 3;
|
|
+ }
|
|
+ } else if (cmd->reading_status == 3) { // Read word.
|
|
+ if (*buf == '\0') {
|
|
+ g_free(buf);
|
|
+ cmd->reading_status = 2;
|
|
+ } else {
|
|
+ struct STARDICT::LookupResponse::DictResponse::DictResult::WordResult *word_result = new STARDICT::LookupResponse::DictResponse::DictResult::WordResult();
|
|
+ word_result->word = buf;
|
|
+ cmd->lookup_response->dict_response.dict_result_list.back()->word_result_list.push_back(word_result);;
|
|
+ cmd->reading_status = 4;
|
|
+ reading_type_ = READ_SIZE;
|
|
+ size_data = (char *)g_malloc(sizeof(guint32));
|
|
+ size_count = size_left = sizeof(guint32);
|
|
+ }
|
|
+ } else if (cmd->reading_status == 4) {
|
|
+ guint32 datasize = g_ntohl(get_uint32(buf));
|
|
+ memcpy(buf, &datasize, sizeof(guint32));
|
|
+ if (datasize == 0) {
|
|
+ g_free(buf);
|
|
+ cmd->reading_status = 3;
|
|
+ reading_type_ = READ_STRING;
|
|
+ } else {
|
|
+ cmd->reading_status = 5;
|
|
+ size_data = (char *)g_realloc(buf, datasize + sizeof(guint32));
|
|
+ size_count = datasize + sizeof(guint32);
|
|
+ size_left = datasize;
|
|
+ }
|
|
+ } else if (cmd->reading_status == 5) {
|
|
+ cmd->lookup_response->dict_response.dict_result_list.back()->word_result_list.back()->datalist.push_back(buf);
|
|
+ cmd->reading_status = 4;
|
|
+ size_data = (char *)g_malloc(sizeof(guint32));
|
|
+ size_count = size_left = sizeof(guint32);
|
|
+ } else if (cmd->reading_status == 6) {
|
|
+ if (strcmp(buf, "d") == 0) {
|
|
+ cmd->reading_status = 8;
|
|
+ cmd->lookup_response->listtype = STARDICT::LookupResponse::ListType_Tree;
|
|
+ cmd->lookup_response->wordtree = new std::list<STARDICT::LookupResponse::WordTreeElement *>;
|
|
+ } else {
|
|
+ cmd->reading_status = 7;
|
|
+ if (strcmp(buf, "r") == 0)
|
|
+ cmd->lookup_response->listtype = STARDICT::LookupResponse::ListType_Rule_List;
|
|
+ else if (strcmp(buf, "g") == 0)
|
|
+ cmd->lookup_response->listtype = STARDICT::LookupResponse::ListType_Regex_List;
|
|
+ else if (strcmp(buf, "f") == 0)
|
|
+ cmd->lookup_response->listtype = STARDICT::LookupResponse::ListType_Fuzzy_List;
|
|
+ else
|
|
+ cmd->lookup_response->listtype = STARDICT::LookupResponse::ListType_List;
|
|
+ cmd->lookup_response->wordlist = new std::list<char *>;
|
|
+ }
|
|
+ g_free(buf);
|
|
+ } else if (cmd->reading_status == 7) {
|
|
+ if (*buf == '\0') {
|
|
+ g_free(buf);
|
|
+ on_lookup_end_.emit(cmd->lookup_response, cmd->seq);
|
|
+ save_cache_lookup_response(cmd->data, cmd->lookup_response);
|
|
+ cmd->lookup_response = NULL;
|
|
+ return 1;
|
|
+ } else {
|
|
+ cmd->lookup_response->wordlist->push_back(buf);
|
|
+ }
|
|
+ } else if (cmd->reading_status == 8) {
|
|
+ if (*buf == '\0') {
|
|
+ g_free(buf);
|
|
+ on_lookup_end_.emit(cmd->lookup_response, cmd->seq);
|
|
+ save_cache_lookup_response(cmd->data, cmd->lookup_response);
|
|
+ cmd->lookup_response = NULL;
|
|
+ return 1;
|
|
+ } else {
|
|
+ STARDICT::LookupResponse::WordTreeElement *element = new STARDICT::LookupResponse::WordTreeElement();
|
|
+ element->bookname = buf;
|
|
+ cmd->lookup_response->wordtree->push_back(element);
|
|
+ cmd->reading_status = 9;
|
|
+ }
|
|
+ } else if (cmd->reading_status == 9) {
|
|
+ if (*buf == '\0') {
|
|
+ g_free(buf);
|
|
+ cmd->reading_status = 8;
|
|
+ } else {
|
|
+ cmd->lookup_response->wordtree->back()->wordlist.push_back(buf);
|
|
+ }
|
|
+ }
|
|
+ return 2;
|
|
+}
|
|
+
|
|
+bool StarDictClient::parse(gchar *line)
|
|
+{
|
|
+ int result;
|
|
+ if (waiting_banner_) {
|
|
+ waiting_banner_ = false;
|
|
+ result = parse_banner(line);
|
|
+ g_free(line);
|
|
+ if (!result)
|
|
+ return false;
|
|
+ request_command();
|
|
+ return true;
|
|
+ }
|
|
+ STARDICT::Cmd* cmd = cmdlist.front();
|
|
+ switch (cmd->command) {
|
|
+ case STARDICT::CMD_CLIENT:
|
|
+ result = parse_command_client(line);
|
|
+ g_free(line);
|
|
+ break;
|
|
+ case STARDICT::CMD_AUTH:
|
|
+ result = parse_command_auth(line);
|
|
+ g_free(line);
|
|
+ break;
|
|
+ case STARDICT::CMD_REGISTER:
|
|
+ result = parse_command_register(line);
|
|
+ g_free(line);
|
|
+ break;
|
|
+ case STARDICT::CMD_GET_DICT_MASK:
|
|
+ result = parse_command_getdictmask(cmd, line);
|
|
+ break;
|
|
+ case STARDICT::CMD_SET_DICT_MASK:
|
|
+ result = parse_command_setdictmask(line);
|
|
+ break;
|
|
+ case STARDICT::CMD_DIR_INFO:
|
|
+ result = parse_command_dirinfo(cmd, line);
|
|
+ break;
|
|
+ case STARDICT::CMD_DICT_INFO:
|
|
+ result = parse_command_dictinfo(cmd, line);
|
|
+ break;
|
|
+ case STARDICT::CMD_MAX_DICT_COUNT:
|
|
+ result = parse_command_maxdictcount(cmd, line);
|
|
+ break;
|
|
+ case STARDICT::CMD_DEFINE:
|
|
+ case STARDICT::CMD_LOOKUP:
|
|
+ case STARDICT::CMD_SELECT_QUERY:
|
|
+ case STARDICT::CMD_SMART_QUERY:
|
|
+ result = parse_dict_result(cmd, line);
|
|
+ break;
|
|
+ case STARDICT::CMD_PREVIOUS:
|
|
+ case STARDICT::CMD_NEXT:
|
|
+ result = parse_wordlist(cmd, line);
|
|
+ break;
|
|
+ case STARDICT::CMD_QUIT:
|
|
+ result = parse_command_quit(line);
|
|
+ g_free(line);
|
|
+ break;
|
|
+ default:
|
|
+ result = 0;
|
|
+ g_free(line);
|
|
+ break;
|
|
+ }
|
|
+ if (result == 0)
|
|
+ return false;
|
|
+ if (result == 1) {
|
|
+ delete cmd;
|
|
+ cmdlist.pop_front();
|
|
+ if (cmdlist.empty()) {
|
|
+ cmdlist.push_back(new STARDICT::Cmd(STARDICT::CMD_QUIT));
|
|
+ }
|
|
+ request_command();
|
|
+ }
|
|
+ return true;
|
|
+}
|
|
diff -Nur stardict-3.0.1.orig//src/lib/stddict.cpp stardict-3.0.1/src/lib/stddict.cpp
|
|
--- stardict-3.0.1.orig//src/lib/stddict.cpp 2007-10-30 04:06:07.000000000 -0500
|
|
+++ stardict-3.0.1/src/lib/stddict.cpp 2010-05-24 00:53:36.377667178 -0500
|
|
@@ -39,6 +39,7 @@
|
|
#include "stddict.hpp"
|
|
#include <algorithm>
|
|
#include "getuint32.h"
|
|
+#include <cstring>
|
|
|
|
static inline gint stardict_strcmp(const gchar *s1, const gchar *s2)
|
|
{
|
|
diff -Nur stardict-3.0.1.orig//src/lib/stddict.cpp~ stardict-3.0.1/src/lib/stddict.cpp~
|
|
--- stardict-3.0.1.orig//src/lib/stddict.cpp~ 1969-12-31 18:00:00.000000000 -0600
|
|
+++ stardict-3.0.1/src/lib/stddict.cpp~ 2007-10-30 04:06:07.000000000 -0500
|
|
@@ -0,0 +1,3263 @@
|
|
+/*
|
|
+ * This file part of StarDict - A international dictionary for GNOME.
|
|
+ * http://stardict.sourceforge.net
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 3 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU Library General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * Implementation of class to work with standard StarDict's dictionaries
|
|
+ * lookup word, get articles and so on.
|
|
+ *
|
|
+ * Notice: read doc/DICTFILE_FORMAT for the dictionary
|
|
+ * file's format information!
|
|
+ */
|
|
+#ifdef HAVE_CONFIG_H
|
|
+# include "config.h"
|
|
+#endif
|
|
+
|
|
+#include <glib/gi18n.h>
|
|
+#include <glib/gstdio.h>
|
|
+
|
|
+#include "common.hpp"
|
|
+#include "distance.h"
|
|
+#include "kmp.h"
|
|
+#include "mapfile.hpp"
|
|
+
|
|
+#include "stddict.hpp"
|
|
+#include <algorithm>
|
|
+#include "getuint32.h"
|
|
+
|
|
+static inline gint stardict_strcmp(const gchar *s1, const gchar *s2)
|
|
+{
|
|
+ gint a=g_ascii_strcasecmp(s1, s2);
|
|
+ if (a == 0)
|
|
+ return strcmp(s1, s2);
|
|
+ else
|
|
+ return a;
|
|
+}
|
|
+
|
|
+static gint stardict_collate(const gchar *str1, const gchar *str2, CollateFunctions func)
|
|
+{
|
|
+ gint x = utf8_collate(str1, str2, func);
|
|
+ if (x == 0)
|
|
+ return strcmp(str1, str2);
|
|
+ else
|
|
+ return x;
|
|
+}
|
|
+
|
|
+gint stardict_server_collate(const gchar *str1, const gchar *str2, int EnableCollationLevel, CollateFunctions func, int servercollatefunc)
|
|
+{
|
|
+ if (EnableCollationLevel == 0)
|
|
+ return stardict_strcmp(str1, str2);
|
|
+ if (EnableCollationLevel == 1)
|
|
+ return stardict_collate(str1, str2, func);
|
|
+ if (servercollatefunc == 0)
|
|
+ return stardict_strcmp(str1, str2);
|
|
+ return stardict_collate(str1, str2, (CollateFunctions)(servercollatefunc-1));
|
|
+}
|
|
+
|
|
+gint stardict_casecmp(const gchar *s1, const gchar *s2, int EnableCollationLevel, CollateFunctions func, int servercollatefunc)
|
|
+{
|
|
+ if (EnableCollationLevel == 0)
|
|
+ return g_ascii_strcasecmp(s1, s2);
|
|
+ if (EnableCollationLevel == 1)
|
|
+ return utf8_collate(s1, s2, func);
|
|
+ if (servercollatefunc == 0)
|
|
+ return g_ascii_strcasecmp(s1, s2);
|
|
+ return utf8_collate(s1, s2, (CollateFunctions)(servercollatefunc-1));
|
|
+}
|
|
+
|
|
+static inline gint prefix_match (const gchar *s1, const gchar *s2)
|
|
+{
|
|
+ gint ret=-1;
|
|
+ gunichar u1, u2;
|
|
+ do {
|
|
+ u1 = g_utf8_get_char(s1);
|
|
+ u2 = g_utf8_get_char(s2);
|
|
+ s1 = g_utf8_next_char(s1);
|
|
+ s2 = g_utf8_next_char(s2);
|
|
+ ret++;
|
|
+ } while (u1 && g_unichar_tolower(u1) == g_unichar_tolower(u2));
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static inline bool bIsVowel(gchar inputchar)
|
|
+{
|
|
+ gchar ch = g_ascii_toupper(inputchar);
|
|
+ return( ch=='A' || ch=='E' || ch=='I' || ch=='O' || ch=='U' );
|
|
+}
|
|
+
|
|
+
|
|
+bool bIsPureEnglish(const gchar *str)
|
|
+{
|
|
+ // i think this should work even when it is UTF8 string :).
|
|
+ for (int i=0; str[i]!=0; i++)
|
|
+ //if(str[i]<0)
|
|
+ //if(str[i]<32 || str[i]>126) // tab equal 9,so this is not OK.
|
|
+ // Better use isascii() but not str[i]<0 while char is default unsigned in arm
|
|
+ if (!isascii(str[i]))
|
|
+ return false;
|
|
+ return true;
|
|
+}
|
|
+
|
|
+class offset_index : public index_file {
|
|
+public:
|
|
+ offset_index();
|
|
+ ~offset_index();
|
|
+ bool load(const std::string& url, gulong wc, gulong fsize,
|
|
+ bool CreateCacheFile, int EnableCollationLevel,
|
|
+ CollateFunctions _CollateFunction, show_progress_t *sp);
|
|
+ void get_data(glong idx);
|
|
+ const gchar *get_key_and_data(glong idx);
|
|
+private:
|
|
+ const gchar *get_key(glong idx);
|
|
+ bool lookup(const char *str, glong &idx, glong &idx_suggest);
|
|
+
|
|
+ static const gint ENTR_PER_PAGE=32;
|
|
+
|
|
+ cache_file oft_file;
|
|
+ FILE *idxfile;
|
|
+ gulong npages;
|
|
+
|
|
+ gchar wordentry_buf[256+sizeof(guint32)*2]; // The length of "word_str" should be less than 256. See doc/DICTFILE_FORMAT.
|
|
+ struct index_entry {
|
|
+ glong idx;
|
|
+ std::string keystr;
|
|
+ void assign(glong i, const std::string& str) {
|
|
+ idx=i;
|
|
+ keystr.assign(str);
|
|
+ }
|
|
+ };
|
|
+ index_entry first, last, middle, real_last;
|
|
+
|
|
+ struct page_entry {
|
|
+ gchar *keystr;
|
|
+ guint32 off, size;
|
|
+ };
|
|
+ std::vector<gchar> page_data;
|
|
+ struct page_t {
|
|
+ glong idx;
|
|
+ page_entry entries[ENTR_PER_PAGE];
|
|
+
|
|
+ page_t(): idx(-1) {}
|
|
+ void fill(gchar *data, gint nent, glong idx_);
|
|
+ } page;
|
|
+ gulong load_page(glong page_idx);
|
|
+ const gchar *read_first_on_page_key(glong page_idx);
|
|
+ const gchar *get_first_on_page_key(glong page_idx);
|
|
+};
|
|
+
|
|
+class wordlist_index : public index_file {
|
|
+public:
|
|
+ wordlist_index();
|
|
+ ~wordlist_index();
|
|
+ bool load(const std::string& url, gulong wc, gulong fsize,
|
|
+ bool CreateCacheFile, int EnableCollationLevel,
|
|
+ CollateFunctions _CollateFunction, show_progress_t *sp);
|
|
+ void get_data(glong idx);
|
|
+ const gchar *get_key_and_data(glong idx);
|
|
+private:
|
|
+ const gchar *get_key(glong idx);
|
|
+ bool lookup(const char *str, glong &idx, glong &idx_suggest);
|
|
+
|
|
+ gchar *idxdatabuf;
|
|
+ std::vector<gchar *> wordlist;
|
|
+};
|
|
+
|
|
+offset_index::offset_index() : oft_file(CacheFileType_oft)
|
|
+{
|
|
+ clt_file = NULL;
|
|
+ idxfile = NULL;
|
|
+}
|
|
+
|
|
+offset_index::~offset_index()
|
|
+{
|
|
+ delete clt_file;
|
|
+ if (idxfile)
|
|
+ fclose(idxfile);
|
|
+}
|
|
+
|
|
+void offset_index::page_t::fill(gchar *data, gint nent, glong idx_)
|
|
+{
|
|
+ idx=idx_;
|
|
+ gchar *p=data;
|
|
+ glong len;
|
|
+ for (gint i=0; i<nent; ++i) {
|
|
+ entries[i].keystr=p;
|
|
+ len=strlen(p);
|
|
+ p+=len+1;
|
|
+ entries[i].off=g_ntohl(get_uint32(p));
|
|
+ p+=sizeof(guint32);
|
|
+ entries[i].size=g_ntohl(get_uint32(p));
|
|
+ p+=sizeof(guint32);
|
|
+ }
|
|
+}
|
|
+
|
|
+inline const gchar *offset_index::read_first_on_page_key(glong page_idx)
|
|
+{
|
|
+ fseek(idxfile, oft_file.wordoffset[page_idx], SEEK_SET);
|
|
+ guint32 page_size=oft_file.wordoffset[page_idx+1]-oft_file.wordoffset[page_idx];
|
|
+ gulong minsize = sizeof(wordentry_buf);
|
|
+ if (page_size < minsize)
|
|
+ minsize = page_size;
|
|
+ fread(wordentry_buf, minsize, 1, idxfile); //TODO: check returned values, deal with word entry that strlen>255.
|
|
+ return wordentry_buf;
|
|
+}
|
|
+
|
|
+inline const gchar *offset_index::get_first_on_page_key(glong page_idx)
|
|
+{
|
|
+ if (page_idx<middle.idx) {
|
|
+ if (page_idx==first.idx)
|
|
+ return first.keystr.c_str();
|
|
+ return read_first_on_page_key(page_idx);
|
|
+ } else if (page_idx>middle.idx) {
|
|
+ if (page_idx==last.idx)
|
|
+ return last.keystr.c_str();
|
|
+ return read_first_on_page_key(page_idx);
|
|
+ } else
|
|
+ return middle.keystr.c_str();
|
|
+}
|
|
+
|
|
+cache_file::cache_file(CacheFileType _cachefiletype)
|
|
+{
|
|
+ wordoffset = NULL;
|
|
+ mf = NULL;
|
|
+ cachefiletype = _cachefiletype;
|
|
+}
|
|
+
|
|
+
|
|
+cache_file::~cache_file()
|
|
+{
|
|
+ if (mf)
|
|
+ delete mf;
|
|
+ else
|
|
+ g_free(wordoffset);
|
|
+}
|
|
+
|
|
+#define OFFSETFILE_MAGIC_DATA "StarDict's oft file\nversion=2.4.8\n"
|
|
+#define COLLATIONFILE_MAGIC_DATA "StarDict's clt file\nversion=2.4.8\n"
|
|
+
|
|
+MapFile* cache_file::get_cache_loadfile(const gchar *filename, const std::string &url, const std::string &saveurl, CollateFunctions cltfunc, glong filedatasize, int next)
|
|
+{
|
|
+ struct stat cachestat;
|
|
+ if (g_stat(filename, &cachestat)!=0)
|
|
+ return NULL;
|
|
+ MapFile *mf = new MapFile;
|
|
+ if (!mf->open(filename, cachestat.st_size)) {
|
|
+ delete mf;
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ gchar *p = mf->begin();
|
|
+ gboolean has_prefix;
|
|
+ if (cachefiletype == CacheFileType_oft)
|
|
+ has_prefix = g_str_has_prefix(p, OFFSETFILE_MAGIC_DATA);
|
|
+ else
|
|
+ has_prefix = g_str_has_prefix(p, COLLATIONFILE_MAGIC_DATA);
|
|
+ if (!has_prefix) {
|
|
+ delete mf;
|
|
+ return NULL;
|
|
+ }
|
|
+ if (cachefiletype == CacheFileType_oft)
|
|
+ p+= sizeof(OFFSETFILE_MAGIC_DATA)-1-1;
|
|
+ else
|
|
+ p+= sizeof(COLLATIONFILE_MAGIC_DATA)-1-1;
|
|
+ gchar *p2;
|
|
+ p2 = strstr(p, "\nurl=");
|
|
+ if (!p2) {
|
|
+ delete mf;
|
|
+ return NULL;
|
|
+ }
|
|
+ p2+=sizeof("\nurl=")-1;
|
|
+ gchar *p3;
|
|
+ p3 = strchr(p2, '\n');
|
|
+ if (!p3) {
|
|
+ delete mf;
|
|
+ return NULL;
|
|
+ }
|
|
+ gchar *tmpstr;
|
|
+ tmpstr = (gchar *)g_memdup(p2, p3-p2+1);
|
|
+ tmpstr[p3-p2] = '\0';
|
|
+ if (saveurl == tmpstr) {
|
|
+ g_free(tmpstr);
|
|
+ if (cachefiletype == CacheFileType_clt) {
|
|
+ p2 = strstr(p, "\nfunc=");
|
|
+ if (!p2) {
|
|
+ delete mf;
|
|
+ return NULL;
|
|
+ }
|
|
+ p2+=sizeof("\nfunc=")-1;
|
|
+ p3 = strchr(p2, '\n');
|
|
+ if (!p3) {
|
|
+ delete mf;
|
|
+ return NULL;
|
|
+ }
|
|
+ tmpstr = (gchar *)g_memdup(p2, p3-p2+1);
|
|
+ tmpstr[p3-p2] = '\0';
|
|
+ if (atoi(tmpstr)!=cltfunc) {
|
|
+ g_free(tmpstr);
|
|
+ delete mf;
|
|
+ return NULL;
|
|
+ }
|
|
+ g_free(tmpstr);
|
|
+ }
|
|
+ if (cachestat.st_size!=glong(filedatasize + strlen(mf->begin()) +1)) {
|
|
+ delete mf;
|
|
+ return NULL;
|
|
+ }
|
|
+ struct stat idxstat;
|
|
+ if (g_stat(url.c_str(), &idxstat)!=0) {
|
|
+ delete mf;
|
|
+ return NULL;
|
|
+ }
|
|
+ if (cachestat.st_mtime<idxstat.st_mtime) {
|
|
+ delete mf;
|
|
+ return NULL;
|
|
+ }
|
|
+ //g_print("Using map file: %s\n", filename);
|
|
+ return mf;
|
|
+ }
|
|
+ g_free(tmpstr);
|
|
+ delete mf;
|
|
+ gchar *basename = g_path_get_basename(saveurl.c_str());
|
|
+ p = strrchr(basename, '.');
|
|
+ if (!p) {
|
|
+ g_free(basename);
|
|
+ return NULL;
|
|
+ }
|
|
+ *p='\0';
|
|
+ gchar *extendname = p+1;
|
|
+ gchar *dirname = g_path_get_dirname(filename);
|
|
+ gchar *nextfilename;
|
|
+ if (cachefiletype == CacheFileType_oft)
|
|
+ nextfilename = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s(%d).%s.oft", dirname, basename, next, extendname);
|
|
+ else if (cachefiletype == CacheFileType_clt)
|
|
+ nextfilename = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s(%d).%s.clt", dirname, basename, next, extendname);
|
|
+ else
|
|
+ nextfilename = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s(%d).%s.%d.clt", dirname, basename, next, extendname, cltfunc);
|
|
+ MapFile *out = get_cache_loadfile(nextfilename, url, saveurl, cltfunc, filedatasize, next+1);
|
|
+ g_free(basename);
|
|
+ g_free(dirname);
|
|
+ g_free(nextfilename);
|
|
+ return out;
|
|
+}
|
|
+
|
|
+bool cache_file::load_cache(const std::string& url, const std::string& saveurl, CollateFunctions cltfunc, glong filedatasize)
|
|
+{
|
|
+ std::string oftfilename;
|
|
+ if (cachefiletype == CacheFileType_oft)
|
|
+ oftfilename=saveurl+".oft";
|
|
+ else if (cachefiletype == CacheFileType_clt)
|
|
+ oftfilename=saveurl+".clt";
|
|
+ else {
|
|
+ gchar *func = g_strdup_printf("%d", cltfunc);
|
|
+ oftfilename=saveurl+'.'+func+".clt";
|
|
+ g_free(func);
|
|
+ }
|
|
+ for (int i=0;i<2;i++) {
|
|
+ if (i==1) {
|
|
+ if (!get_cache_filename(saveurl, oftfilename, false, cltfunc))
|
|
+ break;
|
|
+ }
|
|
+ mf = get_cache_loadfile(oftfilename.c_str(), url, saveurl, cltfunc, filedatasize, 2);
|
|
+ if (!mf)
|
|
+ continue;
|
|
+ wordoffset = (guint32 *)(mf->begin()+strlen(mf->begin())+1);
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
+bool cache_file::get_cache_filename(const std::string& url, std::string &cachefilename, bool create, CollateFunctions cltfunc)
|
|
+{
|
|
+ if (create) {
|
|
+ if (!g_file_test(g_get_user_cache_dir(), G_FILE_TEST_EXISTS) &&
|
|
+ g_mkdir(g_get_user_cache_dir(), 0700)==-1)
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ std::string cache_dir=g_get_user_cache_dir();
|
|
+ cache_dir += G_DIR_SEPARATOR_S "stardict";
|
|
+
|
|
+ if (create) {
|
|
+ if (!g_file_test(cache_dir.c_str(), G_FILE_TEST_EXISTS)) {
|
|
+ if (g_mkdir(cache_dir.c_str(), 0700)==-1)
|
|
+ return false;
|
|
+ } else if (!g_file_test(cache_dir.c_str(), G_FILE_TEST_IS_DIR))
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ gchar *base=g_path_get_basename(url.c_str());
|
|
+ if (cachefiletype == CacheFileType_oft) {
|
|
+ cachefilename = cache_dir+G_DIR_SEPARATOR_S+base+".oft";
|
|
+ } else if (cachefiletype == CacheFileType_clt) {
|
|
+ cachefilename = cache_dir+G_DIR_SEPARATOR_S+base+".clt";
|
|
+ } else {
|
|
+ gchar *func = g_strdup_printf("%d", cltfunc);
|
|
+ cachefilename = cache_dir+G_DIR_SEPARATOR_S+base+'.'+func+".clt";
|
|
+ g_free(func);
|
|
+ }
|
|
+ g_free(base);
|
|
+ return true;
|
|
+}
|
|
+
|
|
+FILE* cache_file::get_cache_savefile(const gchar *filename, const std::string &url, int next, std::string &cfilename, CollateFunctions cltfunc)
|
|
+{
|
|
+ cfilename = filename;
|
|
+ struct stat oftstat;
|
|
+ if (g_stat(filename, &oftstat)!=0) {
|
|
+ return fopen(filename, "wb");
|
|
+ }
|
|
+ MapFile mf;
|
|
+ if (!mf.open(filename, oftstat.st_size)) {
|
|
+ return fopen(filename, "wb");
|
|
+ }
|
|
+ gchar *p = mf.begin();
|
|
+ bool has_prefix;
|
|
+ if (cachefiletype == CacheFileType_oft)
|
|
+ has_prefix = g_str_has_prefix(p, OFFSETFILE_MAGIC_DATA);
|
|
+ else
|
|
+ has_prefix = g_str_has_prefix(p, COLLATIONFILE_MAGIC_DATA);
|
|
+ if (!has_prefix) {
|
|
+ mf.close();
|
|
+ return fopen(filename, "wb");
|
|
+ }
|
|
+ if (cachefiletype == CacheFileType_oft)
|
|
+ p+= sizeof(OFFSETFILE_MAGIC_DATA)-1-1;
|
|
+ else
|
|
+ p+= sizeof(COLLATIONFILE_MAGIC_DATA)-1-1;
|
|
+ gchar *p2;
|
|
+ p2 = strstr(p, "\nurl=");
|
|
+ if (!p2) {
|
|
+ mf.close();
|
|
+ return fopen(filename, "wb");
|
|
+ }
|
|
+ p2+=sizeof("\nurl=")-1;
|
|
+ gchar *p3;
|
|
+ p3 = strchr(p2, '\n');
|
|
+ if (!p3) {
|
|
+ mf.close();
|
|
+ return fopen(filename, "wb");
|
|
+ }
|
|
+ gchar *tmpstr;
|
|
+ tmpstr = (gchar *)g_memdup(p2, p3-p2+1);
|
|
+ tmpstr[p3-p2] = '\0';
|
|
+ if (url == tmpstr) {
|
|
+ g_free(tmpstr);
|
|
+ mf.close();
|
|
+ return fopen(filename, "wb");
|
|
+ }
|
|
+ g_free(tmpstr);
|
|
+ mf.close();
|
|
+ gchar *basename = g_path_get_basename(url.c_str());
|
|
+ p = strrchr(basename, '.');
|
|
+ if (!p) {
|
|
+ g_free(basename);
|
|
+ return NULL;
|
|
+ }
|
|
+ *p='\0';
|
|
+ gchar *extendname = p+1;
|
|
+ gchar *dirname = g_path_get_dirname(filename);
|
|
+ gchar *nextfilename;
|
|
+ if (cachefiletype == CacheFileType_oft)
|
|
+ nextfilename = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s(%d).%s.oft", dirname, basename, next, extendname);
|
|
+ else if (cachefiletype == CacheFileType_clt)
|
|
+ nextfilename = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s(%d).%s.clt", dirname, basename, next, extendname);
|
|
+ else
|
|
+ nextfilename = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s(%d).%s.%d.clt", dirname, basename, next, extendname, cltfunc);
|
|
+ FILE *out = get_cache_savefile(nextfilename, url, next+1, cfilename, cltfunc);
|
|
+ g_free(basename);
|
|
+ g_free(dirname);
|
|
+ g_free(nextfilename);
|
|
+ return out;
|
|
+}
|
|
+
|
|
+bool cache_file::save_cache(const std::string& url, CollateFunctions cltfunc, gulong npages)
|
|
+{
|
|
+ std::string oftfilename;
|
|
+ if (cachefiletype == CacheFileType_oft) {
|
|
+ oftfilename=url+".oft";
|
|
+ } else if (cachefiletype == CacheFileType_clt) {
|
|
+ oftfilename=url+".clt";
|
|
+ } else {
|
|
+ gchar *func = g_strdup_printf("%d", cltfunc);
|
|
+ oftfilename=url+'.'+func+".clt";
|
|
+ g_free(func);
|
|
+ }
|
|
+ for (int i=0;i<2;i++) {
|
|
+ if (i==1) {
|
|
+ if (!get_cache_filename(url, oftfilename, true, cltfunc))
|
|
+ break;
|
|
+ }
|
|
+ std::string cfilename;
|
|
+ FILE *out= get_cache_savefile(oftfilename.c_str(), url, 2, cfilename, cltfunc);
|
|
+ if (!out)
|
|
+ continue;
|
|
+ if (cachefiletype == CacheFileType_oft)
|
|
+ fwrite(OFFSETFILE_MAGIC_DATA, 1, sizeof(OFFSETFILE_MAGIC_DATA)-1, out);
|
|
+ else
|
|
+ fwrite(COLLATIONFILE_MAGIC_DATA, 1, sizeof(COLLATIONFILE_MAGIC_DATA)-1, out);
|
|
+ fwrite("url=", 1, sizeof("url=")-1, out);
|
|
+ fwrite(url.c_str(), 1, url.length(), out);
|
|
+ if (cachefiletype == CacheFileType_clt) {
|
|
+#ifdef _MSC_VER
|
|
+ fprintf_s(out, "\nfunc=%d", cltfunc);
|
|
+#else
|
|
+ fprintf(out, "\nfunc=%d", cltfunc);
|
|
+#endif
|
|
+ }
|
|
+ fwrite("\n", 1, 2, out);
|
|
+ fwrite(wordoffset, sizeof(guint32), npages, out);
|
|
+ fclose(out);
|
|
+ g_print("Save cache file: %s\n", cfilename.c_str());
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
+collation_file::collation_file(idxsyn_file *_idx_file, CacheFileType _cachefiletype) : cache_file(_cachefiletype)
|
|
+{
|
|
+ idx_file = _idx_file;
|
|
+}
|
|
+
|
|
+const gchar *collation_file::GetWord(glong idx)
|
|
+{
|
|
+ return idx_file->get_key(wordoffset[idx]);
|
|
+}
|
|
+
|
|
+glong collation_file::GetOrigIndex(glong cltidx)
|
|
+{
|
|
+ return wordoffset[cltidx];
|
|
+}
|
|
+
|
|
+bool collation_file::lookup(const char *sWord, glong &idx, glong &idx_suggest)
|
|
+{
|
|
+ bool bFound=false;
|
|
+ glong iTo=idx_file->wordcount-1;
|
|
+ if (stardict_collate(sWord, GetWord(0), CollateFunction)<0) {
|
|
+ idx = 0;
|
|
+ idx_suggest = 0;
|
|
+ } else if (stardict_collate(sWord, GetWord(iTo), CollateFunction) >0) {
|
|
+ idx = INVALID_INDEX;
|
|
+ idx_suggest = iTo;
|
|
+ } else {
|
|
+ glong iThisIndex=0;
|
|
+ glong iFrom=0;
|
|
+ gint cmpint;
|
|
+ while (iFrom<=iTo) {
|
|
+ iThisIndex=(iFrom+iTo)/2;
|
|
+ cmpint = stardict_collate(sWord, GetWord(iThisIndex), CollateFunction);
|
|
+ if (cmpint>0)
|
|
+ iFrom=iThisIndex+1;
|
|
+ else if (cmpint<0)
|
|
+ iTo=iThisIndex-1;
|
|
+ else {
|
|
+ bFound=true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if (!bFound) {
|
|
+ idx = iFrom; //next
|
|
+ idx_suggest = iFrom;
|
|
+ gint best, back;
|
|
+ best = prefix_match (sWord, GetWord(idx_suggest));
|
|
+ for (;;) {
|
|
+ if ((iTo=idx_suggest-1) < 0)
|
|
+ break;
|
|
+ back = prefix_match (sWord, GetWord(iTo));
|
|
+ if (!back || back < best)
|
|
+ break;
|
|
+ best = back;
|
|
+ idx_suggest = iTo;
|
|
+ }
|
|
+ } else {
|
|
+ idx = iThisIndex;
|
|
+ idx_suggest = iThisIndex;
|
|
+ }
|
|
+ }
|
|
+ return bFound;
|
|
+}
|
|
+
|
|
+struct sort_collation_index_user_data {
|
|
+ idxsyn_file *idx_file;
|
|
+ CollateFunctions cltfunc;
|
|
+};
|
|
+
|
|
+static gint sort_collation_index(gconstpointer a, gconstpointer b, gpointer user_data)
|
|
+{
|
|
+ sort_collation_index_user_data *data = (sort_collation_index_user_data*)user_data;
|
|
+ gchar *str1 = g_strdup(data->idx_file->get_key(*((guint32 *)a)));
|
|
+ const gchar *str2 = data->idx_file->get_key(*((guint32 *)b));
|
|
+ gint x = stardict_collate(str1, str2, data->cltfunc);
|
|
+ g_free(str1);
|
|
+ if (x==0)
|
|
+ return *((guint32 *)a) - *((guint32 *)b);
|
|
+ else
|
|
+ return x;
|
|
+}
|
|
+
|
|
+idxsyn_file::idxsyn_file()
|
|
+{
|
|
+ memset(clt_files, 0, sizeof(clt_files));
|
|
+}
|
|
+
|
|
+const gchar *idxsyn_file::getWord(glong idx, int EnableCollationLevel, int servercollatefunc)
|
|
+{
|
|
+ if (EnableCollationLevel == 0)
|
|
+ return get_key(idx);
|
|
+ if (EnableCollationLevel == 1)
|
|
+ return clt_file->GetWord(idx);
|
|
+ if (servercollatefunc == 0)
|
|
+ return get_key(idx);
|
|
+ collate_load((CollateFunctions)(servercollatefunc-1));
|
|
+ return clt_files[servercollatefunc-1]->GetWord(idx);
|
|
+}
|
|
+
|
|
+bool idxsyn_file::Lookup(const char *str, glong &idx, glong &idx_suggest, int EnableCollationLevel, int servercollatefunc)
|
|
+{
|
|
+ if (EnableCollationLevel == 0)
|
|
+ return lookup(str, idx, idx_suggest);
|
|
+ if (EnableCollationLevel == 1)
|
|
+ return clt_file->lookup(str, idx, idx_suggest);
|
|
+ if (servercollatefunc == 0)
|
|
+ return lookup(str, idx, idx_suggest);
|
|
+ collate_load((CollateFunctions)(servercollatefunc-1));
|
|
+ return clt_files[servercollatefunc-1]->lookup(str, idx, idx_suggest);
|
|
+}
|
|
+
|
|
+void idxsyn_file::collate_sort(const std::string& url,
|
|
+ const std::string& saveurl,
|
|
+ CollateFunctions collf,
|
|
+ show_progress_t *sp)
|
|
+{
|
|
+ clt_file = new collation_file(this, CacheFileType_clt);
|
|
+ clt_file->CollateFunction = collf;
|
|
+ if (!clt_file->load_cache(url, saveurl, collf, wordcount*sizeof(guint32))) {
|
|
+ sp->notify_about_start(_("Sorting, please wait..."));
|
|
+ clt_file->wordoffset = (guint32 *)g_malloc(wordcount*sizeof(guint32));
|
|
+ for (glong i=0; i<wordcount; i++)
|
|
+ clt_file->wordoffset[i] = i;
|
|
+ sort_collation_index_user_data data;
|
|
+ data.idx_file = this;
|
|
+ data.cltfunc = collf;
|
|
+ g_qsort_with_data(clt_file->wordoffset, wordcount, sizeof(guint32), sort_collation_index, &data);
|
|
+ if (!clt_file->save_cache(saveurl, collf, wordcount))
|
|
+ g_printerr("Cache update failed.\n");
|
|
+ }
|
|
+}
|
|
+
|
|
+void idxsyn_file::collate_save_info(const std::string& _url, const std::string& _saveurl)
|
|
+{
|
|
+ url = _url;
|
|
+ saveurl = _saveurl;
|
|
+}
|
|
+
|
|
+void idxsyn_file::collate_load(CollateFunctions collf)
|
|
+{
|
|
+ if (clt_files[collf])
|
|
+ return;
|
|
+ clt_files[collf] = new collation_file(this, CacheFileType_server_clt);
|
|
+ clt_files[collf]->CollateFunction = collf;
|
|
+ if (!clt_files[collf]->load_cache(url, saveurl, collf, wordcount*sizeof(guint32))) {
|
|
+ clt_files[collf]->wordoffset = (guint32 *)g_malloc(wordcount*sizeof(guint32));
|
|
+ for (glong i=0; i<wordcount; i++)
|
|
+ clt_files[collf]->wordoffset[i] = i;
|
|
+ sort_collation_index_user_data data;
|
|
+ data.idx_file = this;
|
|
+ data.cltfunc = collf;
|
|
+ g_qsort_with_data(clt_files[collf]->wordoffset, wordcount, sizeof(guint32), sort_collation_index, &data);
|
|
+ if (!clt_files[collf]->save_cache(saveurl, collf, wordcount))
|
|
+ g_printerr("Cache update failed.\n");
|
|
+ }
|
|
+}
|
|
+
|
|
+bool offset_index::load(const std::string& url, gulong wc, gulong fsize,
|
|
+ bool CreateCacheFile, int EnableCollationLevel,
|
|
+ CollateFunctions _CollateFunction, show_progress_t *sp)
|
|
+{
|
|
+ wordcount=wc;
|
|
+ npages=(wc-1)/ENTR_PER_PAGE+2;
|
|
+ if (!oft_file.load_cache(url, url, _CollateFunction, npages*sizeof(guint32))) {
|
|
+ MapFile map_file;
|
|
+ if (!map_file.open(url.c_str(), fsize))
|
|
+ return false;
|
|
+ const gchar *idxdatabuffer=map_file.begin();
|
|
+ oft_file.wordoffset = (guint32 *)g_malloc(npages*sizeof(guint32));
|
|
+ const gchar *p1 = idxdatabuffer;
|
|
+ gulong index_size;
|
|
+ guint32 j=0;
|
|
+ for (guint32 i=0; i<wc; i++) {
|
|
+ index_size=strlen(p1) +1 + 2*sizeof(guint32);
|
|
+ if (i % ENTR_PER_PAGE==0) {
|
|
+ oft_file.wordoffset[j]=p1-idxdatabuffer;
|
|
+ ++j;
|
|
+ }
|
|
+ p1 += index_size;
|
|
+ }
|
|
+ oft_file.wordoffset[j]=p1-idxdatabuffer;
|
|
+ map_file.close();
|
|
+ if (CreateCacheFile) {
|
|
+ if (!oft_file.save_cache(url, _CollateFunction, npages))
|
|
+ g_printerr("Cache update failed.\n");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!(idxfile = fopen(url.c_str(), "rb"))) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ first.assign(0, read_first_on_page_key(0));
|
|
+ last.assign(npages-2, read_first_on_page_key(npages-2));
|
|
+ middle.assign((npages-2)/2, read_first_on_page_key((npages-2)/2));
|
|
+ real_last.assign(wc-1, get_key(wc-1));
|
|
+
|
|
+ if (EnableCollationLevel == 0) {
|
|
+ } else if (EnableCollationLevel == 1) {
|
|
+ collate_sort(url, url, _CollateFunction, sp);
|
|
+ } else if (EnableCollationLevel == 2) {
|
|
+ collate_save_info(url, url);
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+inline gulong offset_index::load_page(glong page_idx)
|
|
+{
|
|
+ gulong nentr=ENTR_PER_PAGE;
|
|
+ if (page_idx==glong(npages-2))
|
|
+ if ((nentr=wordcount%ENTR_PER_PAGE)==0)
|
|
+ nentr=ENTR_PER_PAGE;
|
|
+
|
|
+
|
|
+ if (page_idx!=page.idx) {
|
|
+ page_data.resize(oft_file.wordoffset[page_idx+1]-oft_file.wordoffset[page_idx]);
|
|
+ fseek(idxfile, oft_file.wordoffset[page_idx], SEEK_SET);
|
|
+ fread(&page_data[0], 1, page_data.size(), idxfile);
|
|
+ page.fill(&page_data[0], nentr, page_idx);
|
|
+ }
|
|
+
|
|
+ return nentr;
|
|
+}
|
|
+
|
|
+const gchar *offset_index::get_key(glong idx)
|
|
+{
|
|
+ load_page(idx/ENTR_PER_PAGE);
|
|
+ glong idx_in_page=idx%ENTR_PER_PAGE;
|
|
+ wordentry_offset=page.entries[idx_in_page].off;
|
|
+ wordentry_size=page.entries[idx_in_page].size;
|
|
+
|
|
+ return page.entries[idx_in_page].keystr;
|
|
+}
|
|
+
|
|
+void offset_index::get_data(glong idx)
|
|
+{
|
|
+ get_key(idx);
|
|
+}
|
|
+
|
|
+const gchar *offset_index::get_key_and_data(glong idx)
|
|
+{
|
|
+ return get_key(idx);
|
|
+}
|
|
+
|
|
+bool offset_index::lookup(const char *str, glong &idx, glong &idx_suggest)
|
|
+{
|
|
+ bool bFound=false;
|
|
+ glong iFrom;
|
|
+ glong iTo=npages-2;
|
|
+ gint cmpint;
|
|
+ glong iThisIndex;
|
|
+ if (stardict_strcmp(str, first.keystr.c_str())<0) {
|
|
+ idx = 0;
|
|
+ idx_suggest = 0;
|
|
+ return false;
|
|
+ } else if (stardict_strcmp(str, real_last.keystr.c_str()) >0) {
|
|
+ idx = INVALID_INDEX;
|
|
+ idx_suggest = iTo;
|
|
+ return false;
|
|
+ } else {
|
|
+ iFrom=0;
|
|
+ iThisIndex=0;
|
|
+ while (iFrom<=iTo) {
|
|
+ iThisIndex=(iFrom+iTo)/2;
|
|
+ cmpint = stardict_strcmp(str, get_first_on_page_key(iThisIndex));
|
|
+ if (cmpint>0)
|
|
+ iFrom=iThisIndex+1;
|
|
+ else if (cmpint<0)
|
|
+ iTo=iThisIndex-1;
|
|
+ else {
|
|
+ bFound=true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if (!bFound) {
|
|
+ idx = iTo; //prev
|
|
+ } else {
|
|
+ idx = iThisIndex;
|
|
+ }
|
|
+ }
|
|
+ if (!bFound) {
|
|
+ gulong netr=load_page(idx);
|
|
+ iFrom=1; // Needn't search the first word anymore.
|
|
+ iTo=netr-1;
|
|
+ iThisIndex=0;
|
|
+ while (iFrom<=iTo) {
|
|
+ iThisIndex=(iFrom+iTo)/2;
|
|
+ cmpint = stardict_strcmp(str, page.entries[iThisIndex].keystr);
|
|
+ if (cmpint>0)
|
|
+ iFrom=iThisIndex+1;
|
|
+ else if (cmpint<0)
|
|
+ iTo=iThisIndex-1;
|
|
+ else {
|
|
+ bFound=true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ idx*=ENTR_PER_PAGE;
|
|
+ if (!bFound) {
|
|
+ idx += iFrom; //next
|
|
+ idx_suggest = idx;
|
|
+ gint best, back;
|
|
+ best = prefix_match (str, page.entries[idx_suggest % ENTR_PER_PAGE].keystr);
|
|
+ for (;;) {
|
|
+ if ((iTo=idx_suggest-1) < 0)
|
|
+ break;
|
|
+ if (idx_suggest % ENTR_PER_PAGE == 0)
|
|
+ load_page(iTo / ENTR_PER_PAGE);
|
|
+ back = prefix_match (str, page.entries[iTo % ENTR_PER_PAGE].keystr);
|
|
+ if (!back || back < best)
|
|
+ break;
|
|
+ best = back;
|
|
+ idx_suggest = iTo;
|
|
+ }
|
|
+ } else {
|
|
+ idx += iThisIndex;
|
|
+ idx_suggest = idx;
|
|
+ }
|
|
+ } else {
|
|
+ idx*=ENTR_PER_PAGE;
|
|
+ idx_suggest = idx;
|
|
+ }
|
|
+ return bFound;
|
|
+}
|
|
+
|
|
+wordlist_index::wordlist_index()
|
|
+{
|
|
+ clt_file = NULL;
|
|
+ idxdatabuf = NULL;
|
|
+}
|
|
+
|
|
+wordlist_index::~wordlist_index()
|
|
+{
|
|
+ delete clt_file;
|
|
+ g_free(idxdatabuf);
|
|
+}
|
|
+
|
|
+bool wordlist_index::load(const std::string& url, gulong wc, gulong fsize,
|
|
+ bool CreateCacheFile, int EnableCollationLevel,
|
|
+ CollateFunctions _CollateFunction, show_progress_t *sp)
|
|
+{
|
|
+ wordcount=wc;
|
|
+ gzFile in = gzopen(url.c_str(), "rb");
|
|
+ if (in == NULL)
|
|
+ return false;
|
|
+
|
|
+ idxdatabuf = (gchar *)g_malloc(fsize);
|
|
+
|
|
+ gulong len = gzread(in, idxdatabuf, fsize);
|
|
+ gzclose(in);
|
|
+ if (len < 0)
|
|
+ return false;
|
|
+
|
|
+ if (len != fsize)
|
|
+ return false;
|
|
+
|
|
+ wordlist.resize(wc+1);
|
|
+ gchar *p1 = idxdatabuf;
|
|
+ guint32 i;
|
|
+ for (i=0; i<wc; i++) {
|
|
+ wordlist[i] = p1;
|
|
+ p1 += strlen(p1) +1 + 2*sizeof(guint32);
|
|
+ }
|
|
+ wordlist[wc] = p1;
|
|
+
|
|
+ if (EnableCollationLevel == 0) {
|
|
+ } else {
|
|
+ std::string saveurl = url;
|
|
+ saveurl.erase(saveurl.length()-sizeof(".gz")+1, sizeof(".gz")-1);
|
|
+ if (EnableCollationLevel == 1) {
|
|
+ collate_sort(url, saveurl, _CollateFunction, sp);
|
|
+ } else if (EnableCollationLevel == 2) {
|
|
+ collate_save_info(url, saveurl);
|
|
+ }
|
|
+ }
|
|
+ return true;
|
|
+}
|
|
+
|
|
+const gchar *wordlist_index::get_key(glong idx)
|
|
+{
|
|
+ return wordlist[idx];
|
|
+}
|
|
+
|
|
+void wordlist_index::get_data(glong idx)
|
|
+{
|
|
+ gchar *p1 = wordlist[idx]+strlen(wordlist[idx])+sizeof(gchar);
|
|
+ wordentry_offset = g_ntohl(get_uint32(p1));
|
|
+ p1 += sizeof(guint32);
|
|
+ wordentry_size = g_ntohl(get_uint32(p1));
|
|
+}
|
|
+
|
|
+const gchar *wordlist_index::get_key_and_data(glong idx)
|
|
+{
|
|
+ get_data(idx);
|
|
+ return get_key(idx);
|
|
+}
|
|
+
|
|
+bool wordlist_index::lookup(const char *str, glong &idx, glong &idx_suggest)
|
|
+{
|
|
+ bool bFound=false;
|
|
+ glong iTo=wordlist.size()-2;
|
|
+
|
|
+ if (stardict_strcmp(str, get_key(0))<0) {
|
|
+ idx = 0;
|
|
+ idx_suggest = 0;
|
|
+ } else if (stardict_strcmp(str, get_key(iTo)) >0) {
|
|
+ idx = INVALID_INDEX;
|
|
+ idx_suggest = iTo;
|
|
+ } else {
|
|
+ glong iThisIndex=0;
|
|
+ glong iFrom=0;
|
|
+ gint cmpint;
|
|
+ while (iFrom<=iTo) {
|
|
+ iThisIndex=(iFrom+iTo)/2;
|
|
+ cmpint = stardict_strcmp(str, get_key(iThisIndex));
|
|
+ if (cmpint>0)
|
|
+ iFrom=iThisIndex+1;
|
|
+ else if (cmpint<0)
|
|
+ iTo=iThisIndex-1;
|
|
+ else {
|
|
+ bFound=true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if (!bFound) {
|
|
+ idx = iFrom; //next
|
|
+ idx_suggest = iFrom;
|
|
+ gint best, back;
|
|
+ best = prefix_match (str, get_key(idx_suggest));
|
|
+ for (;;) {
|
|
+ if ((iTo=idx_suggest-1) < 0)
|
|
+ break;
|
|
+ back = prefix_match (str, get_key(iTo));
|
|
+ if (!back || back < best)
|
|
+ break;
|
|
+ best = back;
|
|
+ idx_suggest = iTo;
|
|
+ }
|
|
+ } else {
|
|
+ idx = iThisIndex;
|
|
+ idx_suggest = iThisIndex;
|
|
+ }
|
|
+ }
|
|
+ return bFound;
|
|
+}
|
|
+
|
|
+//===================================================================
|
|
+void synonym_file::page_t::fill(gchar *data, gint nent, glong idx_)
|
|
+{
|
|
+ idx=idx_;
|
|
+ gchar *p=data;
|
|
+ glong len;
|
|
+ for (gint i=0; i<nent; ++i) {
|
|
+ entries[i].keystr=p;
|
|
+ len=strlen(p);
|
|
+ p+=len+1;
|
|
+ entries[i].index=g_ntohl(get_uint32(p));
|
|
+ p+=sizeof(guint32);
|
|
+ }
|
|
+}
|
|
+
|
|
+synonym_file::synonym_file() : oft_file(CacheFileType_oft)
|
|
+{
|
|
+ clt_file = NULL;
|
|
+}
|
|
+
|
|
+synonym_file::~synonym_file()
|
|
+{
|
|
+ delete clt_file;
|
|
+ if (synfile)
|
|
+ fclose(synfile);
|
|
+}
|
|
+
|
|
+inline const gchar *synonym_file::read_first_on_page_key(glong page_idx)
|
|
+{
|
|
+ fseek(synfile, oft_file.wordoffset[page_idx], SEEK_SET);
|
|
+ guint32 page_size=oft_file.wordoffset[page_idx+1]-oft_file.wordoffset[page_idx];
|
|
+ gulong minsize = sizeof(wordentry_buf);
|
|
+ if (page_size < minsize)
|
|
+ minsize = page_size;
|
|
+ fread(wordentry_buf, minsize, 1, synfile); //TODO: check returned values, deal with word entry that strlen>255.
|
|
+ return wordentry_buf;
|
|
+}
|
|
+
|
|
+inline const gchar *synonym_file::get_first_on_page_key(glong page_idx)
|
|
+{
|
|
+ if (page_idx<middle.idx) {
|
|
+ if (page_idx==first.idx)
|
|
+ return first.keystr.c_str();
|
|
+ return read_first_on_page_key(page_idx);
|
|
+ } else if (page_idx>middle.idx) {
|
|
+ if (page_idx==last.idx)
|
|
+ return last.keystr.c_str();
|
|
+ return read_first_on_page_key(page_idx);
|
|
+ } else
|
|
+ return middle.keystr.c_str();
|
|
+}
|
|
+
|
|
+bool synonym_file::load(const std::string& url, gulong wc, bool CreateCacheFile,
|
|
+ int EnableCollationLevel, CollateFunctions _CollateFunction,
|
|
+ show_progress_t *sp)
|
|
+{
|
|
+ wordcount=wc;
|
|
+ npages=(wc-1)/ENTR_PER_PAGE+2;
|
|
+ if (!oft_file.load_cache(url, url, _CollateFunction, npages*sizeof(guint32))) {
|
|
+ struct stat stats;
|
|
+ if (stat (url.c_str(), &stats) == -1)
|
|
+ return false;
|
|
+ MapFile map_file;
|
|
+ if (!map_file.open(url.c_str(), stats.st_size))
|
|
+ return false;
|
|
+ const gchar *syndatabuffer=map_file.begin();
|
|
+ oft_file.wordoffset = (guint32 *)g_malloc(npages*sizeof(guint32));
|
|
+ const gchar *p1 = syndatabuffer;
|
|
+ gulong index_size;
|
|
+ guint32 j=0;
|
|
+ for (guint32 i=0; i<wc; i++) {
|
|
+ index_size=strlen(p1) +1 + sizeof(guint32);
|
|
+ if (i % ENTR_PER_PAGE==0) {
|
|
+ oft_file.wordoffset[j]=p1-syndatabuffer;
|
|
+ ++j;
|
|
+ }
|
|
+ p1 += index_size;
|
|
+ }
|
|
+ oft_file.wordoffset[j]=p1-syndatabuffer;
|
|
+ map_file.close();
|
|
+ if (CreateCacheFile) {
|
|
+ if (!oft_file.save_cache(url, _CollateFunction, npages))
|
|
+ g_printerr("Cache update failed.\n");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!(synfile = fopen(url.c_str(), "rb"))) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ first.assign(0, read_first_on_page_key(0));
|
|
+ last.assign(npages-2, read_first_on_page_key(npages-2));
|
|
+ middle.assign((npages-2)/2, read_first_on_page_key((npages-2)/2));
|
|
+ real_last.assign(wc-1, get_key(wc-1));
|
|
+
|
|
+ if (EnableCollationLevel == 0) {
|
|
+ } else if (EnableCollationLevel == 1)
|
|
+ collate_sort(url, url, _CollateFunction, sp);
|
|
+ else if (EnableCollationLevel == 2) {
|
|
+ collate_save_info(url, url);
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+inline gulong synonym_file::load_page(glong page_idx)
|
|
+{
|
|
+ gulong nentr=ENTR_PER_PAGE;
|
|
+ if (page_idx==glong(npages-2))
|
|
+ if ((nentr=wordcount%ENTR_PER_PAGE)==0)
|
|
+ nentr=ENTR_PER_PAGE;
|
|
+
|
|
+
|
|
+ if (page_idx!=page.idx) {
|
|
+ page_data.resize(oft_file.wordoffset[page_idx+1]-oft_file.wordoffset[page_idx]);
|
|
+ fseek(synfile, oft_file.wordoffset[page_idx], SEEK_SET);
|
|
+ fread(&page_data[0], 1, page_data.size(), synfile);
|
|
+ page.fill(&page_data[0], nentr, page_idx);
|
|
+ }
|
|
+
|
|
+ return nentr;
|
|
+}
|
|
+
|
|
+const gchar *synonym_file::get_key(glong idx)
|
|
+{
|
|
+ load_page(idx/ENTR_PER_PAGE);
|
|
+ glong idx_in_page=idx%ENTR_PER_PAGE;
|
|
+ wordentry_index=page.entries[idx_in_page].index;
|
|
+
|
|
+ return page.entries[idx_in_page].keystr;
|
|
+}
|
|
+
|
|
+bool synonym_file::lookup(const char *str, glong &idx, glong &idx_suggest)
|
|
+{
|
|
+ bool bFound=false;
|
|
+ glong iFrom;
|
|
+ glong iTo=npages-2;
|
|
+ gint cmpint;
|
|
+ glong iThisIndex;
|
|
+ if (stardict_strcmp(str, first.keystr.c_str())<0) {
|
|
+ idx = 0;
|
|
+ idx_suggest = 0;
|
|
+ return false;
|
|
+ } else if (stardict_strcmp(str, real_last.keystr.c_str()) >0) {
|
|
+ idx = INVALID_INDEX;
|
|
+ idx_suggest = iTo;
|
|
+ return false;
|
|
+ } else {
|
|
+ iFrom=0;
|
|
+ iThisIndex=0;
|
|
+ while (iFrom<=iTo) {
|
|
+ iThisIndex=(iFrom+iTo)/2;
|
|
+ cmpint = stardict_strcmp(str, get_first_on_page_key(iThisIndex));
|
|
+ if (cmpint>0)
|
|
+ iFrom=iThisIndex+1;
|
|
+ else if (cmpint<0)
|
|
+ iTo=iThisIndex-1;
|
|
+ else {
|
|
+ bFound=true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if (!bFound)
|
|
+ idx = iTo; //prev
|
|
+ else
|
|
+ idx = iThisIndex;
|
|
+ }
|
|
+ if (!bFound) {
|
|
+ gulong netr=load_page(idx);
|
|
+ iFrom=1; // Needn't search the first word anymore.
|
|
+ iTo=netr-1;
|
|
+ iThisIndex=0;
|
|
+ while (iFrom<=iTo) {
|
|
+ iThisIndex=(iFrom+iTo)/2;
|
|
+ cmpint = stardict_strcmp(str, page.entries[iThisIndex].keystr);
|
|
+ if (cmpint>0)
|
|
+ iFrom=iThisIndex+1;
|
|
+ else if (cmpint<0)
|
|
+ iTo=iThisIndex-1;
|
|
+ else {
|
|
+ bFound=true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ idx*=ENTR_PER_PAGE;
|
|
+ if (!bFound) {
|
|
+ idx += iFrom; //next
|
|
+ idx_suggest = idx;
|
|
+ gint best, back;
|
|
+ best = prefix_match (str, page.entries[idx_suggest % ENTR_PER_PAGE].keystr);
|
|
+ for (;;) {
|
|
+ if ((iTo=idx_suggest-1) < 0)
|
|
+ break;
|
|
+ if (idx_suggest % ENTR_PER_PAGE == 0)
|
|
+ load_page(iTo / ENTR_PER_PAGE);
|
|
+ back = prefix_match (str, page.entries[iTo % ENTR_PER_PAGE].keystr);
|
|
+ if (!back || back < best)
|
|
+ break;
|
|
+ best = back;
|
|
+ idx_suggest = iTo;
|
|
+ }
|
|
+ } else {
|
|
+ idx += iThisIndex;
|
|
+ idx_suggest = idx;
|
|
+ }
|
|
+ } else {
|
|
+ idx*=ENTR_PER_PAGE;
|
|
+ idx_suggest = idx;
|
|
+ }
|
|
+ return bFound;
|
|
+}
|
|
+
|
|
+//===================================================================
|
|
+Dict::Dict()
|
|
+{
|
|
+ storage = NULL;
|
|
+}
|
|
+
|
|
+Dict::~Dict()
|
|
+{
|
|
+ delete storage;
|
|
+}
|
|
+
|
|
+bool Dict::load(const std::string& ifofilename, bool CreateCacheFile,
|
|
+ int EnableCollationLevel, CollateFunctions CollateFunction,
|
|
+ show_progress_t *sp)
|
|
+{
|
|
+ gulong idxfilesize;
|
|
+ glong wordcount, synwordcount;
|
|
+ if (!load_ifofile(ifofilename, idxfilesize, wordcount, synwordcount))
|
|
+ return false;
|
|
+ sp->notify_about_start(_("Loading..."));
|
|
+ std::string fullfilename(ifofilename);
|
|
+ fullfilename.replace(fullfilename.length()-sizeof("ifo")+1, sizeof("ifo")-1, "dict.dz");
|
|
+
|
|
+ if (g_file_test(fullfilename.c_str(), G_FILE_TEST_EXISTS)) {
|
|
+ dictdzfile.reset(new dictData);
|
|
+ if (!dictdzfile->open(fullfilename, 0)) {
|
|
+ //g_print("open file %s failed!\n",fullfilename);
|
|
+ return false;
|
|
+ }
|
|
+ } else {
|
|
+ fullfilename.erase(fullfilename.length()-sizeof(".dz")+1, sizeof(".dz")-1);
|
|
+ dictfile = fopen(fullfilename.c_str(),"rb");
|
|
+ if (!dictfile) {
|
|
+ //g_print("open file %s failed!\n",fullfilename);
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ fullfilename=ifofilename;
|
|
+ fullfilename.replace(fullfilename.length()-sizeof("ifo")+1, sizeof("ifo")-1, "idx.gz");
|
|
+
|
|
+ if (g_file_test(fullfilename.c_str(), G_FILE_TEST_EXISTS)) {
|
|
+ idx_file.reset(new wordlist_index);
|
|
+ } else {
|
|
+ fullfilename.erase(fullfilename.length()-sizeof(".gz")+1, sizeof(".gz")-1);
|
|
+ idx_file.reset(new offset_index);
|
|
+ }
|
|
+
|
|
+ if (!idx_file->load(fullfilename, wordcount, idxfilesize,
|
|
+ CreateCacheFile, EnableCollationLevel,
|
|
+ CollateFunction, sp))
|
|
+ return false;
|
|
+
|
|
+ if (synwordcount) {
|
|
+ fullfilename=ifofilename;
|
|
+ fullfilename.replace(fullfilename.length()-sizeof("ifo")+1, sizeof("ifo")-1, "syn");
|
|
+ if (g_file_test(fullfilename.c_str(), G_FILE_TEST_EXISTS)) {
|
|
+ syn_file.reset(new synonym_file);
|
|
+ if (!syn_file->load(fullfilename, synwordcount,
|
|
+ CreateCacheFile, EnableCollationLevel,
|
|
+ CollateFunction, sp))
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ bool has_res = false;
|
|
+ gchar *dirname = g_path_get_dirname(ifofilename.c_str());
|
|
+ fullfilename = dirname;
|
|
+ fullfilename += G_DIR_SEPARATOR_S "res";
|
|
+ if (g_file_test(fullfilename.c_str(), G_FILE_TEST_IS_DIR)) {
|
|
+ has_res = true;
|
|
+ } else {
|
|
+ fullfilename = dirname;
|
|
+ fullfilename += G_DIR_SEPARATOR_S "res.rifo";
|
|
+ if (g_file_test(fullfilename.c_str(), G_FILE_TEST_EXISTS)) {
|
|
+ has_res = true;
|
|
+ }
|
|
+ }
|
|
+ if (has_res) {
|
|
+ storage = new ResourceStorage();
|
|
+ bool failed = storage->load(dirname);
|
|
+ if (failed) {
|
|
+ delete storage;
|
|
+ storage = NULL;
|
|
+ }
|
|
+ }
|
|
+ g_free(dirname);
|
|
+
|
|
+ g_print("bookname: %s , wordcount %lu\n", bookname.c_str(), wordcount);
|
|
+ return true;
|
|
+}
|
|
+
|
|
+bool Dict::load_ifofile(const std::string& ifofilename, gulong &idxfilesize, glong &wordcount, glong &synwordcount)
|
|
+{
|
|
+ DictInfo dict_info;
|
|
+ if (!dict_info.load_from_ifo_file(ifofilename, false))
|
|
+ return false;
|
|
+ if (dict_info.wordcount==0)
|
|
+ return false;
|
|
+
|
|
+ ifo_file_name=dict_info.ifo_file_name;
|
|
+ bookname=dict_info.bookname;
|
|
+
|
|
+ idxfilesize=dict_info.index_file_size;
|
|
+ wordcount=dict_info.wordcount;
|
|
+ synwordcount=dict_info.synwordcount;
|
|
+
|
|
+ sametypesequence=dict_info.sametypesequence;
|
|
+ dicttype=dict_info.dicttype;
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+glong Dict::nsynarticles()
|
|
+{
|
|
+ if (syn_file.get() == NULL)
|
|
+ return 0;
|
|
+ return syn_file->wordcount;
|
|
+}
|
|
+
|
|
+bool Dict::GetWordPrev(glong idx, glong &pidx, bool isidx, int EnableCollationLevel, int servercollatefunc)
|
|
+{
|
|
+ idxsyn_file *is_file;
|
|
+ if (isidx)
|
|
+ is_file = idx_file.get();
|
|
+ else
|
|
+ is_file = syn_file.get();
|
|
+ if (idx==INVALID_INDEX) {
|
|
+ pidx = is_file->wordcount-1;
|
|
+ return true;
|
|
+ }
|
|
+ pidx = idx;
|
|
+ gchar *cWord = g_strdup(is_file->getWord(pidx, EnableCollationLevel, servercollatefunc));
|
|
+ const gchar *pWord;
|
|
+ bool found=false;
|
|
+ while (pidx>0) {
|
|
+ pWord = is_file->getWord(pidx-1, EnableCollationLevel, servercollatefunc);
|
|
+ if (strcmp(pWord, cWord)!=0) {
|
|
+ found=true;
|
|
+ break;
|
|
+ }
|
|
+ pidx--;
|
|
+ }
|
|
+ g_free(cWord);
|
|
+ if (found) {
|
|
+ pidx--;
|
|
+ return true;
|
|
+ } else {
|
|
+ return false;
|
|
+ }
|
|
+}
|
|
+
|
|
+void Dict::GetWordNext(glong &idx, bool isidx, int EnableCollationLevel, int servercollatefunc)
|
|
+{
|
|
+ idxsyn_file *is_file;
|
|
+ if (isidx)
|
|
+ is_file = idx_file.get();
|
|
+ else
|
|
+ is_file = syn_file.get();
|
|
+ gchar *cWord = g_strdup(is_file->getWord(idx, EnableCollationLevel, servercollatefunc));
|
|
+ const gchar *pWord;
|
|
+ bool found=false;
|
|
+ while (idx < is_file->wordcount-1) {
|
|
+ pWord = is_file->getWord(idx+1, EnableCollationLevel, servercollatefunc);
|
|
+ if (strcmp(pWord, cWord)!=0) {
|
|
+ found=true;
|
|
+ break;
|
|
+ }
|
|
+ idx++;
|
|
+ }
|
|
+ g_free(cWord);
|
|
+ if (found)
|
|
+ idx++;
|
|
+ else
|
|
+ idx=INVALID_INDEX;
|
|
+}
|
|
+
|
|
+gint Dict::GetOrigWordCount(glong& idx, bool isidx)
|
|
+{
|
|
+ idxsyn_file *is_file;
|
|
+ if (isidx)
|
|
+ is_file = idx_file.get();
|
|
+ else
|
|
+ is_file = syn_file.get();
|
|
+ gchar *cWord = g_strdup(is_file->get_key(idx));
|
|
+ const gchar *pWord;
|
|
+ gint count = 1;
|
|
+ glong idx1 = idx;
|
|
+ while (idx1>0) {
|
|
+ pWord = is_file->get_key(idx1-1);
|
|
+ if (strcmp(pWord, cWord)!=0)
|
|
+ break;
|
|
+ count++;
|
|
+ idx1--;
|
|
+ }
|
|
+ glong idx2=idx;
|
|
+ while (idx2<is_file->wordcount-1) {
|
|
+ pWord = is_file->get_key(idx2+1);
|
|
+ if (strcmp(pWord, cWord)!=0)
|
|
+ break;
|
|
+ count++;
|
|
+ idx2++;
|
|
+ }
|
|
+ idx=idx1;
|
|
+ g_free(cWord);
|
|
+ return count;
|
|
+}
|
|
+
|
|
+bool Dict::LookupSynonym(const char *str, glong &synidx, glong &synidx_suggest, int EnableCollationLevel, int servercollatefunc)
|
|
+{
|
|
+ if (syn_file.get() == NULL) {
|
|
+ synidx = UNSET_INDEX;
|
|
+ synidx_suggest = UNSET_INDEX;
|
|
+ return false;
|
|
+ }
|
|
+ return syn_file->Lookup(str, synidx, synidx_suggest, EnableCollationLevel, servercollatefunc);
|
|
+}
|
|
+
|
|
+bool Dict::LookupWithRule(GPatternSpec *pspec, glong *aIndex, int iBuffLen)
|
|
+{
|
|
+ int iIndexCount=0;
|
|
+ for (glong i=0; i<narticles() && iIndexCount<iBuffLen-1; i++)
|
|
+ // Need to deal with same word in index? But this will slow down processing in most case.
|
|
+ if (g_pattern_match_string(pspec, idx_file->getWord(i, 0, 0)))
|
|
+ aIndex[iIndexCount++]=i;
|
|
+ aIndex[iIndexCount]= -1; // -1 is the end.
|
|
+ return (iIndexCount>0);
|
|
+}
|
|
+
|
|
+bool Dict::LookupWithRuleSynonym(GPatternSpec *pspec, glong *aIndex, int iBuffLen)
|
|
+{
|
|
+ if (syn_file.get() == NULL)
|
|
+ return false;
|
|
+ int iIndexCount=0;
|
|
+ for (glong i=0; i<nsynarticles() && iIndexCount<iBuffLen-1; i++)
|
|
+ // Need to deal with same word in index? But this will slow down processing in most case.
|
|
+ if (g_pattern_match_string(pspec, syn_file->getWord(i, 0, 0)))
|
|
+ aIndex[iIndexCount++]=i;
|
|
+ aIndex[iIndexCount]= -1; // -1 is the end.
|
|
+ return (iIndexCount>0);
|
|
+}
|
|
+
|
|
+bool Dict::LookupWithRegex(GRegex *regex, glong *aIndex, int iBuffLen)
|
|
+{
|
|
+ int iIndexCount=0;
|
|
+ for (glong i=0; i<narticles() && iIndexCount<iBuffLen-1; i++)
|
|
+ // Need to deal with same word in index? But this will slow down processing in most case.
|
|
+ if (g_regex_match(regex, idx_file->getWord(i, 0, 0), (GRegexMatchFlags)0, NULL))
|
|
+ aIndex[iIndexCount++]=i;
|
|
+ aIndex[iIndexCount]= -1; // -1 is the end.
|
|
+ return (iIndexCount>0);
|
|
+}
|
|
+
|
|
+bool Dict::LookupWithRegexSynonym(GRegex *regex, glong *aIndex, int iBuffLen)
|
|
+{
|
|
+ if (syn_file.get() == NULL)
|
|
+ return false;
|
|
+ int iIndexCount=0;
|
|
+ for (glong i=0; i<nsynarticles() && iIndexCount<iBuffLen-1; i++)
|
|
+ // Need to deal with same word in index? But this will slow down processing in most case.
|
|
+ if (g_regex_match(regex, syn_file->getWord(i, 0, 0), (GRegexMatchFlags)0, NULL))
|
|
+ aIndex[iIndexCount++]=i;
|
|
+ aIndex[iIndexCount]= -1; // -1 is the end.
|
|
+ return (iIndexCount>0);
|
|
+}
|
|
+
|
|
+//===================================================================
|
|
+show_progress_t Libs::default_show_progress;
|
|
+
|
|
+Libs::Libs(show_progress_t *sp, bool create, int enablelevel, int function)
|
|
+{
|
|
+#ifdef SD_SERVER_CODE
|
|
+ root_info_item = NULL;
|
|
+#endif
|
|
+ set_show_progress(sp);
|
|
+ CreateCacheFile = create;
|
|
+ EnableCollationLevel = enablelevel;
|
|
+ CollateFunction = (CollateFunctions)function;
|
|
+ iMaxFuzzyDistance = MAX_FUZZY_DISTANCE; //need to read from cfg.
|
|
+ if (EnableCollationLevel == 0) {
|
|
+ } else if (EnableCollationLevel == 1) {
|
|
+ if (utf8_collate_init(CollateFunction))
|
|
+ printf("Init collate function failed!\n");
|
|
+ } else if (EnableCollationLevel == 2){
|
|
+ if (utf8_collate_init_all())
|
|
+ printf("Init collate functions failed!\n");
|
|
+ }
|
|
+}
|
|
+
|
|
+Libs::~Libs()
|
|
+{
|
|
+#ifdef SD_SERVER_CODE
|
|
+ if (root_info_item)
|
|
+ delete root_info_item;
|
|
+#endif
|
|
+ for (std::vector<Dict *>::iterator p=oLib.begin(); p!=oLib.end(); ++p)
|
|
+ delete *p;
|
|
+ utf8_collate_end();
|
|
+}
|
|
+
|
|
+bool Libs::load_dict(const std::string& url, show_progress_t *sp)
|
|
+{
|
|
+ Dict *lib=new Dict;
|
|
+ if (lib->load(url, CreateCacheFile, EnableCollationLevel,
|
|
+ CollateFunction, sp)) {
|
|
+ oLib.push_back(lib);
|
|
+ return true;
|
|
+ } else {
|
|
+ delete lib;
|
|
+ return false;
|
|
+ }
|
|
+}
|
|
+
|
|
+#ifdef SD_SERVER_CODE
|
|
+void Libs::LoadFromXML()
|
|
+{
|
|
+ root_info_item = new DictInfoItem();
|
|
+ root_info_item->isdir = 1;
|
|
+ root_info_item->dir = new DictInfoDirItem();
|
|
+ root_info_item->dir->name='/';
|
|
+ LoadXMLDir("/usr/share/stardict/dic", root_info_item);
|
|
+ GenLinkDict(root_info_item);
|
|
+}
|
|
+
|
|
+void Libs::GenLinkDict(DictInfoItem *info_item)
|
|
+{
|
|
+ std::list<std::list<DictInfoItem *>::iterator> eraselist;
|
|
+ for (std::list<DictInfoItem *>::iterator i = info_item->dir->info_item_list.begin(); i!= info_item->dir->info_item_list.end(); ++i) {
|
|
+ if ((*i)->isdir == 1) {
|
|
+ GenLinkDict(*i);
|
|
+ } else if ((*i)->isdir == 2) {
|
|
+ std::map<std::string, DictInfoDictItem *>::iterator uid_iter;
|
|
+ uid_iter = uidmap.find(*((*i)->linkuid));
|
|
+ if (uid_iter!=uidmap.end()) {
|
|
+ delete (*i)->linkuid;
|
|
+ (*i)->dict = uid_iter->second;
|
|
+ } else {
|
|
+ g_print("Error, linkdict uid not found! %s\n", (*i)->linkuid->c_str());
|
|
+ delete (*i)->linkuid;
|
|
+ eraselist.push_back(i);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ for (std::list<std::list<DictInfoItem *>::iterator>::iterator i = eraselist.begin(); i!= eraselist.end(); ++i) {
|
|
+ info_item->dir->info_item_list.erase(*i);
|
|
+ }
|
|
+}
|
|
+
|
|
+void Libs::func_parse_start_element(GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **error)
|
|
+{
|
|
+ if (strcmp(element_name, "dict")==0) {
|
|
+ ParseUserData *Data = (ParseUserData *)user_data;
|
|
+ Data->indict = true;
|
|
+ Data->path.clear();
|
|
+ Data->uid.clear();
|
|
+ Data->level.clear();
|
|
+ Data->download.clear();
|
|
+ Data->from.clear();
|
|
+ Data->to.clear();
|
|
+ } else if (strcmp(element_name, "linkdict")==0) {
|
|
+ ParseUserData *Data = (ParseUserData *)user_data;
|
|
+ Data->inlinkdict = true;
|
|
+ Data->linkuid.clear();
|
|
+ }
|
|
+}
|
|
+
|
|
+void Libs::func_parse_end_element(GMarkupParseContext *context, const gchar *element_name, gpointer user_data, GError **error)
|
|
+{
|
|
+ if (strcmp(element_name, "dict")==0) {
|
|
+ ParseUserData *Data = (ParseUserData *)user_data;
|
|
+ Data->indict = false;
|
|
+ if (!Data->path.empty() && !Data->uid.empty()) {
|
|
+ std::string url;
|
|
+ url = Data->dir;
|
|
+ url += G_DIR_SEPARATOR;
|
|
+ url += Data->path;
|
|
+ if (Data->oLibs->load_dict(url, Data->oLibs->show_progress)) {
|
|
+ DictInfoItem *sub_info_item = new DictInfoItem();
|
|
+ sub_info_item->isdir = 0;
|
|
+ sub_info_item->dict = new DictInfoDictItem();
|
|
+ sub_info_item->dict->uid = Data->uid;
|
|
+ sub_info_item->dict->download = Data->download;
|
|
+ sub_info_item->dict->from = Data->from;
|
|
+ sub_info_item->dict->to = Data->to;
|
|
+ if (Data->level.empty())
|
|
+ sub_info_item->dict->level = 0;
|
|
+ else
|
|
+ sub_info_item->dict->level = atoi(Data->level.c_str());
|
|
+ sub_info_item->dict->id = Data->oLibs->oLib.size()-1;
|
|
+ Data->info_item->dir->info_item_list.push_back(sub_info_item);
|
|
+ Data->oLibs->uidmap[Data->uid] = sub_info_item->dict;
|
|
+ }
|
|
+ }
|
|
+ } else if (strcmp(element_name, "linkdict")==0) {
|
|
+ ParseUserData *Data = (ParseUserData *)user_data;
|
|
+ Data->inlinkdict = false;
|
|
+ if (!Data->linkuid.empty()) {
|
|
+ DictInfoItem *sub_info_item = new DictInfoItem();
|
|
+ sub_info_item->isdir = 2;
|
|
+ sub_info_item->linkuid = new std::string(Data->linkuid);
|
|
+ Data->info_item->dir->info_item_list.push_back(sub_info_item);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+void Libs::func_parse_text(GMarkupParseContext *context, const gchar *text, gsize text_len, gpointer user_data, GError **error)
|
|
+{
|
|
+ const gchar *element = g_markup_parse_context_get_element(context);
|
|
+ if (!element)
|
|
+ return;
|
|
+ ParseUserData *Data = (ParseUserData *)user_data;
|
|
+ if (strcmp(element, "subdir")==0) {
|
|
+ std::string subdir;
|
|
+ subdir = Data->dir;
|
|
+ subdir += G_DIR_SEPARATOR;
|
|
+ subdir.append(text, text_len);
|
|
+ DictInfoItem *sub_info_item = new DictInfoItem();
|
|
+ sub_info_item->isdir = 1;
|
|
+ sub_info_item->dir = new DictInfoDirItem();
|
|
+ sub_info_item->dir->name.assign(text, text_len);
|
|
+ Data->oLibs->LoadXMLDir(subdir.c_str(), sub_info_item);
|
|
+ Data->info_item->dir->info_item_list.push_back(sub_info_item);
|
|
+ } else if (strcmp(element, "dirname")==0) {
|
|
+ Data->info_item->dir->dirname.assign(text, text_len);
|
|
+ } else if (strcmp(element, "path")==0) {
|
|
+ Data->path.assign(text, text_len);
|
|
+ } else if (strcmp(element, "uid")==0) {
|
|
+ if (Data->indict) {
|
|
+ std::string uid(text, text_len);
|
|
+ if (uid.find_first_of(' ')!=std::string::npos) {
|
|
+ g_print("Error: uid contains space! %s: %s\n", Data->dir, uid.c_str());
|
|
+ } else {
|
|
+ std::map<std::string, DictInfoDictItem *>::iterator uid_iter;
|
|
+ uid_iter = Data->oLibs->uidmap.find(uid);
|
|
+ if (uid_iter!=Data->oLibs->uidmap.end()) {
|
|
+ g_print("Error: uid duplicated! %s: %s\n", Data->dir, uid.c_str());
|
|
+ } else {
|
|
+ Data->uid = uid;
|
|
+ }
|
|
+ }
|
|
+ } else if (Data->inlinkdict) {
|
|
+ Data->linkuid.assign(text, text_len);
|
|
+ }
|
|
+ } else if (strcmp(element, "level")==0) {
|
|
+ Data->level.assign(text, text_len);
|
|
+ } else if (strcmp(element, "download")==0) {
|
|
+ Data->download.assign(text, text_len);
|
|
+ } else if (strcmp(element, "from")==0) {
|
|
+ Data->from.assign(text, text_len);
|
|
+ } else if (strcmp(element, "to")==0) {
|
|
+ Data->to.assign(text, text_len);
|
|
+ }
|
|
+}
|
|
+
|
|
+void Libs::LoadXMLDir(const char *dir, DictInfoItem *info_item)
|
|
+{
|
|
+ std::string filename;
|
|
+ filename = dir;
|
|
+ filename += G_DIR_SEPARATOR_S "stardictd.xml";
|
|
+ struct stat filestat;
|
|
+ if (g_stat(filename.c_str(), &filestat)!=0)
|
|
+ return;
|
|
+ MapFile mf;
|
|
+ if (!mf.open(filename.c_str(), filestat.st_size))
|
|
+ return;
|
|
+ ParseUserData Data;
|
|
+ Data.oLibs = this;
|
|
+ Data.dir = dir;
|
|
+ Data.info_item = info_item;
|
|
+ Data.indict = false;
|
|
+ Data.inlinkdict = false;
|
|
+ GMarkupParser parser;
|
|
+ parser.start_element = func_parse_start_element;
|
|
+ parser.end_element = func_parse_end_element;
|
|
+ parser.text = func_parse_text;
|
|
+ parser.passthrough = NULL;
|
|
+ parser.error = NULL;
|
|
+ GMarkupParseContext* context = g_markup_parse_context_new(&parser, (GMarkupParseFlags)0, &Data, NULL);
|
|
+ g_markup_parse_context_parse(context, mf.begin(), filestat.st_size, NULL);
|
|
+ g_markup_parse_context_end_parse(context, NULL);
|
|
+ g_markup_parse_context_free(context);
|
|
+ mf.close();
|
|
+ info_item->dir->dictcount = 0;
|
|
+ for (std::list<DictInfoItem *>::iterator i = info_item->dir->info_item_list.begin(); i!= info_item->dir->info_item_list.end(); ++i) {
|
|
+ if ((*i)->isdir == 1) {
|
|
+ info_item->dir->dictcount += (*i)->dir->dictcount;
|
|
+ } else if ((*i)->isdir == 0) {
|
|
+ info_item->dir->dictcount++;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+const std::string &Libs::get_fromto_info() {
|
|
+ if(cache_fromto.empty()){
|
|
+ std::map<std::string, std::list<FromTo> > map_fromto;
|
|
+ gen_fromto_info(root_info_item, map_fromto);
|
|
+ cache_fromto+="<lang>";
|
|
+ for (std::map<std::string, std::list<FromTo> >::iterator map_it = map_fromto.begin(); map_it != map_fromto.end(); ++map_it){
|
|
+ cache_fromto+="<from lang=\"";
|
|
+ cache_fromto+=map_it->first;
|
|
+ cache_fromto+="\">";
|
|
+ std::list<FromTo> &fromTo = map_it->second;
|
|
+ for (std::list<FromTo>::iterator i = fromTo.begin() ; i!= fromTo.end(); ++i){
|
|
+ cache_fromto+="<to lang=\"";
|
|
+ cache_fromto+= i->to;
|
|
+ cache_fromto+="\">";
|
|
+ std::list<FromToInfo> &fromtoinfo = i->fromto_info;
|
|
+ for (std::list<FromToInfo>::iterator j = fromtoinfo.begin() ; j!= fromtoinfo.end(); ++j){
|
|
+ cache_fromto+="<dict><uid>";
|
|
+ cache_fromto+=j->uid;
|
|
+ cache_fromto+="</uid><bookname>";
|
|
+ cache_fromto+= j->bookname;
|
|
+ cache_fromto+="</bookname></dict>";
|
|
+ }
|
|
+ cache_fromto+="</to>";
|
|
+ }
|
|
+ cache_fromto+="</from>";
|
|
+ }
|
|
+ cache_fromto+="</lang>";
|
|
+ }
|
|
+ return cache_fromto;
|
|
+}
|
|
+
|
|
+void Libs::gen_fromto_info(struct DictInfoItem *info_item, std::map<std::string, std::list<FromTo> > &map_fromto) {
|
|
+ gchar *etext;
|
|
+ for(std::list<DictInfoItem *>::iterator i = info_item->dir->info_item_list.begin() ; i!= info_item->dir->info_item_list.end(); ++i){
|
|
+ if ((*i)->isdir == 1) {
|
|
+ gen_fromto_info((*i), map_fromto);
|
|
+ } else {
|
|
+ std::string from_str = (*i)->dict->from;
|
|
+ std::string to_str = (*i)->dict->to;
|
|
+ if(from_str.empty() || to_str.empty()){
|
|
+ continue;
|
|
+ }
|
|
+ std::string uid_str = (*i)->dict->uid;
|
|
+ etext = g_markup_escape_text(oLib[(*i)->dict->id]->dict_name().c_str(), -1);
|
|
+ std::string bookname_str = etext;
|
|
+ g_free(etext);
|
|
+ std::map<std::string, std::list<FromTo> >::iterator fromto1 = map_fromto.find(from_str);
|
|
+ if (fromto1==map_fromto.end()) {
|
|
+ //if an from_str element not already in map, add new from_str to map
|
|
+ FromToInfo fromtoinfo;
|
|
+ fromtoinfo.uid = uid_str;
|
|
+ fromtoinfo.bookname = bookname_str;
|
|
+ std::list<FromToInfo> list_fromtoinfo ;
|
|
+ list_fromtoinfo.push_back(fromtoinfo);
|
|
+ FromTo new_fromTo;
|
|
+ new_fromTo.to = to_str;
|
|
+ new_fromTo.fromto_info = list_fromtoinfo;
|
|
+ std::list<FromTo> list_fromTo;
|
|
+ list_fromTo.push_back(new_fromTo);
|
|
+ map_fromto[from_str] = list_fromTo;
|
|
+ } else {
|
|
+ // else if from_str already in map, so comparison to_str and from_to1 , then choose insert.
|
|
+ std::list<FromTo> &fromTo_list = fromto1->second;
|
|
+ std::string from_name1 = fromto1->first;
|
|
+ bool found = false;
|
|
+ for (std::list<FromTo>::iterator new_fromTo = fromTo_list.begin(); new_fromTo != fromTo_list.end(); ++new_fromTo) {
|
|
+ if(to_str == new_fromTo->to) {
|
|
+ std::list<FromToInfo> &fromtoinfo1 = new_fromTo->fromto_info;
|
|
+ FromToInfo fromtoinfo;
|
|
+ fromtoinfo.uid = uid_str;
|
|
+ fromtoinfo.bookname = bookname_str;
|
|
+ fromtoinfo1.push_back(fromtoinfo);
|
|
+ found = true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if(!found){
|
|
+ FromToInfo fromtoinfo;
|
|
+ fromtoinfo.uid = uid_str;
|
|
+ fromtoinfo.bookname = bookname_str;
|
|
+ std::list<FromToInfo> fromtoinfo1;
|
|
+ fromtoinfo1.push_back(fromtoinfo);
|
|
+ FromTo fromTo;
|
|
+ fromTo.to = to_str;
|
|
+ fromTo.fromto_info = fromtoinfo1;
|
|
+ fromTo_list.push_back(fromTo);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+const std::string *Libs::get_dir_info(const char *path)
|
|
+{
|
|
+ if (path[0]!='/')
|
|
+ return NULL;
|
|
+ DictInfoItem *info_item = root_info_item;
|
|
+ std::string item;
|
|
+ const char *p = path+1;
|
|
+ const char *p1;
|
|
+ bool found;
|
|
+ do {
|
|
+ p1 = strchr(p, '/');
|
|
+ if (p1) {
|
|
+ item.assign(p, p1-p);
|
|
+ if (!item.empty()) {
|
|
+ found = false;
|
|
+ for (std::list<DictInfoItem *>::iterator i = info_item->dir->info_item_list.begin(); i!= info_item->dir->info_item_list.end(); ++i) {
|
|
+ if ((*i)->isdir == 1) {
|
|
+ if ((*i)->dir->name == item) {
|
|
+ info_item = (*i);
|
|
+ found = true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ if (!found)
|
|
+ return NULL;
|
|
+ }
|
|
+ p = p1+1;
|
|
+ }
|
|
+ } while (p1);
|
|
+ if (*p)
|
|
+ return NULL; // Not end by '/'.
|
|
+ DictInfoDirItem *dir = info_item->dir;
|
|
+ if (dir->info_string.empty()) {
|
|
+ dir->info_string += "<parent>";
|
|
+ dir->info_string += path;
|
|
+ dir->info_string += "</parent>";
|
|
+ gchar *etext;
|
|
+ for (std::list<DictInfoItem *>::iterator i = info_item->dir->info_item_list.begin(); i!= info_item->dir->info_item_list.end(); ++i) {
|
|
+ if ((*i)->isdir == 1) {
|
|
+ dir->info_string += "<dir><name>";
|
|
+ dir->info_string += (*i)->dir->name;
|
|
+ dir->info_string += "</name><dirname>";
|
|
+ dir->info_string += (*i)->dir->dirname;
|
|
+ dir->info_string += "</dirname><dictcount>";
|
|
+ gchar *dictcount = g_strdup_printf("%u", (*i)->dir->dictcount);
|
|
+ dir->info_string += dictcount;
|
|
+ g_free(dictcount);
|
|
+ dir->info_string += "</dictcount></dir>";
|
|
+ } else {
|
|
+ dir->info_string += "<dict>";
|
|
+ if ((*i)->isdir == 2)
|
|
+ dir->info_string += "<islink>1</islink>";
|
|
+ if ((*i)->dict->level != 0) {
|
|
+ dir->info_string += "<level>";
|
|
+ gchar *level = g_strdup_printf("%u", (*i)->dict->level);
|
|
+ dir->info_string += level;
|
|
+ g_free(level);
|
|
+ dir->info_string += "</level>";
|
|
+ }
|
|
+ dir->info_string += "<uid>";
|
|
+ dir->info_string += (*i)->dict->uid;
|
|
+ dir->info_string += "</uid><bookname>";
|
|
+ etext = g_markup_escape_text(oLib[(*i)->dict->id]->dict_name().c_str(), -1);
|
|
+ dir->info_string += etext;
|
|
+ g_free(etext);
|
|
+ dir->info_string += "</bookname><wordcount>";
|
|
+ gchar *wc = g_strdup_printf("%ld", oLib[(*i)->dict->id]->narticles());
|
|
+ dir->info_string += wc;
|
|
+ g_free(wc);
|
|
+ dir->info_string += "</wordcount></dict>";
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return &(dir->info_string);
|
|
+}
|
|
+
|
|
+int Libs::get_dict_level(const char *uid)
|
|
+{
|
|
+ std::map<std::string, DictInfoDictItem *>::iterator uid_iter;
|
|
+ uid_iter = uidmap.find(uid);
|
|
+ if (uid_iter==uidmap.end())
|
|
+ return -1;
|
|
+ return uid_iter->second->level;
|
|
+}
|
|
+
|
|
+std::string Libs::get_dicts_list(const char *dictmask, int max_dict_count, int userLevel)
|
|
+{
|
|
+ std::list<std::string> uid_list;
|
|
+ std::string uid;
|
|
+ const char *p, *p1;
|
|
+ p = dictmask;
|
|
+ do {
|
|
+ p1 = strchr(p, ' ');
|
|
+ if (p1) {
|
|
+ uid.assign(p, p1-p);
|
|
+ if (!uid.empty())
|
|
+ uid_list.push_back(uid);
|
|
+ p = p1+1;
|
|
+ }
|
|
+ } while (p1);
|
|
+ uid = p;
|
|
+ if (!uid.empty())
|
|
+ uid_list.push_back(uid);
|
|
+
|
|
+ std::string dictmask_str;
|
|
+ int count = 0;
|
|
+ const std::string *info_string;
|
|
+ int level;
|
|
+ for (std::list<std::string>::iterator i = uid_list.begin(); i!= uid_list.end(); ++i) {
|
|
+ level = get_dict_level((*i).c_str());
|
|
+ if (level < 0 || level > userLevel)
|
|
+ continue;
|
|
+ info_string = get_dict_info(i->c_str(), true);
|
|
+ if (info_string) {
|
|
+ if (count>=max_dict_count)
|
|
+ break;
|
|
+ dictmask_str += info_string->c_str();
|
|
+ count++;
|
|
+ }
|
|
+ }
|
|
+ return dictmask_str;
|
|
+}
|
|
+
|
|
+const std::string *Libs::get_dict_info(const char *uid, bool is_short)
|
|
+{
|
|
+ std::map<std::string, DictInfoDictItem *>::iterator uid_iter;
|
|
+ uid_iter = uidmap.find(uid);
|
|
+ if (uid_iter==uidmap.end())
|
|
+ return NULL;
|
|
+ DictInfoDictItem *dict;
|
|
+ dict = uid_iter->second;
|
|
+ if (is_short) {
|
|
+ if (dict->short_info_string.empty()) {
|
|
+ gchar *etext;
|
|
+ dict->short_info_string += "<dict><uid>";
|
|
+ dict->short_info_string += uid;
|
|
+ dict->short_info_string += "</uid><bookname>";
|
|
+ etext = g_markup_escape_text(oLib[dict->id]->dict_name().c_str(), -1);
|
|
+ dict->short_info_string += etext;
|
|
+ g_free(etext);
|
|
+ dict->short_info_string += "</bookname><wordcount>";
|
|
+ gchar *wc = g_strdup_printf("%ld", oLib[dict->id]->narticles());
|
|
+ dict->short_info_string += wc;
|
|
+ g_free(wc);
|
|
+ dict->short_info_string += "</wordcount></dict>";
|
|
+ }
|
|
+ return &(dict->short_info_string);
|
|
+ } else {
|
|
+ if (dict->info_string.empty()) {
|
|
+ gchar *etext;
|
|
+ DictInfo dict_info;
|
|
+ if (!dict_info.load_from_ifo_file(oLib[dict->id]->ifofilename(), false))
|
|
+ return NULL;
|
|
+ dict->info_string += "<dictinfo><bookname>";
|
|
+ etext = g_markup_escape_text(dict_info.bookname.c_str(), -1);
|
|
+ dict->info_string += etext;
|
|
+ g_free(etext);
|
|
+ dict->info_string += "</bookname><wordcount>";
|
|
+ gchar *wc = g_strdup_printf("%u", dict_info.wordcount);
|
|
+ dict->info_string += wc;
|
|
+ g_free(wc);
|
|
+ dict->info_string += "</wordcount>";
|
|
+ if (dict_info.synwordcount!=0) {
|
|
+ dict->info_string += "<synwordcount>";
|
|
+ wc = g_strdup_printf("%u", dict_info.synwordcount);
|
|
+ dict->info_string += wc;
|
|
+ g_free(wc);
|
|
+ dict->info_string += "</synwordcount>";
|
|
+ }
|
|
+ dict->info_string += "<author>";
|
|
+ etext = g_markup_escape_text(dict_info.author.c_str(), -1);
|
|
+ dict->info_string += etext;
|
|
+ g_free(etext);
|
|
+ dict->info_string += "</author><email>";
|
|
+ etext = g_markup_escape_text(dict_info.email.c_str(), -1);
|
|
+ dict->info_string += etext;
|
|
+ g_free(etext);
|
|
+ dict->info_string += "</email><website>";
|
|
+ etext = g_markup_escape_text(dict_info.website.c_str(), -1);
|
|
+ dict->info_string += etext;
|
|
+ g_free(etext);
|
|
+ dict->info_string += "</website><description>";
|
|
+ etext = g_markup_escape_text(dict_info.description.c_str(), -1);
|
|
+ dict->info_string += etext;
|
|
+ g_free(etext);
|
|
+ dict->info_string += "</description><date>";
|
|
+ etext = g_markup_escape_text(dict_info.date.c_str(), -1);
|
|
+ dict->info_string += etext;
|
|
+ g_free(etext);
|
|
+ dict->info_string += "</date><download>";
|
|
+ etext = g_markup_escape_text(dict->download.c_str(), -1);
|
|
+ dict->info_string += etext;
|
|
+ g_free(etext);
|
|
+ dict->info_string += "</download></dictinfo>";
|
|
+ }
|
|
+ return &(dict->info_string);
|
|
+ }
|
|
+}
|
|
+
|
|
+void Libs::SetServerDictMask(std::vector<InstantDictIndex> &dictmask, const char *dicts, int max, int userLevel)
|
|
+{
|
|
+ InstantDictIndex instance_dict_index;
|
|
+ instance_dict_index.type = InstantDictType_LOCAL;
|
|
+ dictmask.clear();
|
|
+ std::list<std::string> uid_list;
|
|
+ std::string uid;
|
|
+ const char *p, *p1;
|
|
+ p = dicts;
|
|
+ do {
|
|
+ p1 = strchr(p, ' ');
|
|
+ if (p1) {
|
|
+ uid.assign(p, p1-p);
|
|
+ if (!uid.empty())
|
|
+ uid_list.push_back(uid);
|
|
+ p = p1+1;
|
|
+ }
|
|
+ } while (p1);
|
|
+ uid = p;
|
|
+ if (!uid.empty())
|
|
+ uid_list.push_back(uid);
|
|
+ int count = 0;
|
|
+ std::map<std::string, DictInfoDictItem *>::iterator uid_iter;
|
|
+ for (std::list<std::string>::iterator i = uid_list.begin(); i!= uid_list.end(); ++i) {
|
|
+ uid_iter = uidmap.find(*i);
|
|
+ if (uid_iter!=uidmap.end()) {
|
|
+ if (max>=0 && count >= max)
|
|
+ break;
|
|
+ if (userLevel>=0 && (unsigned int)userLevel< uid_iter->second->level)
|
|
+ continue;
|
|
+ instance_dict_index.index = uid_iter->second->id;
|
|
+ dictmask.push_back(instance_dict_index);
|
|
+ count++;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+void Libs::LoadCollateFile(std::vector<InstantDictIndex> &dictmask, CollateFunctions cltfuc)
|
|
+{
|
|
+ for (std::vector<InstantDictIndex>::iterator i = dictmask.begin(); i!=dictmask.end(); ++i) {
|
|
+ if ((*i).type == InstantDictType_LOCAL) {
|
|
+ oLib[(*i).index]->idx_file->collate_load(cltfuc);
|
|
+ if (oLib[(*i).index]->syn_file.get() != NULL)
|
|
+ oLib[(*i).index]->syn_file->collate_load(cltfuc);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+#endif
|
|
+
|
|
+#ifdef SD_CLIENT_CODE
|
|
+bool Libs::find_lib_by_filename(const char *filename, size_t &iLib)
|
|
+{
|
|
+ for (std::vector<Dict *>::size_type i =0; i < oLib.size(); i++) {
|
|
+ if (oLib[i]->ifofilename() == filename) {
|
|
+ iLib = i;
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
+void Libs::load(std::list<std::string> &load_list)
|
|
+{
|
|
+ for (std::list<std::string>::iterator i = load_list.begin(); i != load_list.end(); ++i) {
|
|
+ load_dict(*i, show_progress);
|
|
+ }
|
|
+}
|
|
+
|
|
+void Libs::reload(std::list<std::string> &load_list, int is_coll_enb, int collf)
|
|
+{
|
|
+ if (is_coll_enb == EnableCollationLevel && collf == CollateFunction) {
|
|
+ std::vector<Dict *> prev(oLib);
|
|
+ oLib.clear();
|
|
+ for (std::list<std::string>::iterator i = load_list.begin(); i != load_list.end(); ++i) {
|
|
+ std::vector<Dict *>::iterator it;
|
|
+ for (it=prev.begin(); it!=prev.end(); ++it) {
|
|
+ if ((*it)->ifofilename()==*i)
|
|
+ break;
|
|
+ }
|
|
+ if (it==prev.end()) {
|
|
+ load_dict(*i, show_progress);
|
|
+ } else {
|
|
+ Dict *res=*it;
|
|
+ prev.erase(it);
|
|
+ oLib.push_back(res);
|
|
+ }
|
|
+ }
|
|
+ for (std::vector<Dict *>::iterator it=prev.begin(); it!=prev.end(); ++it) {
|
|
+ delete *it;
|
|
+ }
|
|
+ } else {
|
|
+ for (std::vector<Dict *>::iterator it = oLib.begin(); it != oLib.end(); ++it)
|
|
+ delete *it;
|
|
+ oLib.clear();
|
|
+ EnableCollationLevel = is_coll_enb;
|
|
+ CollateFunction = CollateFunctions(collf);
|
|
+ if (EnableCollationLevel == 0) {
|
|
+ } else if (EnableCollationLevel == 1) {
|
|
+ if (utf8_collate_init(CollateFunction))
|
|
+ printf("Init collate function failed!\n");
|
|
+ } else if (EnableCollationLevel == 2) {
|
|
+ if (utf8_collate_init_all())
|
|
+ printf("Init collate functions failed!\n");
|
|
+ }
|
|
+ load(load_list);
|
|
+ }
|
|
+}
|
|
+#endif
|
|
+
|
|
+glong Libs::CltIndexToOrig(glong cltidx, size_t iLib, int servercollatefunc)
|
|
+{
|
|
+ if (EnableCollationLevel == 0)
|
|
+ return cltidx;
|
|
+ if (EnableCollationLevel == 1) {
|
|
+ if (cltidx == INVALID_INDEX)
|
|
+ return cltidx;
|
|
+ return oLib[iLib]->idx_file->clt_file->GetOrigIndex(cltidx);
|
|
+ }
|
|
+ if (servercollatefunc == 0)
|
|
+ return cltidx;
|
|
+ if (cltidx == INVALID_INDEX)
|
|
+ return cltidx;
|
|
+ oLib[iLib]->idx_file->collate_load((CollateFunctions)(servercollatefunc-1));
|
|
+ return oLib[iLib]->idx_file->clt_files[servercollatefunc-1]->GetOrigIndex(cltidx);
|
|
+}
|
|
+
|
|
+glong Libs::CltSynIndexToOrig(glong cltidx, size_t iLib, int servercollatefunc)
|
|
+{
|
|
+ if (EnableCollationLevel == 0)
|
|
+ return cltidx;
|
|
+ if (EnableCollationLevel == 1) {
|
|
+ if (cltidx == UNSET_INDEX || cltidx == INVALID_INDEX)
|
|
+ return cltidx;
|
|
+ return oLib[iLib]->syn_file->clt_file->GetOrigIndex(cltidx);
|
|
+ }
|
|
+ if (servercollatefunc == 0)
|
|
+ return cltidx;
|
|
+ if (cltidx == UNSET_INDEX || cltidx == INVALID_INDEX)
|
|
+ return cltidx;
|
|
+ oLib[iLib]->syn_file->collate_load((CollateFunctions)(servercollatefunc-1));
|
|
+ return oLib[iLib]->syn_file->clt_files[servercollatefunc-1]->GetOrigIndex(cltidx);
|
|
+}
|
|
+
|
|
+const gchar *Libs::GetSuggestWord(const gchar *sWord, CurrentIndex *iCurrent, std::vector<InstantDictIndex> &dictmask, int servercollatefunc)
|
|
+{
|
|
+ const gchar *poCurrentWord = NULL;
|
|
+ const gchar *word;
|
|
+ gint best =0;
|
|
+ gint back;
|
|
+ std::vector<InstantDictIndex>::size_type iLib;
|
|
+ std::vector<Dict *>::size_type iRealLib;
|
|
+ for (iLib=0; iLib < dictmask.size(); iLib++) {
|
|
+ if (dictmask[iLib].type != InstantDictType_LOCAL)
|
|
+ continue;
|
|
+ iRealLib = dictmask[iLib].index;
|
|
+ if ( poCurrentWord == NULL ) {
|
|
+ poCurrentWord = poGetWord(iCurrent[iLib].idx_suggest, iRealLib, servercollatefunc);
|
|
+ best = prefix_match (sWord, poCurrentWord);
|
|
+ } else {
|
|
+ word = poGetWord(iCurrent[iLib].idx_suggest, iRealLib, servercollatefunc);
|
|
+ back = prefix_match (sWord, word);
|
|
+ if (back > best) {
|
|
+ best = back;
|
|
+ poCurrentWord = word;
|
|
+ } else if (back == best) {
|
|
+ gint x = stardict_server_collate(poCurrentWord, word, EnableCollationLevel, CollateFunction, servercollatefunc);
|
|
+ if (x > 0) {
|
|
+ poCurrentWord = word;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ for (iLib=0; iLib<dictmask.size(); iLib++) {
|
|
+ if (dictmask[iLib].type != InstantDictType_LOCAL)
|
|
+ continue;
|
|
+ if (iCurrent[iLib].synidx_suggest==UNSET_INDEX)
|
|
+ continue;
|
|
+ iRealLib = dictmask[iLib].index;
|
|
+ if ( poCurrentWord == NULL ) {
|
|
+ poCurrentWord = poGetSynonymWord(iCurrent[iLib].synidx_suggest, iRealLib, servercollatefunc);
|
|
+ best = prefix_match (sWord, poCurrentWord);
|
|
+ } else {
|
|
+ word = poGetSynonymWord(iCurrent[iLib].synidx_suggest, iRealLib, servercollatefunc);
|
|
+ back = prefix_match (sWord, word);
|
|
+ if (back > best) {
|
|
+ best = back;
|
|
+ poCurrentWord = word;
|
|
+ } else if (back == best) {
|
|
+ gint x = stardict_server_collate(poCurrentWord, word, EnableCollationLevel, CollateFunction, servercollatefunc);
|
|
+ if (x > 0) {
|
|
+ poCurrentWord = word;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return poCurrentWord;
|
|
+}
|
|
+
|
|
+const gchar *Libs::poGetCurrentWord(CurrentIndex * iCurrent, std::vector<InstantDictIndex> &dictmask, int servercollatefunc)
|
|
+{
|
|
+ const gchar *poCurrentWord = NULL;
|
|
+ const gchar *word;
|
|
+ std::vector<InstantDictIndex>::size_type iLib;
|
|
+ std::vector<Dict *>::size_type iRealLib;
|
|
+ for (iLib=0; iLib < dictmask.size(); iLib++) {
|
|
+ if (dictmask[iLib].type != InstantDictType_LOCAL)
|
|
+ continue;
|
|
+ iRealLib = dictmask[iLib].index;
|
|
+ if (iCurrent[iLib].idx==INVALID_INDEX)
|
|
+ continue;
|
|
+ if ( iCurrent[iLib].idx>=narticles(iRealLib) || iCurrent[iLib].idx<0)
|
|
+ continue;
|
|
+ if ( poCurrentWord == NULL ) {
|
|
+ poCurrentWord = poGetWord(iCurrent[iLib].idx, iRealLib, servercollatefunc);
|
|
+ } else {
|
|
+ word = poGetWord(iCurrent[iLib].idx, iRealLib, servercollatefunc);
|
|
+ gint x = stardict_server_collate(poCurrentWord, word, EnableCollationLevel, CollateFunction, servercollatefunc);
|
|
+ if (x > 0) {
|
|
+ poCurrentWord = word;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ for (iLib=0; iLib<dictmask.size(); iLib++) {
|
|
+ if (dictmask[iLib].type != InstantDictType_LOCAL)
|
|
+ continue;
|
|
+ iRealLib = dictmask[iLib].index;
|
|
+ if (iCurrent[iLib].synidx==UNSET_INDEX)
|
|
+ continue;
|
|
+ if (iCurrent[iLib].synidx==INVALID_INDEX)
|
|
+ continue;
|
|
+ if ( iCurrent[iLib].synidx>=nsynarticles(iRealLib) || iCurrent[iLib].synidx<0)
|
|
+ continue;
|
|
+ if ( poCurrentWord == NULL ) {
|
|
+ poCurrentWord = poGetSynonymWord(iCurrent[iLib].synidx, iRealLib, servercollatefunc);
|
|
+ } else {
|
|
+ word = poGetSynonymWord(iCurrent[iLib].synidx, iRealLib, servercollatefunc);
|
|
+ gint x = stardict_server_collate(poCurrentWord, word, EnableCollationLevel, CollateFunction, servercollatefunc);
|
|
+ if (x > 0) {
|
|
+ poCurrentWord = word;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return poCurrentWord;
|
|
+}
|
|
+
|
|
+const gchar *
|
|
+Libs::poGetNextWord(const gchar *sWord, CurrentIndex *iCurrent, std::vector<InstantDictIndex> &dictmask, int servercollatefunc)
|
|
+{
|
|
+ // the input can be:
|
|
+ // (word,iCurrent),read word,write iNext to iCurrent,and return next word. used by TopWin::NextCallback();
|
|
+ // (NULL,iCurrent),read iCurrent,write iNext to iCurrent,and return next word. used by AppCore::ListWords();
|
|
+ const gchar *poCurrentWord = NULL;
|
|
+ std::vector<Dict *>::size_type iCurrentLib=0, iCurrentRealLib=0;
|
|
+ bool isLib = false;
|
|
+ const gchar *word;
|
|
+
|
|
+ std::vector<InstantDictIndex>::size_type iLib;
|
|
+ std::vector<Dict *>::size_type iRealLib;
|
|
+ for (iLib=0; iLib < dictmask.size(); iLib++) {
|
|
+ if (dictmask[iLib].type != InstantDictType_LOCAL)
|
|
+ continue;
|
|
+ iRealLib = dictmask[iLib].index;
|
|
+ if (sWord) {
|
|
+ oLib[iRealLib]->Lookup(sWord, iCurrent[iLib].idx, iCurrent[iLib].idx_suggest, EnableCollationLevel, servercollatefunc);
|
|
+ }
|
|
+ if (iCurrent[iLib].idx==INVALID_INDEX)
|
|
+ continue;
|
|
+ if (iCurrent[iLib].idx>=narticles(iRealLib) || iCurrent[iLib].idx<0)
|
|
+ continue;
|
|
+ if (poCurrentWord == NULL ) {
|
|
+ poCurrentWord = poGetWord(iCurrent[iLib].idx, iRealLib, servercollatefunc);
|
|
+ iCurrentLib = iLib;
|
|
+ iCurrentRealLib = iRealLib;
|
|
+ isLib=true;
|
|
+ } else {
|
|
+ gint x;
|
|
+ word = poGetWord(iCurrent[iLib].idx, iRealLib, servercollatefunc);
|
|
+ x = stardict_server_collate(poCurrentWord, word, EnableCollationLevel, CollateFunction, servercollatefunc);
|
|
+ if (x > 0) {
|
|
+ poCurrentWord = word;
|
|
+ iCurrentLib = iLib;
|
|
+ iCurrentRealLib = iRealLib;
|
|
+ isLib=true;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ for (iLib=0; iLib < dictmask.size(); iLib++) {
|
|
+ if (dictmask[iLib].type != InstantDictType_LOCAL)
|
|
+ continue;
|
|
+ iRealLib = dictmask[iLib].index;
|
|
+ if (sWord) {
|
|
+ oLib[iRealLib]->LookupSynonym(sWord, iCurrent[iLib].synidx, iCurrent[iLib].synidx_suggest, EnableCollationLevel, servercollatefunc);
|
|
+ }
|
|
+ if (iCurrent[iLib].synidx==UNSET_INDEX)
|
|
+ continue;
|
|
+ if (iCurrent[iLib].synidx==INVALID_INDEX)
|
|
+ continue;
|
|
+ if (iCurrent[iLib].synidx>=nsynarticles(iRealLib) || iCurrent[iLib].synidx<0)
|
|
+ continue;
|
|
+ if (poCurrentWord == NULL ) {
|
|
+ poCurrentWord = poGetSynonymWord(iCurrent[iLib].synidx, iRealLib, servercollatefunc);
|
|
+ iCurrentLib = iLib;
|
|
+ iCurrentRealLib = iRealLib;
|
|
+ isLib=false;
|
|
+ } else {
|
|
+ gint x;
|
|
+ word = poGetSynonymWord(iCurrent[iLib].synidx, iRealLib, servercollatefunc);
|
|
+ x = stardict_server_collate(poCurrentWord, word, EnableCollationLevel, CollateFunction, servercollatefunc);
|
|
+ if (x > 0 ) {
|
|
+ poCurrentWord = word;
|
|
+ iCurrentLib = iLib;
|
|
+ iCurrentRealLib = iRealLib;
|
|
+ isLib=false;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ if (poCurrentWord) {
|
|
+ for (iLib=0; iLib < dictmask.size(); iLib++) {
|
|
+ if (dictmask[iLib].type != InstantDictType_LOCAL)
|
|
+ continue;
|
|
+ iRealLib = dictmask[iLib].index;
|
|
+ if (isLib && (iLib == iCurrentLib))
|
|
+ continue;
|
|
+ if (iCurrent[iLib].idx==INVALID_INDEX)
|
|
+ continue;
|
|
+ if (iCurrent[iLib].idx>=narticles(iRealLib) || iCurrent[iLib].idx<0)
|
|
+ continue;
|
|
+ word = poGetWord(iCurrent[iLib].idx, iRealLib, servercollatefunc);
|
|
+ if (strcmp(poCurrentWord, word) == 0) {
|
|
+ GetWordNext(iCurrent[iLib].idx, iRealLib, true, servercollatefunc);
|
|
+ }
|
|
+ }
|
|
+ for (iLib=0; iLib < dictmask.size(); iLib++) {
|
|
+ if (dictmask[iLib].type != InstantDictType_LOCAL)
|
|
+ continue;
|
|
+ iRealLib = dictmask[iLib].index;
|
|
+ if ((!isLib) && (iLib == iCurrentLib))
|
|
+ continue;
|
|
+ if (iCurrent[iLib].synidx==UNSET_INDEX)
|
|
+ continue;
|
|
+ if (iCurrent[iLib].synidx==INVALID_INDEX)
|
|
+ continue;
|
|
+ if (iCurrent[iLib].synidx>=nsynarticles(iRealLib) || iCurrent[iLib].synidx<0)
|
|
+ continue;
|
|
+ word = poGetSynonymWord(iCurrent[iLib].synidx, iRealLib, servercollatefunc);
|
|
+ if (strcmp(poCurrentWord, word) == 0) {
|
|
+ GetWordNext(iCurrent[iLib].synidx, iRealLib, false, servercollatefunc);
|
|
+ }
|
|
+ }
|
|
+ //GetWordNext will change poCurrentWord's content, so do it at the last.
|
|
+ if (isLib) {
|
|
+ GetWordNext(iCurrent[iCurrentLib].idx, iCurrentRealLib, true, servercollatefunc);
|
|
+ } else {
|
|
+ GetWordNext(iCurrent[iCurrentLib].synidx, iCurrentRealLib, false, servercollatefunc);
|
|
+ }
|
|
+ poCurrentWord = poGetCurrentWord(iCurrent, dictmask, servercollatefunc);
|
|
+ }
|
|
+ return poCurrentWord;
|
|
+}
|
|
+
|
|
+const gchar *
|
|
+Libs::poGetPreWord(const gchar *sWord, CurrentIndex* iCurrent, std::vector<InstantDictIndex> &dictmask, int servercollatefunc)
|
|
+{
|
|
+ // used by TopWin::PreviousCallback(); the iCurrent is cached by AppCore::TopWinWordChange();
|
|
+ const gchar *poCurrentWord = NULL;
|
|
+ std::vector<Dict *>::size_type iCurrentLib=0, iCurrentRealLib=0;
|
|
+ bool isLib = false;
|
|
+
|
|
+ const gchar *word;
|
|
+ glong pidx;
|
|
+ std::vector<InstantDictIndex>::size_type iLib;
|
|
+ std::vector<Dict *>::size_type iRealLib;
|
|
+ for (iLib=0;iLib<dictmask.size();iLib++) {
|
|
+ if (dictmask[iLib].type != InstantDictType_LOCAL)
|
|
+ continue;
|
|
+ iRealLib = dictmask[iLib].index;
|
|
+ if (sWord) {
|
|
+ oLib[iRealLib]->Lookup(sWord, iCurrent[iLib].idx, iCurrent[iLib].idx_suggest, EnableCollationLevel, servercollatefunc);
|
|
+ }
|
|
+ if (iCurrent[iLib].idx!=INVALID_INDEX) {
|
|
+ if ( iCurrent[iLib].idx>=narticles(iRealLib) || iCurrent[iLib].idx<=0)
|
|
+ continue;
|
|
+ }
|
|
+ if ( poCurrentWord == NULL ) {
|
|
+ if (GetWordPrev(iCurrent[iLib].idx, pidx, iRealLib, true, servercollatefunc)) {
|
|
+ poCurrentWord = poGetWord(pidx, iRealLib, servercollatefunc);
|
|
+ iCurrentLib = iLib;
|
|
+ iCurrentRealLib = iRealLib;
|
|
+ isLib=true;
|
|
+ }
|
|
+ } else {
|
|
+ if (GetWordPrev(iCurrent[iLib].idx, pidx, iRealLib, true, servercollatefunc)) {
|
|
+ gint x;
|
|
+ word = poGetWord(pidx, iRealLib, servercollatefunc);
|
|
+ x = stardict_server_collate(poCurrentWord, word, EnableCollationLevel, CollateFunction, servercollatefunc);
|
|
+ if (x < 0 ) {
|
|
+ poCurrentWord = word;
|
|
+ iCurrentLib = iLib;
|
|
+ iCurrentRealLib = iRealLib;
|
|
+ isLib=true;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ for (iLib=0;iLib<dictmask.size();iLib++) {
|
|
+ if (dictmask[iLib].type != InstantDictType_LOCAL)
|
|
+ continue;
|
|
+ iRealLib = dictmask[iLib].index;
|
|
+ if (sWord) {
|
|
+ oLib[iRealLib]->LookupSynonym(sWord, iCurrent[iLib].synidx, iCurrent[iLib].synidx_suggest, EnableCollationLevel, servercollatefunc);
|
|
+ }
|
|
+ if (iCurrent[iLib].synidx==UNSET_INDEX)
|
|
+ continue;
|
|
+ if (iCurrent[iLib].synidx!=INVALID_INDEX) {
|
|
+ if ( iCurrent[iLib].synidx>=nsynarticles(iRealLib) || iCurrent[iLib].synidx<=0)
|
|
+ continue;
|
|
+ }
|
|
+ if ( poCurrentWord == NULL ) {
|
|
+ if (GetWordPrev(iCurrent[iLib].synidx, pidx, iRealLib, false, servercollatefunc)) {
|
|
+ poCurrentWord = poGetSynonymWord(pidx, iRealLib, servercollatefunc);
|
|
+ iCurrentLib = iLib;
|
|
+ iCurrentRealLib = iRealLib;
|
|
+ isLib=false;
|
|
+ }
|
|
+ } else {
|
|
+ if (GetWordPrev(iCurrent[iLib].synidx, pidx, iRealLib, false, servercollatefunc)) {
|
|
+ gint x;
|
|
+ word = poGetSynonymWord(pidx,iRealLib, servercollatefunc);
|
|
+ x = stardict_server_collate(poCurrentWord, word, EnableCollationLevel, CollateFunction, servercollatefunc);
|
|
+ if (x < 0 ) {
|
|
+ poCurrentWord = word;
|
|
+ iCurrentLib = iLib;
|
|
+ iCurrentRealLib = iRealLib;
|
|
+ isLib=false;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ if (poCurrentWord) {
|
|
+ for (iLib=0;iLib<dictmask.size();iLib++) {
|
|
+ if (dictmask[iLib].type != InstantDictType_LOCAL)
|
|
+ continue;
|
|
+ iRealLib = dictmask[iLib].index;
|
|
+ if (isLib && (iLib == iCurrentLib))
|
|
+ continue;
|
|
+ if (iCurrent[iLib].idx!=INVALID_INDEX) {
|
|
+ if (iCurrent[iLib].idx>=narticles(iRealLib) || iCurrent[iLib].idx<=0)
|
|
+ continue;
|
|
+ }
|
|
+ if (GetWordPrev(iCurrent[iLib].idx, pidx, iRealLib, true, servercollatefunc)) {
|
|
+ word = poGetWord(pidx, iRealLib, servercollatefunc);
|
|
+ if (strcmp(poCurrentWord, word) == 0) {
|
|
+ iCurrent[iLib].idx=pidx;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ for (iLib=0;iLib<dictmask.size();iLib++) {
|
|
+ if (dictmask[iLib].type != InstantDictType_LOCAL)
|
|
+ continue;
|
|
+ iRealLib = dictmask[iLib].index;
|
|
+ if ((!isLib) && (iLib == iCurrentLib))
|
|
+ continue;
|
|
+ if (iCurrent[iLib].synidx==UNSET_INDEX)
|
|
+ continue;
|
|
+ if (iCurrent[iLib].synidx!=INVALID_INDEX) {
|
|
+ if (iCurrent[iLib].synidx>=nsynarticles(iRealLib) || iCurrent[iLib].synidx<=0)
|
|
+ continue;
|
|
+ }
|
|
+ if (GetWordPrev(iCurrent[iLib].synidx, pidx, iRealLib, false, servercollatefunc)) {
|
|
+ word = poGetSynonymWord(pidx, iRealLib, servercollatefunc);
|
|
+ if (strcmp(poCurrentWord, word) == 0) {
|
|
+ iCurrent[iLib].synidx=pidx;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ if (isLib) {
|
|
+ GetWordPrev(iCurrent[iCurrentLib].idx, pidx, iCurrentRealLib, true, servercollatefunc);
|
|
+ iCurrent[iCurrentLib].idx = pidx;
|
|
+ } else {
|
|
+ GetWordPrev(iCurrent[iCurrentLib].synidx, pidx, iCurrentRealLib, false, servercollatefunc);
|
|
+ iCurrent[iCurrentLib].synidx = pidx;
|
|
+ }
|
|
+ }
|
|
+ return poCurrentWord;
|
|
+}
|
|
+
|
|
+bool Libs::LookupSynonymSimilarWord(const gchar* sWord, glong &iSynonymWordIndex, glong &synidx_suggest, size_t iLib, int servercollatefunc)
|
|
+{
|
|
+ if (oLib[iLib]->syn_file.get() == NULL)
|
|
+ return false;
|
|
+
|
|
+ glong iIndex;
|
|
+ glong iIndex_suggest;
|
|
+ bool bFound=false;
|
|
+ gchar *casestr;
|
|
+ bool bLookup;
|
|
+
|
|
+ if (!bFound) {
|
|
+ // to lower case.
|
|
+ casestr = g_utf8_strdown(sWord, -1);
|
|
+ if (strcmp(casestr, sWord)) {
|
|
+ bLookup = oLib[iLib]->LookupSynonym(casestr, iIndex, iIndex_suggest, EnableCollationLevel, servercollatefunc);
|
|
+ if(bLookup)
|
|
+ bFound=true;
|
|
+ }
|
|
+ g_free(casestr);
|
|
+ // to upper case.
|
|
+ if (!bFound) {
|
|
+ casestr = g_utf8_strup(sWord, -1);
|
|
+ if (strcmp(casestr, sWord)) {
|
|
+ bLookup = oLib[iLib]->LookupSynonym(casestr, iIndex, iIndex_suggest, EnableCollationLevel, servercollatefunc);
|
|
+ if(bLookup)
|
|
+ bFound=true;
|
|
+ }
|
|
+ g_free(casestr);
|
|
+ }
|
|
+ // Upper the first character and lower others.
|
|
+ if (!bFound) {
|
|
+ gchar *nextchar = g_utf8_next_char(sWord);
|
|
+ gchar *firstchar = g_utf8_strup(sWord, nextchar - sWord);
|
|
+ nextchar = g_utf8_strdown(nextchar, -1);
|
|
+ casestr = g_strdup_printf("%s%s", firstchar, nextchar);
|
|
+ g_free(firstchar);
|
|
+ g_free(nextchar);
|
|
+ if (strcmp(casestr, sWord)) {
|
|
+ bLookup = oLib[iLib]->LookupSynonym(casestr, iIndex, iIndex_suggest, EnableCollationLevel, servercollatefunc);
|
|
+ if(bLookup)
|
|
+ bFound=true;
|
|
+ }
|
|
+ g_free(casestr);
|
|
+ }
|
|
+ if (!bFound) {
|
|
+ iIndex = iSynonymWordIndex;
|
|
+ glong pidx;
|
|
+ const gchar *cword;
|
|
+ do {
|
|
+ if (GetWordPrev(iIndex, pidx, iLib, false, servercollatefunc)) {
|
|
+ cword = poGetSynonymWord(pidx, iLib, servercollatefunc);
|
|
+ if (stardict_casecmp(cword, sWord, EnableCollationLevel, CollateFunction, servercollatefunc)==0) {
|
|
+ iIndex = pidx;
|
|
+ bFound=true;
|
|
+ } else {
|
|
+ break;
|
|
+ }
|
|
+ } else {
|
|
+ break;
|
|
+ }
|
|
+ } while (true);
|
|
+ if (!bFound) {
|
|
+ if (iIndex!=INVALID_INDEX) {
|
|
+ cword = poGetSynonymWord(iIndex, iLib, servercollatefunc);
|
|
+ if (stardict_casecmp(cword, sWord, EnableCollationLevel, CollateFunction, servercollatefunc)==0) {
|
|
+ bFound=true;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ if (bFound) {
|
|
+ iSynonymWordIndex = iIndex;
|
|
+ synidx_suggest = iIndex_suggest;
|
|
+ }
|
|
+ return bFound;
|
|
+}
|
|
+
|
|
+bool Libs::LookupSimilarWord(const gchar* sWord, glong & iWordIndex, glong &idx_suggest, size_t iLib, int servercollatefunc)
|
|
+{
|
|
+ glong iIndex;
|
|
+ bool bFound=false;
|
|
+ gchar *casestr;
|
|
+
|
|
+ if (!bFound) {
|
|
+ // to lower case.
|
|
+ casestr = g_utf8_strdown(sWord, -1);
|
|
+ if (strcmp(casestr, sWord)) {
|
|
+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ }
|
|
+ g_free(casestr);
|
|
+ // to upper case.
|
|
+ if (!bFound) {
|
|
+ casestr = g_utf8_strup(sWord, -1);
|
|
+ if (strcmp(casestr, sWord)) {
|
|
+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ }
|
|
+ g_free(casestr);
|
|
+ }
|
|
+ // Upper the first character and lower others.
|
|
+ if (!bFound) {
|
|
+ gchar *nextchar = g_utf8_next_char(sWord);
|
|
+ gchar *firstchar = g_utf8_strup(sWord, nextchar - sWord);
|
|
+ nextchar = g_utf8_strdown(nextchar, -1);
|
|
+ casestr = g_strdup_printf("%s%s", firstchar, nextchar);
|
|
+ g_free(firstchar);
|
|
+ g_free(nextchar);
|
|
+ if (strcmp(casestr, sWord)) {
|
|
+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ }
|
|
+ g_free(casestr);
|
|
+ }
|
|
+ if (!bFound) {
|
|
+ iIndex = iWordIndex;
|
|
+ glong pidx;
|
|
+ const gchar *cword;
|
|
+ do {
|
|
+ if (GetWordPrev(iIndex, pidx, iLib, true, servercollatefunc)) {
|
|
+ cword = poGetWord(pidx, iLib, servercollatefunc);
|
|
+ if (stardict_casecmp(cword, sWord, EnableCollationLevel, CollateFunction, servercollatefunc)==0) {
|
|
+ iIndex = pidx;
|
|
+ bFound=true;
|
|
+ } else {
|
|
+ break;
|
|
+ }
|
|
+ } else {
|
|
+ break;
|
|
+ }
|
|
+ } while (true);
|
|
+ if (!bFound) {
|
|
+ if (iIndex!=INVALID_INDEX) {
|
|
+ cword = poGetWord(iIndex, iLib, servercollatefunc);
|
|
+ if (stardict_casecmp(cword, sWord, EnableCollationLevel, CollateFunction, servercollatefunc)==0) {
|
|
+ bFound=true;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (bIsPureEnglish(sWord)) {
|
|
+ // If not Found , try other status of sWord.
|
|
+ size_t iWordLen=strlen(sWord);
|
|
+ bool isupcase;
|
|
+
|
|
+ gchar *sNewWord = (gchar *)g_malloc(iWordLen + 1);
|
|
+
|
|
+ //cut one char "s" or "d"
|
|
+ if(!bFound && iWordLen>1) {
|
|
+ isupcase = sWord[iWordLen-1]=='S' || !strncmp(&sWord[iWordLen-2],"ED",2);
|
|
+ if (isupcase || sWord[iWordLen-1]=='s' || !strncmp(&sWord[iWordLen-2],"ed",2)) {
|
|
+ strcpy(sNewWord,sWord);
|
|
+ sNewWord[iWordLen-1]='\0'; // cut "s" or "d"
|
|
+ if (oLib[iLib]->Lookup(sNewWord, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ else if (isupcase || g_ascii_isupper(sWord[0])) {
|
|
+ casestr = g_ascii_strdown(sNewWord, -1);
|
|
+ if (strcmp(casestr, sNewWord)) {
|
|
+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ }
|
|
+ g_free(casestr);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ //cut "ly"
|
|
+ if(!bFound && iWordLen>2) {
|
|
+ isupcase = !strncmp(&sWord[iWordLen-2],"LY",2);
|
|
+ if (isupcase || (!strncmp(&sWord[iWordLen-2],"ly",2))) {
|
|
+ strcpy(sNewWord,sWord);
|
|
+ sNewWord[iWordLen-2]='\0'; // cut "ly"
|
|
+ if (iWordLen>5 && sNewWord[iWordLen-3]==sNewWord[iWordLen-4]
|
|
+ && !bIsVowel(sNewWord[iWordLen-4]) &&
|
|
+ bIsVowel(sNewWord[iWordLen-5])) {//doubled
|
|
+
|
|
+ sNewWord[iWordLen-3]='\0';
|
|
+ if(oLib[iLib]->Lookup(sNewWord, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ else {
|
|
+ if (isupcase || g_ascii_isupper(sWord[0])) {
|
|
+ casestr = g_ascii_strdown(sNewWord, -1);
|
|
+ if (strcmp(casestr, sNewWord)) {
|
|
+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ }
|
|
+ g_free(casestr);
|
|
+ }
|
|
+ if (!bFound)
|
|
+ sNewWord[iWordLen-3]=sNewWord[iWordLen-4]; //restore
|
|
+ }
|
|
+ }
|
|
+ if (!bFound) {
|
|
+ if (oLib[iLib]->Lookup(sNewWord, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ else if (isupcase || g_ascii_isupper(sWord[0])) {
|
|
+ casestr = g_ascii_strdown(sNewWord, -1);
|
|
+ if (strcmp(casestr, sNewWord)) {
|
|
+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ }
|
|
+ g_free(casestr);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ //cut "ing"
|
|
+ if(!bFound && iWordLen>3) {
|
|
+ isupcase = !strncmp(&sWord[iWordLen-3],"ING",3);
|
|
+ if (isupcase || !strncmp(&sWord[iWordLen-3],"ing",3) ) {
|
|
+ strcpy(sNewWord,sWord);
|
|
+ sNewWord[iWordLen-3]='\0';
|
|
+ if ( iWordLen>6 && (sNewWord[iWordLen-4]==sNewWord[iWordLen-5])
|
|
+ && !bIsVowel(sNewWord[iWordLen-5]) &&
|
|
+ bIsVowel(sNewWord[iWordLen-6])) { //doubled
|
|
+ sNewWord[iWordLen-4]='\0';
|
|
+ if (oLib[iLib]->Lookup(sNewWord, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ else {
|
|
+ if (isupcase || g_ascii_isupper(sWord[0])) {
|
|
+ casestr = g_ascii_strdown(sNewWord, -1);
|
|
+ if (strcmp(casestr, sNewWord)) {
|
|
+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ }
|
|
+ g_free(casestr);
|
|
+ }
|
|
+ if (!bFound)
|
|
+ sNewWord[iWordLen-4]=sNewWord[iWordLen-5]; //restore
|
|
+ }
|
|
+ }
|
|
+ if( !bFound ) {
|
|
+ if (oLib[iLib]->Lookup(sNewWord, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ else if (isupcase || g_ascii_isupper(sWord[0])) {
|
|
+ casestr = g_ascii_strdown(sNewWord, -1);
|
|
+ if (strcmp(casestr, sNewWord)) {
|
|
+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ }
|
|
+ g_free(casestr);
|
|
+ }
|
|
+ }
|
|
+ if(!bFound) {
|
|
+ if (isupcase)
|
|
+ strcat(sNewWord,"E"); // add a char "E"
|
|
+ else
|
|
+ strcat(sNewWord,"e"); // add a char "e"
|
|
+ if(oLib[iLib]->Lookup(sNewWord, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ else if (isupcase || g_ascii_isupper(sWord[0])) {
|
|
+ casestr = g_ascii_strdown(sNewWord, -1);
|
|
+ if (strcmp(casestr, sNewWord)) {
|
|
+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ }
|
|
+ g_free(casestr);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ //cut two char "es"
|
|
+ if(!bFound && iWordLen>3) {
|
|
+ isupcase = (!strncmp(&sWord[iWordLen-2],"ES",2) &&
|
|
+ (sWord[iWordLen-3] == 'S' ||
|
|
+ sWord[iWordLen-3] == 'X' ||
|
|
+ sWord[iWordLen-3] == 'O' ||
|
|
+ (iWordLen >4 && sWord[iWordLen-3] == 'H' &&
|
|
+ (sWord[iWordLen-4] == 'C' ||
|
|
+ sWord[iWordLen-4] == 'S'))));
|
|
+ if (isupcase ||
|
|
+ (!strncmp(&sWord[iWordLen-2],"es",2) &&
|
|
+ (sWord[iWordLen-3] == 's' || sWord[iWordLen-3] == 'x' ||
|
|
+ sWord[iWordLen-3] == 'o' ||
|
|
+ (iWordLen >4 && sWord[iWordLen-3] == 'h' &&
|
|
+ (sWord[iWordLen-4] == 'c' || sWord[iWordLen-4] == 's'))))) {
|
|
+ strcpy(sNewWord,sWord);
|
|
+ sNewWord[iWordLen-2]='\0';
|
|
+ if(oLib[iLib]->Lookup(sNewWord, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ else if (isupcase || g_ascii_isupper(sWord[0])) {
|
|
+ casestr = g_ascii_strdown(sNewWord, -1);
|
|
+ if (strcmp(casestr, sNewWord)) {
|
|
+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ }
|
|
+ g_free(casestr);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ //cut "ed"
|
|
+ if (!bFound && iWordLen>3) {
|
|
+ isupcase = !strncmp(&sWord[iWordLen-2],"ED",2);
|
|
+ if (isupcase || !strncmp(&sWord[iWordLen-2],"ed",2)) {
|
|
+ strcpy(sNewWord,sWord);
|
|
+ sNewWord[iWordLen-2]='\0';
|
|
+ if (iWordLen>5 && (sNewWord[iWordLen-3]==sNewWord[iWordLen-4])
|
|
+ && !bIsVowel(sNewWord[iWordLen-4]) &&
|
|
+ bIsVowel(sNewWord[iWordLen-5])) {//doubled
|
|
+ sNewWord[iWordLen-3]='\0';
|
|
+ if (oLib[iLib]->Lookup(sNewWord, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ else {
|
|
+ if (isupcase || g_ascii_isupper(sWord[0])) {
|
|
+ casestr = g_ascii_strdown(sNewWord, -1);
|
|
+ if (strcmp(casestr, sNewWord)) {
|
|
+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ }
|
|
+ g_free(casestr);
|
|
+ }
|
|
+ if (!bFound)
|
|
+ sNewWord[iWordLen-3]=sNewWord[iWordLen-4]; //restore
|
|
+ }
|
|
+ }
|
|
+ if (!bFound) {
|
|
+ if (oLib[iLib]->Lookup(sNewWord, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ else if (isupcase || g_ascii_isupper(sWord[0])) {
|
|
+ casestr = g_ascii_strdown(sNewWord, -1);
|
|
+ if (strcmp(casestr, sNewWord)) {
|
|
+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ }
|
|
+ g_free(casestr);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // cut "ied" , add "y".
|
|
+ if (!bFound && iWordLen>3) {
|
|
+ isupcase = !strncmp(&sWord[iWordLen-3],"IED",3);
|
|
+ if (isupcase || (!strncmp(&sWord[iWordLen-3],"ied",3))) {
|
|
+ strcpy(sNewWord,sWord);
|
|
+ sNewWord[iWordLen-3]='\0';
|
|
+ if (isupcase)
|
|
+ strcat(sNewWord,"Y"); // add a char "Y"
|
|
+ else
|
|
+ strcat(sNewWord,"y"); // add a char "y"
|
|
+ if (oLib[iLib]->Lookup(sNewWord, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ else if (isupcase || g_ascii_isupper(sWord[0])) {
|
|
+ casestr = g_ascii_strdown(sNewWord, -1);
|
|
+ if (strcmp(casestr, sNewWord)) {
|
|
+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ }
|
|
+ g_free(casestr);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // cut "ies" , add "y".
|
|
+ if (!bFound && iWordLen>3) {
|
|
+ isupcase = !strncmp(&sWord[iWordLen-3],"IES",3);
|
|
+ if (isupcase || (!strncmp(&sWord[iWordLen-3],"ies",3))) {
|
|
+ strcpy(sNewWord,sWord);
|
|
+ sNewWord[iWordLen-3]='\0';
|
|
+ if (isupcase)
|
|
+ strcat(sNewWord,"Y"); // add a char "Y"
|
|
+ else
|
|
+ strcat(sNewWord,"y"); // add a char "y"
|
|
+ if(oLib[iLib]->Lookup(sNewWord, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ else if (isupcase || g_ascii_isupper(sWord[0])) {
|
|
+ casestr = g_ascii_strdown(sNewWord, -1);
|
|
+ if (strcmp(casestr, sNewWord)) {
|
|
+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ }
|
|
+ g_free(casestr);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // cut "er".
|
|
+ if (!bFound && iWordLen>2) {
|
|
+ isupcase = !strncmp(&sWord[iWordLen-2],"ER",2);
|
|
+ if (isupcase || (!strncmp(&sWord[iWordLen-2],"er",2))) {
|
|
+ strcpy(sNewWord,sWord);
|
|
+ sNewWord[iWordLen-2]='\0';
|
|
+ if(oLib[iLib]->Lookup(sNewWord, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ else if (isupcase || g_ascii_isupper(sWord[0])) {
|
|
+ casestr = g_ascii_strdown(sNewWord, -1);
|
|
+ if (strcmp(casestr, sNewWord)) {
|
|
+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ }
|
|
+ g_free(casestr);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // cut "est".
|
|
+ if (!bFound && iWordLen>3) {
|
|
+ isupcase = !strncmp(&sWord[iWordLen-3], "EST", 3);
|
|
+ if (isupcase || (!strncmp(&sWord[iWordLen-3],"est", 3))) {
|
|
+ strcpy(sNewWord,sWord);
|
|
+ sNewWord[iWordLen-3]='\0';
|
|
+ if(oLib[iLib]->Lookup(sNewWord, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ else if (isupcase || g_ascii_isupper(sWord[0])) {
|
|
+ casestr = g_ascii_strdown(sNewWord, -1);
|
|
+ if (strcmp(casestr, sNewWord)) {
|
|
+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc))
|
|
+ bFound=true;
|
|
+ }
|
|
+ g_free(casestr);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ g_free(sNewWord);
|
|
+ }
|
|
+
|
|
+ if (bFound)
|
|
+ iWordIndex = iIndex;
|
|
+#if 0
|
|
+ else {
|
|
+ //don't change iWordIndex here.
|
|
+ //when LookupSimilarWord all failed too, we want to use the old LookupWord index to list words.
|
|
+ //iWordIndex = INVALID_INDEX;
|
|
+ }
|
|
+#endif
|
|
+ return bFound;
|
|
+}
|
|
+
|
|
+bool Libs::SimpleLookupWord(const gchar* sWord, glong & iWordIndex, glong &idx_suggest, size_t iLib, int servercollatefunc)
|
|
+{
|
|
+ bool bFound = oLib[iLib]->Lookup(sWord, iWordIndex, idx_suggest, EnableCollationLevel, servercollatefunc);
|
|
+ if (!bFound)
|
|
+ bFound = LookupSimilarWord(sWord, iWordIndex, idx_suggest, iLib, servercollatefunc);
|
|
+ return bFound;
|
|
+}
|
|
+
|
|
+bool Libs::SimpleLookupSynonymWord(const gchar* sWord, glong & iWordIndex, glong &synidx_suggest, size_t iLib, int servercollatefunc)
|
|
+{
|
|
+ bool bFound = oLib[iLib]->LookupSynonym(sWord, iWordIndex, synidx_suggest, EnableCollationLevel, servercollatefunc);
|
|
+ if (!bFound)
|
|
+ bFound = LookupSynonymSimilarWord(sWord, iWordIndex, synidx_suggest, iLib, servercollatefunc);
|
|
+ return bFound;
|
|
+}
|
|
+
|
|
+struct Fuzzystruct {
|
|
+ char * pMatchWord;
|
|
+ int iMatchWordDistance;
|
|
+};
|
|
+
|
|
+static inline bool operator<(const Fuzzystruct & lh, const Fuzzystruct & rh) {
|
|
+ if (lh.iMatchWordDistance!=rh.iMatchWordDistance)
|
|
+ return lh.iMatchWordDistance<rh.iMatchWordDistance;
|
|
+
|
|
+ if (lh.pMatchWord && rh.pMatchWord)
|
|
+ return stardict_strcmp(lh.pMatchWord, rh.pMatchWord)<0;
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
+static inline void unicode_strdown(gunichar *str)
|
|
+{
|
|
+ while (*str) {
|
|
+ *str=g_unichar_tolower(*str);
|
|
+ ++str;
|
|
+ }
|
|
+}
|
|
+
|
|
+bool Libs::LookupWithFuzzy(const gchar *sWord, gchar *reslist[], gint reslist_size, std::vector<InstantDictIndex> &dictmask)
|
|
+{
|
|
+ if (sWord[0] == '\0')
|
|
+ return false;
|
|
+
|
|
+ std::vector<Fuzzystruct> oFuzzystruct(reslist_size);
|
|
+
|
|
+ for (int i=0; i<reslist_size; i++) {
|
|
+ oFuzzystruct[i].pMatchWord = NULL;
|
|
+ oFuzzystruct[i].iMatchWordDistance = iMaxFuzzyDistance;
|
|
+ }
|
|
+ int iMaxDistance = iMaxFuzzyDistance;
|
|
+ int iDistance;
|
|
+ bool Found = false;
|
|
+ EditDistance oEditDistance;
|
|
+
|
|
+ glong iCheckWordLen;
|
|
+ const char *sCheck;
|
|
+ gunichar *ucs4_str1, *ucs4_str2;
|
|
+ glong ucs4_str2_len;
|
|
+
|
|
+ ucs4_str2 = g_utf8_to_ucs4_fast(sWord, -1, &ucs4_str2_len);
|
|
+ unicode_strdown(ucs4_str2);
|
|
+
|
|
+ std::vector<Dict *>::size_type iRealLib;
|
|
+ for (std::vector<InstantDictIndex>::size_type iLib=0; iLib<dictmask.size(); iLib++) {
|
|
+ if (dictmask[iLib].type != InstantDictType_LOCAL)
|
|
+ continue;
|
|
+ iRealLib = dictmask[iLib].index;
|
|
+ for (gint synLib=0; synLib<2; synLib++) {
|
|
+ if (synLib==1) {
|
|
+ if (oLib[iRealLib]->syn_file.get()==NULL)
|
|
+ break;
|
|
+ }
|
|
+ show_progress->notify_about_work();
|
|
+
|
|
+ //if (stardict_strcmp(sWord, poGetWord(0,iRealLib))>=0 && stardict_strcmp(sWord, poGetWord(narticles(iRealLib)-1,iRealLib))<=0) {
|
|
+ //there are Chinese dicts and English dicts...
|
|
+ if (TRUE) {
|
|
+ glong iwords;
|
|
+ if (synLib==0)
|
|
+ iwords = narticles(iRealLib);
|
|
+ else
|
|
+ iwords = nsynarticles(iRealLib);
|
|
+ for (glong index=0; index<iwords; index++) {
|
|
+ // Need to deal with same word in index? But this will slow down processing in most case.
|
|
+ if (synLib==0)
|
|
+ sCheck = poGetOrigWord(index,iRealLib);
|
|
+ else
|
|
+ sCheck = poGetOrigSynonymWord(index,iRealLib);
|
|
+ // tolower and skip too long or too short words
|
|
+ iCheckWordLen = g_utf8_strlen(sCheck, -1);
|
|
+ if (iCheckWordLen-ucs4_str2_len>=iMaxDistance ||
|
|
+ ucs4_str2_len-iCheckWordLen>=iMaxDistance)
|
|
+ continue;
|
|
+ ucs4_str1 = g_utf8_to_ucs4_fast(sCheck, -1, NULL);
|
|
+ if (iCheckWordLen > ucs4_str2_len)
|
|
+ ucs4_str1[ucs4_str2_len]=0;
|
|
+ unicode_strdown(ucs4_str1);
|
|
+
|
|
+ iDistance = oEditDistance.CalEditDistance(ucs4_str1, ucs4_str2, iMaxDistance);
|
|
+ g_free(ucs4_str1);
|
|
+ if (iDistance<iMaxDistance && iDistance < ucs4_str2_len) {
|
|
+ // when ucs4_str2_len=1,2 we need less fuzzy.
|
|
+ Found = true;
|
|
+ bool bAlreadyInList = false;
|
|
+ int iMaxDistanceAt=0;
|
|
+ for (int j=0; j<reslist_size; j++) {
|
|
+ if (oFuzzystruct[j].pMatchWord &&
|
|
+ strcmp(oFuzzystruct[j].pMatchWord,sCheck)==0 ) {//already in list
|
|
+ bAlreadyInList = true;
|
|
+ break;
|
|
+ }
|
|
+ //find the position,it will certainly be found (include the first time) as iMaxDistance is set by last time.
|
|
+ if (oFuzzystruct[j].iMatchWordDistance == iMaxDistance ) {
|
|
+ iMaxDistanceAt = j;
|
|
+ }
|
|
+ }
|
|
+ if (!bAlreadyInList) {
|
|
+ if (oFuzzystruct[iMaxDistanceAt].pMatchWord)
|
|
+ g_free(oFuzzystruct[iMaxDistanceAt].pMatchWord);
|
|
+ oFuzzystruct[iMaxDistanceAt].pMatchWord = g_strdup(sCheck);
|
|
+ oFuzzystruct[iMaxDistanceAt].iMatchWordDistance = iDistance;
|
|
+ // calc new iMaxDistance
|
|
+ iMaxDistance = iDistance;
|
|
+ for (int j=0; j<reslist_size; j++) {
|
|
+ if (oFuzzystruct[j].iMatchWordDistance > iMaxDistance)
|
|
+ iMaxDistance = oFuzzystruct[j].iMatchWordDistance;
|
|
+ } // calc new iMaxDistance
|
|
+ } // add to list
|
|
+ } // find one
|
|
+ } // each word
|
|
+ } // ok for search
|
|
+ } // synLib
|
|
+ } // each lib
|
|
+ g_free(ucs4_str2);
|
|
+
|
|
+ if (Found)// sort with distance
|
|
+ std::sort(oFuzzystruct.begin(), oFuzzystruct.end());
|
|
+
|
|
+ for (gint i=0; i<reslist_size; ++i)
|
|
+ reslist[i]=oFuzzystruct[i].pMatchWord;
|
|
+
|
|
+ return Found;
|
|
+}
|
|
+
|
|
+static inline bool less_for_compare(const char *lh, const char *rh) {
|
|
+ return stardict_strcmp(lh, rh)<0;
|
|
+}
|
|
+
|
|
+gint Libs::LookupWithRule(const gchar *word, gchar **ppMatchWord, std::vector<InstantDictIndex> &dictmask)
|
|
+{
|
|
+ glong aiIndex[MAX_MATCH_ITEM_PER_LIB+1];
|
|
+ gint iMatchCount = 0;
|
|
+ GPatternSpec *pspec = g_pattern_spec_new(word);
|
|
+
|
|
+ const gchar * sMatchWord;
|
|
+ bool bAlreadyInList;
|
|
+ std::vector<Dict *>::size_type iRealLib;
|
|
+ for (std::vector<InstantDictIndex>::size_type iLib=0; iLib<dictmask.size(); iLib++) {
|
|
+ //if(oLibs.LookdupWordsWithRule(pspec,aiIndex,MAX_MATCH_ITEM_PER_LIB+1-iMatchCount,iLib))
|
|
+ // -iMatchCount,so save time,but may got less result and the word may repeat.
|
|
+ if (dictmask[iLib].type != InstantDictType_LOCAL)
|
|
+ continue;
|
|
+ iRealLib = dictmask[iLib].index;
|
|
+ if (oLib[iRealLib]->LookupWithRule(pspec, aiIndex, MAX_MATCH_ITEM_PER_LIB+1)) {
|
|
+ show_progress->notify_about_work();
|
|
+ for (int i=0; aiIndex[i]!=-1; i++) {
|
|
+ sMatchWord = poGetOrigWord(aiIndex[i],iRealLib);
|
|
+ bAlreadyInList = false;
|
|
+ for (int j=0; j<iMatchCount; j++) {
|
|
+ if (strcmp(ppMatchWord[j],sMatchWord)==0) {//already in list
|
|
+ bAlreadyInList = true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if (!bAlreadyInList)
|
|
+ ppMatchWord[iMatchCount++] = g_strdup(sMatchWord);
|
|
+ }
|
|
+ }
|
|
+ if (oLib[iRealLib]->LookupWithRuleSynonym(pspec, aiIndex, MAX_MATCH_ITEM_PER_LIB+1)) {
|
|
+ show_progress->notify_about_work();
|
|
+ for (int i=0; aiIndex[i]!=-1; i++) {
|
|
+ sMatchWord = poGetOrigSynonymWord(aiIndex[i],iRealLib);
|
|
+ bAlreadyInList = false;
|
|
+ for (int j=0; j<iMatchCount; j++) {
|
|
+ if (strcmp(ppMatchWord[j],sMatchWord)==0) {//already in list
|
|
+ bAlreadyInList = true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if (!bAlreadyInList)
|
|
+ ppMatchWord[iMatchCount++] = g_strdup(sMatchWord);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ g_pattern_spec_free(pspec);
|
|
+
|
|
+ if (iMatchCount)// sort it.
|
|
+ std::sort(ppMatchWord, ppMatchWord+iMatchCount, less_for_compare);
|
|
+ return iMatchCount;
|
|
+}
|
|
+
|
|
+gint Libs::LookupWithRegex(const gchar *word, gchar **ppMatchWord, std::vector<InstantDictIndex> &dictmask)
|
|
+{
|
|
+ glong aiIndex[MAX_MATCH_ITEM_PER_LIB+1];
|
|
+ gint iMatchCount = 0;
|
|
+ GRegex *regex = g_regex_new(word, G_REGEX_OPTIMIZE, (GRegexMatchFlags)0, NULL);
|
|
+
|
|
+ const gchar * sMatchWord;
|
|
+ bool bAlreadyInList;
|
|
+ std::vector<Dict *>::size_type iRealLib;
|
|
+ for (std::vector<InstantDictIndex>::size_type iLib=0; iLib<dictmask.size(); iLib++) {
|
|
+ //if(oLibs.LookdupWordsWithRule(pspec,aiIndex,MAX_MATCH_ITEM_PER_LIB+1-iMatchCount,iLib))
|
|
+ // -iMatchCount,so save time,but may got less result and the word may repeat.
|
|
+ if (dictmask[iLib].type != InstantDictType_LOCAL)
|
|
+ continue;
|
|
+ iRealLib = dictmask[iLib].index;
|
|
+ if (oLib[iRealLib]->LookupWithRegex(regex, aiIndex, MAX_MATCH_ITEM_PER_LIB+1)) {
|
|
+ show_progress->notify_about_work();
|
|
+ for (int i=0; aiIndex[i]!=-1; i++) {
|
|
+ sMatchWord = poGetOrigWord(aiIndex[i],iRealLib);
|
|
+ bAlreadyInList = false;
|
|
+ for (int j=0; j<iMatchCount; j++) {
|
|
+ if (strcmp(ppMatchWord[j],sMatchWord)==0) {//already in list
|
|
+ bAlreadyInList = true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if (!bAlreadyInList)
|
|
+ ppMatchWord[iMatchCount++] = g_strdup(sMatchWord);
|
|
+ }
|
|
+ }
|
|
+ if (oLib[iRealLib]->LookupWithRegexSynonym(regex, aiIndex, MAX_MATCH_ITEM_PER_LIB+1)) {
|
|
+ show_progress->notify_about_work();
|
|
+ for (int i=0; aiIndex[i]!=-1; i++) {
|
|
+ sMatchWord = poGetOrigSynonymWord(aiIndex[i],iRealLib);
|
|
+ bAlreadyInList = false;
|
|
+ for (int j=0; j<iMatchCount; j++) {
|
|
+ if (strcmp(ppMatchWord[j],sMatchWord)==0) {//already in list
|
|
+ bAlreadyInList = true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if (!bAlreadyInList)
|
|
+ ppMatchWord[iMatchCount++] = g_strdup(sMatchWord);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ g_regex_unref(regex);
|
|
+
|
|
+ if (iMatchCount)// sort it.
|
|
+ std::sort(ppMatchWord, ppMatchWord+iMatchCount, less_for_compare);
|
|
+ return iMatchCount;
|
|
+}
|
|
+
|
|
+bool Libs::LookupData(const gchar *sWord, std::vector<gchar *> *reslist, updateSearchDialog_func search_func, gpointer search_data, bool *cancel, std::vector<InstantDictIndex> &dictmask)
|
|
+{
|
|
+ std::vector<std::string> SearchWords;
|
|
+ std::string SearchWord;
|
|
+ const char *p=sWord;
|
|
+ while (*p) {
|
|
+ if (*p=='\\') {
|
|
+ p++;
|
|
+ switch (*p) {
|
|
+ case ' ':
|
|
+ SearchWord+=' ';
|
|
+ break;
|
|
+ case '\\':
|
|
+ SearchWord+='\\';
|
|
+ break;
|
|
+ case 't':
|
|
+ SearchWord+='\t';
|
|
+ break;
|
|
+ case 'n':
|
|
+ SearchWord+='\n';
|
|
+ break;
|
|
+ default:
|
|
+ SearchWord+=*p;
|
|
+ }
|
|
+ } else if (*p == ' ') {
|
|
+ if (!SearchWord.empty()) {
|
|
+ SearchWords.push_back(SearchWord);
|
|
+ SearchWord.clear();
|
|
+ }
|
|
+ } else {
|
|
+ SearchWord+=*p;
|
|
+ }
|
|
+ p++;
|
|
+ }
|
|
+ if (!SearchWord.empty()) {
|
|
+ SearchWords.push_back(SearchWord);
|
|
+ SearchWord.clear();
|
|
+ }
|
|
+ if (SearchWords.empty())
|
|
+ return false;
|
|
+
|
|
+ glong search_count=0;
|
|
+ glong total_count=0;
|
|
+ if (search_func) {
|
|
+ for (std::vector<InstantDictIndex>::size_type i=0; i<dictmask.size(); ++i) {
|
|
+ if (dictmask[i].type == InstantDictType_LOCAL)
|
|
+ total_count += narticles(dictmask[i].index);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ guint32 max_size =0;
|
|
+ gchar *origin_data = NULL;
|
|
+ std::vector<InstantDictIndex>::size_type iRealLib;
|
|
+ for (std::vector<InstantDictIndex>::size_type i=0; i<dictmask.size(); ++i) {
|
|
+ if (dictmask[i].type != InstantDictType_LOCAL)
|
|
+ continue;
|
|
+ iRealLib = dictmask[i].index;
|
|
+ if (!oLib[iRealLib]->containSearchData())
|
|
+ continue;
|
|
+ const gulong iwords = narticles(iRealLib);
|
|
+ const gchar *key;
|
|
+ guint32 offset, size;
|
|
+ for (gulong j=0; j<iwords; ++j) {
|
|
+ if (search_func) {
|
|
+ if (*cancel)
|
|
+ goto search_out;
|
|
+ if (search_count % 10000 == 0) {
|
|
+ search_func(search_data, (gdouble)search_count/(gdouble)total_count);
|
|
+ }
|
|
+ search_count++;
|
|
+ }
|
|
+ oLib[iRealLib]->get_key_and_data(j, &key, &offset, &size);
|
|
+ if (size>max_size) {
|
|
+ origin_data = (gchar *)g_realloc(origin_data, size);
|
|
+ max_size = size;
|
|
+ }
|
|
+ if (oLib[iRealLib]->SearchData(SearchWords, offset, size, origin_data)) {
|
|
+ if (reslist[i].empty() || strcmp(reslist[i].back(), key))
|
|
+ reslist[i].push_back(g_strdup(key));
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+search_out:
|
|
+ g_free(origin_data);
|
|
+ KMP_end();
|
|
+
|
|
+ std::vector<InstantDictIndex>::size_type i;
|
|
+ for (i=0; i<dictmask.size(); ++i)
|
|
+ if (!reslist[i].empty())
|
|
+ break;
|
|
+
|
|
+ return i!=dictmask.size();
|
|
+}
|
|
+
|
|
+int Libs::GetStorageType(size_t iLib)
|
|
+{
|
|
+ if (oLib[iLib]->storage == NULL)
|
|
+ return -1;
|
|
+ return oLib[iLib]->storage->is_file_or_db;
|
|
+}
|
|
+
|
|
+const char *Libs::GetStorageFilePath(size_t iLib, const char *key)
|
|
+{
|
|
+ if (oLib[iLib]->storage == NULL)
|
|
+ return NULL;
|
|
+ return oLib[iLib]->storage->get_file_path(key);
|
|
+}
|
|
+
|
|
+const char *Libs::GetStorageFileContent(size_t iLib, const char *key)
|
|
+{
|
|
+ if (oLib[iLib]->storage == NULL)
|
|
+ return NULL;
|
|
+ return oLib[iLib]->storage->get_file_content(key);
|
|
+}
|
|
diff -Nur stardict-3.0.1.orig//src/lib/treedict.cpp stardict-3.0.1/src/lib/treedict.cpp
|
|
--- stardict-3.0.1.orig//src/lib/treedict.cpp 2007-09-20 20:09:52.000000000 -0500
|
|
+++ stardict-3.0.1/src/lib/treedict.cpp 2010-05-24 00:53:36.378667536 -0500
|
|
@@ -29,6 +29,7 @@
|
|
#include "getuint32.h"
|
|
|
|
#include "treedict.hpp"
|
|
+#include <cstring>
|
|
|
|
GtkTreeStore *TreeDict::model=NULL;
|
|
|
|
diff -Nur stardict-3.0.1.orig//src/lib/treedict.cpp~ stardict-3.0.1/src/lib/treedict.cpp~
|
|
--- stardict-3.0.1.orig//src/lib/treedict.cpp~ 1969-12-31 18:00:00.000000000 -0600
|
|
+++ stardict-3.0.1/src/lib/treedict.cpp~ 2007-09-20 20:09:52.000000000 -0500
|
|
@@ -0,0 +1,197 @@
|
|
+/*
|
|
+ * This file part of StarDict - A international dictionary for GNOME.
|
|
+ * http://stardict.sourceforge.net
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 3 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU Library General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * Implementation of class to work with GtkTree
|
|
+ * based StarDict's dictionaries
|
|
+ */
|
|
+#ifdef HAVE_CONFIG_H
|
|
+# include "config.h"
|
|
+#endif
|
|
+
|
|
+#include "file.hpp"
|
|
+#include "getuint32.h"
|
|
+
|
|
+#include "treedict.hpp"
|
|
+
|
|
+GtkTreeStore *TreeDict::model=NULL;
|
|
+
|
|
+TreeDict::TreeDict()
|
|
+{
|
|
+ if (model)
|
|
+ return;
|
|
+
|
|
+ // It is said G_TYPE_UINT will always be 32 bit.
|
|
+ // see http://bugzilla.gnome.org/show_bug.cgi?id=337966
|
|
+ model = gtk_tree_store_new (3, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT); //word, offset, size
|
|
+}
|
|
+
|
|
+bool TreeDict::load(const std::string& ifofilename)
|
|
+{
|
|
+ gulong tdxfilesize;
|
|
+ if (!load_ifofile(ifofilename, &tdxfilesize))
|
|
+ return false;
|
|
+
|
|
+ std::string fullfilename(ifofilename);
|
|
+ fullfilename.replace(fullfilename.length()-sizeof("ifo")+1, sizeof("ifo")-1, "dict.dz");
|
|
+
|
|
+ if (g_file_test(fullfilename.c_str(), G_FILE_TEST_EXISTS)) {
|
|
+ dictdzfile.reset(new dictData);
|
|
+ if (!dictdzfile->open(fullfilename, 0)) {
|
|
+ //g_print("open file %s failed!\n",fullfilename);
|
|
+ return false;
|
|
+ }
|
|
+ } else {
|
|
+ fullfilename.erase(fullfilename.length()-sizeof(".dz")+1, sizeof(".dz")-1);
|
|
+ dictfile = fopen(fullfilename.c_str(),"rb");
|
|
+ if (!dictfile) {
|
|
+ //g_print("open file %s failed!\n",fullfilename);
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ fullfilename=ifofilename;
|
|
+ fullfilename.replace(fullfilename.length()-sizeof("ifo")+1, sizeof("ifo")-1, "tdx.gz");
|
|
+
|
|
+ gchar *buffer= NULL;
|
|
+ if (g_file_test(fullfilename.c_str(), G_FILE_TEST_EXISTS)) {
|
|
+ gzFile in;
|
|
+ in = gzopen(fullfilename.c_str(),"rb");
|
|
+ if (in == NULL) {
|
|
+ //g_print("Open file %s failed!\n",idxfilename);
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ buffer = (gchar *)g_malloc(tdxfilesize);
|
|
+
|
|
+ gulong len;
|
|
+ len = gzread(in, buffer, tdxfilesize);
|
|
+ if (len < 0) {
|
|
+ g_free(buffer);
|
|
+ return false;
|
|
+ }
|
|
+ gzclose(in);
|
|
+ if (len != tdxfilesize) {
|
|
+ g_free(buffer);
|
|
+ return false;
|
|
+ }
|
|
+ } else {
|
|
+ fullfilename.erase(fullfilename.length()-sizeof(".gz")+1, sizeof(".gz")-1);
|
|
+ FILE *file;
|
|
+ if (!(file = fopen (fullfilename.c_str(), "rb"))) {
|
|
+ //g_print("Open file %s failed!\n",fullfilename);
|
|
+ return false;
|
|
+ }
|
|
+ buffer = (gchar *)g_malloc(tdxfilesize);
|
|
+ gulong read_len;
|
|
+ read_len = fread(buffer, 1, tdxfilesize, file);
|
|
+ fclose(file);
|
|
+ if (read_len!=tdxfilesize) {
|
|
+ g_free(buffer);
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ gchar *tmp_buffer = buffer;
|
|
+ load_model(&tmp_buffer, NULL, 1); // tmp_buffer will be changed.
|
|
+ g_free(buffer);
|
|
+ return true;
|
|
+}
|
|
+
|
|
+bool TreeDict::load_ifofile(const std::string& ifofilename, gulong *tdxfilesize)
|
|
+{
|
|
+ DictInfo dict_info;
|
|
+ if (!dict_info.load_from_ifo_file(ifofilename, true))
|
|
+ return false;
|
|
+
|
|
+ *tdxfilesize = dict_info.index_file_size;
|
|
+ sametypesequence=dict_info.sametypesequence;
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+void TreeDict::load_model(gchar **buffer, GtkTreeIter *parent, guint32 count)
|
|
+{
|
|
+ GtkTreeIter iter;
|
|
+ gchar *p1;
|
|
+ guint32 offset, size, subentry_count;
|
|
+
|
|
+ for (guint32 i=0; i< count; i++) {
|
|
+ p1 = *buffer + strlen(*buffer) +1;
|
|
+ offset = g_ntohl(get_uint32(p1));
|
|
+ p1 += sizeof(guint32);
|
|
+ size = g_ntohl(get_uint32(p1));
|
|
+ p1 += sizeof(guint32);
|
|
+ subentry_count = g_ntohl(get_uint32(p1));
|
|
+ p1 += sizeof(guint32);
|
|
+ gtk_tree_store_append(model, &iter, parent);
|
|
+ gtk_tree_store_set(model, &iter, 0, *buffer, 1, offset, 2, size, -1);
|
|
+ *buffer = p1;
|
|
+ if (subentry_count)
|
|
+ load_model(buffer, &iter, subentry_count);
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+/**************************************************/
|
|
+TreeDicts::TreeDicts()
|
|
+{
|
|
+}
|
|
+
|
|
+TreeDicts::~TreeDicts()
|
|
+{
|
|
+ for (std::vector<TreeDict *>::iterator it=oTreeDict.begin();
|
|
+ it!=oTreeDict.end(); ++it)
|
|
+ delete *it;
|
|
+}
|
|
+
|
|
+void TreeDicts::load_dict(const std::string& url)
|
|
+{
|
|
+ TreeDict *lib = new TreeDict;
|
|
+ if (lib->load(url))
|
|
+ oTreeDict.push_back(lib);
|
|
+ else
|
|
+ delete lib;
|
|
+}
|
|
+
|
|
+class TreeDictLoader {
|
|
+public:
|
|
+ TreeDictLoader(TreeDicts& td_) : td(td_) {}
|
|
+ void operator()(const std::string& url, bool disable) {
|
|
+ if (!disable)
|
|
+ td.load_dict(url);
|
|
+ }
|
|
+private:
|
|
+ TreeDicts& td;
|
|
+};
|
|
+
|
|
+GtkTreeStore* TreeDicts::Load(const strlist_t& tree_dicts_dirs,
|
|
+ const strlist_t& order_list,
|
|
+ const strlist_t& disable_list)
|
|
+{
|
|
+ TreeDictLoader load(*this);
|
|
+ for_each_file(tree_dicts_dirs, ".ifo", order_list, disable_list, load);
|
|
+
|
|
+ return TreeDict::get_model();
|
|
+}
|
|
+
|
|
+gchar* TreeDicts::poGetWordData(guint32 offset, guint32 size, int iTreeDict)
|
|
+{
|
|
+ return oTreeDict[iTreeDict]->GetWordData(offset, size);
|
|
+}
|
|
diff -Nur stardict-3.0.1.orig//src/pangoview.cpp stardict-3.0.1/src/pangoview.cpp
|
|
--- stardict-3.0.1.orig//src/pangoview.cpp 2007-09-25 02:11:48.000000000 -0500
|
|
+++ stardict-3.0.1/src/pangoview.cpp 2010-05-24 00:53:36.378667536 -0500
|
|
@@ -22,6 +22,8 @@
|
|
# include "config.h"
|
|
#endif
|
|
|
|
+#include <cstring>
|
|
+
|
|
#include "gtktextviewpango.h"
|
|
#include "utils.h"
|
|
#include "skin.h"//for SkinCursor definition
|
|
diff -Nur stardict-3.0.1.orig//src/pangoview.cpp~ stardict-3.0.1/src/pangoview.cpp~
|
|
--- stardict-3.0.1.orig//src/pangoview.cpp~ 1969-12-31 18:00:00.000000000 -0600
|
|
+++ stardict-3.0.1/src/pangoview.cpp~ 2007-09-25 02:11:48.000000000 -0500
|
|
@@ -0,0 +1,499 @@
|
|
+/*
|
|
+ * This file part of StarDict - A international dictionary for GNOME.
|
|
+ * http://stardict.sourceforge.net
|
|
+ * Copyright (C) 2005-2006 Evgeniy <dushistov@mail.ru>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 3 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU Library General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
+ */
|
|
+
|
|
+#ifdef HAVE_CONFIG_H
|
|
+# include "config.h"
|
|
+#endif
|
|
+
|
|
+#include "gtktextviewpango.h"
|
|
+#include "utils.h"
|
|
+#include "skin.h"//for SkinCursor definition
|
|
+
|
|
+#include "pangoview.h"
|
|
+
|
|
+class TextPangoWidget : public PangoWidgetBase {
|
|
+public:
|
|
+ TextPangoWidget();
|
|
+ GtkWidget *widget() { return GTK_WIDGET(textview_); }
|
|
+
|
|
+ void clear();
|
|
+ void append_mark(const char *mark);
|
|
+ void append_pixbuf(GdkPixbuf *pixbuf, const char *label);
|
|
+ void append_widget(GtkWidget *widget);
|
|
+ void begin_update();
|
|
+ void end_update();
|
|
+ std::string get_text();
|
|
+ void append_pango_text_with_links(const std::string&,
|
|
+ const LinksPosList&);
|
|
+protected:
|
|
+ void do_set_text(const char *str);
|
|
+ void do_append_text(const char *str);
|
|
+ void do_append_pango_text(const char *str);
|
|
+ void do_set_pango_text(const char *str);
|
|
+private:
|
|
+ GtkTextView *textview_;
|
|
+ std::list<GtkTextMark *> marklist_;
|
|
+ struct TextBufPos {
|
|
+ gint beg_;
|
|
+ gint end_;
|
|
+ std::string link_;
|
|
+ TextBufPos(gint beg, gint end, std::string link): beg_(beg), end_(end), link_(link) {}
|
|
+ };
|
|
+ typedef std::vector<TextBufPos> TextBufLinks;
|
|
+
|
|
+ TextBufLinks tb_links_;
|
|
+ GtkTextIter iter_;
|
|
+ SkinCursor hand_cursor_, regular_cursor_;
|
|
+
|
|
+ static gboolean on_mouse_move(GtkWidget *, GdkEventMotion *, gpointer);
|
|
+ static gboolean on_button_release(GtkWidget *, GdkEventButton *, gpointer);
|
|
+
|
|
+ void goto_begin();
|
|
+ void goto_end();
|
|
+ TextBufLinks::const_iterator find_link(gint x, gint y);
|
|
+};
|
|
+
|
|
+class LabelPangoWidget : public PangoWidgetBase {
|
|
+public:
|
|
+ LabelPangoWidget();
|
|
+ GtkWidget *widget() { return GTK_WIDGET(label_); }
|
|
+
|
|
+ void clear();
|
|
+ void append_mark(const char *mark) {}
|
|
+ void append_pixbuf(GdkPixbuf *pixbuf, const char *label);
|
|
+ void append_widget(GtkWidget *widget);
|
|
+ std::string get_text();
|
|
+ void modify_bg(GtkStateType state, const GdkColor *color);
|
|
+protected:
|
|
+ void do_set_text(const char *str);
|
|
+ void do_append_text(const char *str);
|
|
+ void do_append_pango_text(const char *str);
|
|
+ void do_set_pango_text(const char *str);
|
|
+private:
|
|
+ GtkLabel *label_;
|
|
+ GtkWidget *viewport_;
|
|
+};
|
|
+
|
|
+
|
|
+void PangoWidgetBase::begin_update()
|
|
+{
|
|
+ update_ = true;
|
|
+}
|
|
+
|
|
+void PangoWidgetBase::end_update()
|
|
+{
|
|
+ if (update_) {
|
|
+ update_ = false;
|
|
+ do_append_pango_text(cache_.c_str());
|
|
+ cache_.clear();
|
|
+ }
|
|
+}
|
|
+
|
|
+void PangoWidgetBase::append_text(const char *str)
|
|
+{
|
|
+ if (update_) {
|
|
+ gchar *mark = g_markup_escape_text(str, -1);
|
|
+ cache_ += mark;
|
|
+ g_free(mark);
|
|
+ } else {
|
|
+ do_append_text(str);
|
|
+ }
|
|
+}
|
|
+
|
|
+void PangoWidgetBase::append_pango_text(const char *str)
|
|
+{
|
|
+ if (update_)
|
|
+ cache_ += str;
|
|
+ else
|
|
+ do_append_pango_text(str);
|
|
+}
|
|
+
|
|
+void PangoWidgetBase::append_pango_text_with_links(const std::string& str,
|
|
+ const LinksPosList&)
|
|
+{
|
|
+ append_pango_text(str.c_str());
|
|
+}
|
|
+
|
|
+void PangoWidgetBase::set_pango_text(const char *str)
|
|
+{
|
|
+ if (update_)
|
|
+ cache_ = str;
|
|
+ else
|
|
+ do_set_pango_text(str);
|
|
+}
|
|
+
|
|
+
|
|
+void TextPangoWidget::begin_update()
|
|
+{
|
|
+ PangoWidgetBase::begin_update();
|
|
+ gtk_text_buffer_begin_user_action(
|
|
+ gtk_text_view_get_buffer(textview_));
|
|
+}
|
|
+
|
|
+
|
|
+void TextPangoWidget::end_update()
|
|
+{
|
|
+ PangoWidgetBase::end_update();
|
|
+ gtk_text_buffer_end_user_action(gtk_text_view_get_buffer(textview_));
|
|
+}
|
|
+
|
|
+
|
|
+TextPangoWidget::TextPangoWidget()
|
|
+{
|
|
+ hand_cursor_.reset(gdk_cursor_new(GDK_HAND2));
|
|
+ regular_cursor_.reset(gdk_cursor_new(GDK_XTERM));
|
|
+ textview_ = GTK_TEXT_VIEW(gtk_text_view_new());
|
|
+ gtk_widget_show(GTK_WIDGET(textview_));
|
|
+ gtk_text_view_set_editable(textview_, FALSE);
|
|
+ gtk_text_view_set_cursor_visible(textview_, FALSE);
|
|
+ gtk_text_view_set_wrap_mode(textview_, GTK_WRAP_WORD_CHAR);
|
|
+ gtk_text_view_set_left_margin(textview_, 5);
|
|
+ gtk_text_view_set_right_margin(textview_, 5);
|
|
+
|
|
+ g_signal_connect(textview_, "button-release-event",
|
|
+ G_CALLBACK(on_button_release), this);
|
|
+ g_signal_connect(textview_, "motion-notify-event",
|
|
+ G_CALLBACK(on_mouse_move), this);
|
|
+
|
|
+ gtk_text_buffer_get_iter_at_offset(gtk_text_view_get_buffer(textview_),
|
|
+ &iter_, 0);
|
|
+ scroll_win_ = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL, NULL));
|
|
+ gtk_widget_show(GTK_WIDGET(scroll_win_));
|
|
+
|
|
+
|
|
+ gtk_scrolled_window_set_policy(scroll_win_,
|
|
+ //altought textview's set_wrap_mode will cause
|
|
+ //this can be GTK_POLICY_NEVER,but...
|
|
+ //there are widgets that may make this broken.
|
|
+ GTK_POLICY_AUTOMATIC,
|
|
+ GTK_POLICY_AUTOMATIC);
|
|
+ gtk_container_add(GTK_CONTAINER(scroll_win_), GTK_WIDGET(textview_));
|
|
+ gtk_scrolled_window_set_shadow_type(scroll_win_, GTK_SHADOW_IN);
|
|
+}
|
|
+
|
|
+void LabelPangoWidget::modify_bg(GtkStateType state, const GdkColor *color)
|
|
+{
|
|
+ gtk_widget_modify_bg(viewport_, state, color);
|
|
+}
|
|
+
|
|
+LabelPangoWidget::LabelPangoWidget()
|
|
+{
|
|
+ label_ = GTK_LABEL(gtk_label_new(NULL));
|
|
+ gtk_label_set_justify(label_, GTK_JUSTIFY_LEFT);
|
|
+ scroll_win_ = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL, NULL));
|
|
+ gtk_scrolled_window_set_shadow_type(scroll_win_, GTK_SHADOW_NONE);
|
|
+ gtk_scrolled_window_set_policy(scroll_win_, GTK_POLICY_NEVER,
|
|
+ GTK_POLICY_AUTOMATIC);
|
|
+
|
|
+ viewport_ =
|
|
+ gtk_viewport_new(gtk_scrolled_window_get_hadjustment(scroll_win_),
|
|
+ gtk_scrolled_window_get_vadjustment(scroll_win_));
|
|
+ gtk_widget_add_events(viewport_, GDK_BUTTON1_MOTION_MASK);
|
|
+ gtk_widget_add_events(viewport_, GDK_BUTTON_RELEASE_MASK);
|
|
+ gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport_), GTK_SHADOW_NONE);
|
|
+ gtk_container_add(GTK_CONTAINER(scroll_win_), viewport_);
|
|
+ gtk_container_add(GTK_CONTAINER(viewport_), GTK_WIDGET(label_));
|
|
+}
|
|
+
|
|
+PangoWidgetBase *PangoWidgetBase::create(bool autoresize)
|
|
+{
|
|
+ if (!autoresize)
|
|
+ return new TextPangoWidget;
|
|
+ else
|
|
+ return new LabelPangoWidget;
|
|
+}
|
|
+
|
|
+void TextPangoWidget::do_set_text(const char *text)
|
|
+{
|
|
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(textview_);
|
|
+
|
|
+ std::list<GtkTextMark *>::const_iterator it;
|
|
+ for (it = marklist_.begin(); it != marklist_.end(); ++it)
|
|
+ gtk_text_buffer_delete_mark(buffer, *it);
|
|
+ marklist_.clear();
|
|
+ tb_links_.clear();
|
|
+
|
|
+ gtk_text_buffer_set_text(buffer, text, -1);
|
|
+}
|
|
+
|
|
+void LabelPangoWidget::do_set_text(const char *text)
|
|
+{
|
|
+ scroll_to(0);
|
|
+ // this should speed up the next two line.
|
|
+ gtk_label_set_markup(label_, "");
|
|
+ // so Popup()'s gtk_widget_size_request(label, &requisition); can
|
|
+ gtk_widget_set_size_request(GTK_WIDGET(label_), -1, -1);
|
|
+ // get its original width.
|
|
+ gtk_label_set_line_wrap(label_, FALSE);
|
|
+ gchar *mstr = g_markup_escape_text(text, -1);
|
|
+ gtk_label_set_text(label_, mstr);
|
|
+ g_free(mstr);
|
|
+}
|
|
+
|
|
+void LabelPangoWidget::append_pixbuf(GdkPixbuf *pixbuf, const char *label)
|
|
+{
|
|
+ if (label) {
|
|
+ gchar *markup = g_markup_printf_escaped("<span foreground=\"red\">[Image:%s]</span>", label);
|
|
+ append_pango_text(markup);
|
|
+ g_free(markup);
|
|
+ } else {
|
|
+ append_pango_text("<span foreground=\"red\">[Image]</span>");
|
|
+ }
|
|
+}
|
|
+
|
|
+void LabelPangoWidget::append_widget(GtkWidget *widget)
|
|
+{
|
|
+ append_pango_text("<span foreground=\"red\">[Widget]</span>");
|
|
+ if (widget) {
|
|
+ gtk_widget_destroy(widget);
|
|
+ }
|
|
+}
|
|
+
|
|
+void PangoWidgetBase::set_text(const char *str)
|
|
+{
|
|
+ if (update_) {
|
|
+ gchar *mark = g_markup_escape_text(str, -1);
|
|
+ cache_ = mark;
|
|
+ g_free(mark);
|
|
+ } else {
|
|
+ do_set_text(str);
|
|
+ }
|
|
+}
|
|
+
|
|
+void TextPangoWidget::do_append_text(const char *str)
|
|
+{
|
|
+ gtk_text_buffer_insert(gtk_text_view_get_buffer(textview_),
|
|
+ &iter_, str, strlen(str));
|
|
+}
|
|
+
|
|
+void LabelPangoWidget::do_append_text(const char *str)
|
|
+{
|
|
+ set_text((std::string(gtk_label_get_text(label_)) + str).c_str());
|
|
+}
|
|
+
|
|
+
|
|
+void TextPangoWidget::do_append_pango_text(const char *str)
|
|
+{
|
|
+
|
|
+ gtk_text_buffer_insert_markup(gtk_text_view_get_buffer(textview_),
|
|
+ &iter_, str);
|
|
+}
|
|
+
|
|
+void TextPangoWidget::do_set_pango_text(const char *str)
|
|
+{
|
|
+ clear();
|
|
+ goto_begin();
|
|
+ do_append_pango_text(str);
|
|
+}
|
|
+
|
|
+void LabelPangoWidget::do_set_pango_text(const char *str)
|
|
+{
|
|
+ scroll_to(0);
|
|
+ // this should speed up the next two line.
|
|
+ gtk_label_set_markup(label_, "");
|
|
+ // so Popup()'s gtk_widget_size_request(label,&requisition); can
|
|
+ gtk_widget_set_size_request(GTK_WIDGET(label_), -1, -1);
|
|
+ // get its original width.
|
|
+ gtk_label_set_line_wrap(label_, FALSE);
|
|
+ gtk_label_set_markup(label_, str);
|
|
+}
|
|
+
|
|
+void LabelPangoWidget::do_append_pango_text(const char *str)
|
|
+{
|
|
+ do_set_pango_text((std::string(gtk_label_get_label(label_)) + str).c_str());
|
|
+}
|
|
+
|
|
+void TextPangoWidget::append_mark(const char *mark)
|
|
+{
|
|
+ GtkTextBuffer *buffer=gtk_text_view_get_buffer(textview_);
|
|
+ if (update_) {
|
|
+ if (!cache_.empty()) {
|
|
+ do_append_pango_text(cache_.c_str());
|
|
+ cache_.clear();
|
|
+ }
|
|
+ }
|
|
+ marklist_.push_back(
|
|
+ gtk_text_buffer_create_mark(buffer, mark, &iter_, TRUE));
|
|
+}
|
|
+
|
|
+void TextPangoWidget::clear()
|
|
+{
|
|
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(textview_);
|
|
+
|
|
+ std::list<GtkTextMark *>::const_iterator it;
|
|
+ for (it = marklist_.begin(); it != marklist_.end(); ++it)
|
|
+ gtk_text_buffer_delete_mark(buffer, *it);
|
|
+
|
|
+ marklist_.clear();
|
|
+ tb_links_.clear();
|
|
+
|
|
+ GtkTextIter start, end;
|
|
+ gtk_text_buffer_get_bounds(buffer, &start, &end);
|
|
+ gtk_text_buffer_delete(buffer, &start, &end);
|
|
+ scroll_to(0);
|
|
+ cache_.clear();
|
|
+}
|
|
+
|
|
+void LabelPangoWidget::clear()
|
|
+{
|
|
+ do_set_text("");
|
|
+ cache_.clear();
|
|
+}
|
|
+
|
|
+void TextPangoWidget::goto_begin()
|
|
+{
|
|
+ gtk_text_buffer_get_iter_at_offset(
|
|
+ gtk_text_view_get_buffer(textview_), &iter_, 0
|
|
+ );
|
|
+}
|
|
+
|
|
+void TextPangoWidget::goto_end()
|
|
+{
|
|
+ gtk_text_buffer_get_iter_at_offset(gtk_text_view_get_buffer(textview_), &iter_, -1);
|
|
+}
|
|
+
|
|
+std::string TextPangoWidget::get_text()
|
|
+{
|
|
+ std::string res;
|
|
+
|
|
+ GtkTextIter start, end;
|
|
+ GtkTextBuffer *buffer=gtk_text_view_get_buffer(textview_);
|
|
+ gtk_text_buffer_get_bounds(buffer, &start, &end);
|
|
+ gchar *text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
|
|
+ res = text;
|
|
+ g_free(text);
|
|
+
|
|
+ return res;
|
|
+}
|
|
+
|
|
+std::string LabelPangoWidget::get_text()
|
|
+{
|
|
+ return gtk_label_get_text(label_);
|
|
+}
|
|
+
|
|
+
|
|
+void TextPangoWidget::append_pango_text_with_links(const std::string& str,
|
|
+ const LinksPosList& links)
|
|
+{
|
|
+ if (links.empty()) {
|
|
+ append_pango_text(str.c_str());
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ do_append_pango_text(cache_.c_str());
|
|
+ cache_.clear();
|
|
+
|
|
+ gint beg = gtk_text_iter_get_offset(&iter_);
|
|
+
|
|
+ for (LinksPosList::const_iterator it = links.begin();
|
|
+ it != links.end(); ++it) {
|
|
+ tb_links_.push_back(TextBufPos(beg + it->pos_, beg + it->pos_ + it->len_, it->link_));
|
|
+ }
|
|
+
|
|
+ gtk_text_buffer_insert_markup(gtk_text_view_get_buffer(textview_),
|
|
+ &iter_, str.c_str());
|
|
+}
|
|
+
|
|
+void TextPangoWidget::append_pixbuf(GdkPixbuf *pixbuf, const char *label)
|
|
+{
|
|
+ do_append_pango_text(cache_.c_str());
|
|
+ cache_.clear();
|
|
+ gtk_text_buffer_insert_pixbuf (gtk_text_view_get_buffer(textview_), &iter_, pixbuf);
|
|
+}
|
|
+
|
|
+void TextPangoWidget::append_widget(GtkWidget *widget)
|
|
+{
|
|
+ do_append_pango_text(cache_.c_str());
|
|
+ cache_.clear();
|
|
+ GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor (gtk_text_view_get_buffer(textview_), &iter_);
|
|
+ gtk_text_view_add_child_at_anchor (textview_, widget, anchor);
|
|
+}
|
|
+
|
|
+TextPangoWidget::TextBufLinks::const_iterator TextPangoWidget::find_link(gint x,
|
|
+ gint y)
|
|
+{
|
|
+ GtkTextIter iter;
|
|
+ gtk_text_view_get_iter_at_location(textview_, &iter, x, y);
|
|
+ gint pos = gtk_text_iter_get_offset(&iter);
|
|
+ TextBufLinks::const_iterator it;
|
|
+ for (it = tb_links_.begin(); it != tb_links_.end(); ++it) {
|
|
+ if (pos < it->beg_)
|
|
+ return tb_links_.end();
|
|
+ if (it->beg_ <= pos && pos < it->end_)
|
|
+ break;
|
|
+ }
|
|
+ return it;
|
|
+}
|
|
+
|
|
+gboolean TextPangoWidget::on_mouse_move(GtkWidget *widget, GdkEventMotion *event,
|
|
+ gpointer userdata)
|
|
+{
|
|
+ TextPangoWidget *tpw = static_cast<TextPangoWidget *>(userdata);
|
|
+ GtkTextWindowType win_type =
|
|
+ gtk_text_view_get_window_type(tpw->textview_, event->window);
|
|
+ gint x, y;
|
|
+ gtk_text_view_window_to_buffer_coords(tpw->textview_, win_type,
|
|
+ gint(event->x), gint(event->y),
|
|
+ &x, &y);
|
|
+
|
|
+ TextBufLinks::const_iterator it = tpw->find_link(x, y);
|
|
+ if (it != tpw->tb_links_.end()) {
|
|
+ gdk_window_set_cursor(
|
|
+ gtk_text_view_get_window(tpw->textview_,
|
|
+ GTK_TEXT_WINDOW_TEXT),
|
|
+ get_impl(tpw->hand_cursor_));
|
|
+ } else {
|
|
+ gdk_window_set_cursor(
|
|
+ gtk_text_view_get_window(tpw->textview_,
|
|
+ GTK_TEXT_WINDOW_TEXT),
|
|
+ get_impl(tpw->regular_cursor_));
|
|
+ }
|
|
+
|
|
+ gdk_window_get_pointer(widget->window, NULL, NULL, NULL);
|
|
+
|
|
+ return FALSE;
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
+gboolean TextPangoWidget::on_button_release(GtkWidget *, GdkEventButton *event,
|
|
+ gpointer userdata)
|
|
+{
|
|
+ if (event->button != 1)
|
|
+ return FALSE;
|
|
+ TextPangoWidget *tpw = static_cast<TextPangoWidget *>(userdata);
|
|
+ GtkTextBuffer *buf = gtk_text_view_get_buffer(tpw->textview_);
|
|
+ /* we shouldn't follow a link if the user has selected something */
|
|
+ GtkTextIter beg, end;
|
|
+ gtk_text_buffer_get_selection_bounds (buf, &beg, &end);
|
|
+ if (gtk_text_iter_get_offset (&beg) != gtk_text_iter_get_offset (&end))
|
|
+ return FALSE;
|
|
+ GtkTextWindowType win_type =
|
|
+ gtk_text_view_get_window_type(tpw->textview_, event->window);
|
|
+ gint x, y;
|
|
+ gtk_text_view_window_to_buffer_coords(tpw->textview_, win_type,
|
|
+ gint(event->x), gint(event->y),
|
|
+ &x, &y);
|
|
+ TextBufLinks::const_iterator it = tpw->find_link(x, y);
|
|
+ if (it != tpw->tb_links_.end()) {
|
|
+ tpw->on_link_click_.emit(it->link_);
|
|
+ }
|
|
+ return FALSE;
|
|
+}
|
|
diff -Nur stardict-3.0.1.orig//src/prefsdlg.cpp stardict-3.0.1/src/prefsdlg.cpp
|
|
--- stardict-3.0.1.orig//src/prefsdlg.cpp 2007-10-30 03:14:07.000000000 -0500
|
|
+++ stardict-3.0.1/src/prefsdlg.cpp 2010-05-24 00:53:36.380667202 -0500
|
|
@@ -21,6 +21,8 @@
|
|
# include "config.h"
|
|
#endif
|
|
|
|
+#include <cstdlib>
|
|
+
|
|
#include <glib/gi18n.h>
|
|
#include <glib/gstdio.h>
|
|
|
|
diff -Nur stardict-3.0.1.orig//src/prefsdlg.cpp~ stardict-3.0.1/src/prefsdlg.cpp~
|
|
--- stardict-3.0.1.orig//src/prefsdlg.cpp~ 1969-12-31 18:00:00.000000000 -0600
|
|
+++ stardict-3.0.1/src/prefsdlg.cpp~ 2007-10-30 03:14:07.000000000 -0500
|
|
@@ -0,0 +1,1908 @@
|
|
+/*
|
|
+ * This file part of StarDict - A international dictionary for GNOME.
|
|
+ * http://stardict.sourceforge.net
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 3 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU Library General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
+ */
|
|
+
|
|
+#ifdef HAVE_CONFIG_H
|
|
+# include "config.h"
|
|
+#endif
|
|
+
|
|
+#include <glib/gi18n.h>
|
|
+#include <glib/gstdio.h>
|
|
+
|
|
+#ifdef _WIN32
|
|
+# include <gdk/gdkwin32.h>
|
|
+#endif
|
|
+
|
|
+#include "stardict.h"
|
|
+#include "conf.h"
|
|
+#include "desktop.hpp"
|
|
+#include "utils.h"
|
|
+#include "iskeyspressed.hpp"
|
|
+#include "lib/md5.h"
|
|
+
|
|
+#include "prefsdlg.h"
|
|
+
|
|
+#ifndef CONFIG_GPE
|
|
+enum {
|
|
+ LOGO = 0,
|
|
+ DICTIONARY_SCAN_SETTINGS,
|
|
+ DICTIONARY_FONT_SETTINGS,
|
|
+ DICTIONARY_CACHE_SETTINGS,
|
|
+ DICTIONARY_EXPORT_SETTINGS,
|
|
+ DICTIONARY_SOUND_SETTINGS,
|
|
+ DICIONARY_ARTICLE_RENDERING,
|
|
+ NETWORK_NETDICT,
|
|
+ MAINWIN_INPUT_SETTINGS,
|
|
+ MAINWIN_OPTIONS_SETTINGS,
|
|
+ MAINWIN_SEARCH_WEBSITE_SETTINGS,
|
|
+ NOTIFICATION_AREA_ICON_OPITIONS_SETTINGS,
|
|
+ FLOATWIN_OPTIONS_SETTINGS,
|
|
+ FLOATWIN_SIZE_SETTINGS,
|
|
+};
|
|
+
|
|
+enum
|
|
+{
|
|
+ CATEGORY_COLUMN = 0,
|
|
+ PAGE_NUM_COLUMN,
|
|
+ NUM_COLUMNS
|
|
+};
|
|
+
|
|
+
|
|
+struct CategoriesTreeItem {
|
|
+ gchar *category;
|
|
+
|
|
+ CategoriesTreeItem *children;
|
|
+
|
|
+ gint notebook_page;
|
|
+};
|
|
+
|
|
+static CategoriesTreeItem dictionary_behavior [] = {
|
|
+ {N_("Scan Selection"), NULL, DICTIONARY_SCAN_SETTINGS},
|
|
+ {N_("Font"), NULL, DICTIONARY_FONT_SETTINGS},
|
|
+ {N_("Cache"), NULL, DICTIONARY_CACHE_SETTINGS},
|
|
+ {N_("Export"), NULL, DICTIONARY_EXPORT_SETTINGS},
|
|
+ {N_("Sound"), NULL, DICTIONARY_SOUND_SETTINGS},
|
|
+ {N_("Article rendering"), NULL, DICIONARY_ARTICLE_RENDERING },
|
|
+ { NULL }
|
|
+};
|
|
+
|
|
+static CategoriesTreeItem network_behavior [] = {
|
|
+ {N_("Net Dict"), NULL, NETWORK_NETDICT},
|
|
+ { NULL }
|
|
+};
|
|
+
|
|
+static CategoriesTreeItem mainwin_behavior [] =
|
|
+{
|
|
+ {N_("Input"), NULL, MAINWIN_INPUT_SETTINGS},
|
|
+ {N_("Options"), NULL, MAINWIN_OPTIONS_SETTINGS},
|
|
+ {N_("Search website"), NULL, MAINWIN_SEARCH_WEBSITE_SETTINGS},
|
|
+
|
|
+ { NULL }
|
|
+};
|
|
+
|
|
+static CategoriesTreeItem NotificationAreaIcon_behavior [] =
|
|
+{
|
|
+ {N_("Options"), NULL, NOTIFICATION_AREA_ICON_OPITIONS_SETTINGS},
|
|
+
|
|
+ { NULL }
|
|
+};
|
|
+
|
|
+static CategoriesTreeItem floatwin_behavior [] =
|
|
+{
|
|
+ {N_("Options"), NULL, FLOATWIN_OPTIONS_SETTINGS},
|
|
+ {N_("Settings"), NULL, FLOATWIN_SIZE_SETTINGS},
|
|
+
|
|
+ { NULL }
|
|
+};
|
|
+
|
|
+static CategoriesTreeItem toplevel [] =
|
|
+{
|
|
+ {N_("Dictionary"), dictionary_behavior, LOGO},
|
|
+
|
|
+ {N_("Network"), network_behavior, LOGO},
|
|
+
|
|
+ {N_("Main window"), mainwin_behavior, LOGO},
|
|
+
|
|
+ {N_("Notification area icon"), NotificationAreaIcon_behavior, LOGO},
|
|
+
|
|
+ {N_("Floating window"), floatwin_behavior, LOGO},
|
|
+
|
|
+ { NULL }
|
|
+};
|
|
+
|
|
+static gint last_selected_page_num = DICTIONARY_SCAN_SETTINGS;
|
|
+#endif
|
|
+
|
|
+void PrefsDlg::response_handler (GtkDialog *dialog, gint res_id, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ if (res_id==GTK_RESPONSE_HELP)
|
|
+ show_help("stardict-prefs");
|
|
+}
|
|
+
|
|
+#ifndef CONFIG_GPE
|
|
+GtkTreeModel* PrefsDlg::create_categories_tree_model ()
|
|
+{
|
|
+ GtkTreeStore *model;
|
|
+ GtkTreeIter iter;
|
|
+ CategoriesTreeItem *category = toplevel;
|
|
+
|
|
+ model = gtk_tree_store_new (NUM_COLUMNS, G_TYPE_STRING, G_TYPE_INT);
|
|
+
|
|
+ while (category->category) {
|
|
+ CategoriesTreeItem *sub_category = category->children;
|
|
+ gtk_tree_store_append (model, &iter, NULL);
|
|
+ gtk_tree_store_set (model, &iter, CATEGORY_COLUMN, gettext (category->category), PAGE_NUM_COLUMN, category->notebook_page, -1);
|
|
+
|
|
+ while (sub_category->category) {
|
|
+ GtkTreeIter child_iter;
|
|
+ gtk_tree_store_append (model, &child_iter, &iter);
|
|
+ gtk_tree_store_set (model, &child_iter,
|
|
+ CATEGORY_COLUMN, gettext (sub_category->category),
|
|
+ PAGE_NUM_COLUMN, sub_category->notebook_page,
|
|
+ -1);
|
|
+ sub_category++;
|
|
+ }
|
|
+ category++;
|
|
+ }
|
|
+ return GTK_TREE_MODEL (model);
|
|
+}
|
|
+
|
|
+void PrefsDlg::categories_tree_selection_cb (GtkTreeSelection *selection, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ GtkTreeIter iter;
|
|
+ GValue value = {0, };
|
|
+
|
|
+ if (! gtk_tree_selection_get_selected (selection, NULL, &iter))
|
|
+ return;
|
|
+
|
|
+ gtk_tree_model_get_value (oPrefsDlg->categories_tree_model, &iter,
|
|
+ PAGE_NUM_COLUMN,
|
|
+ &value);
|
|
+
|
|
+ last_selected_page_num = g_value_get_int (&value);
|
|
+
|
|
+ if (oPrefsDlg->notebook != NULL)
|
|
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (oPrefsDlg->notebook),
|
|
+ last_selected_page_num);
|
|
+ g_value_unset (&value);
|
|
+}
|
|
+
|
|
+gboolean PrefsDlg::selection_init (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ GValue value = {0, };
|
|
+ gint page_num;
|
|
+
|
|
+ gtk_tree_model_get_value (oPrefsDlg->categories_tree_model, iter,
|
|
+ PAGE_NUM_COLUMN,
|
|
+ &value);
|
|
+
|
|
+ page_num = g_value_get_int (&value);
|
|
+
|
|
+ g_value_unset (&value);
|
|
+
|
|
+ if (page_num == last_selected_page_num)
|
|
+ {
|
|
+ GtkTreeSelection *selection;
|
|
+
|
|
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (oPrefsDlg->categories_tree));
|
|
+
|
|
+ gtk_tree_selection_select_iter (selection, iter);
|
|
+
|
|
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (oPrefsDlg->notebook), page_num);
|
|
+
|
|
+ return TRUE;
|
|
+ }
|
|
+ return FALSE;
|
|
+}
|
|
+
|
|
+void PrefsDlg::categories_tree_realize (GtkWidget *widget, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ gtk_tree_view_expand_all(GTK_TREE_VIEW(widget));
|
|
+
|
|
+ gtk_tree_model_foreach(oPrefsDlg->categories_tree_model,
|
|
+ GtkTreeModelForeachFunc(selection_init),
|
|
+ oPrefsDlg);
|
|
+}
|
|
+
|
|
+void PrefsDlg::create_categories_tree(void)
|
|
+{
|
|
+ GtkWidget *sw;
|
|
+ GtkTreeModel *model;
|
|
+ GtkWidget *treeview;
|
|
+ GtkCellRenderer *renderer;
|
|
+ GtkTreeSelection *selection;
|
|
+ GtkTreeViewColumn *column;
|
|
+ gint col_offset;
|
|
+
|
|
+ sw = gtk_scrolled_window_new (NULL, NULL);
|
|
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
|
|
+ GTK_SHADOW_ETCHED_IN);
|
|
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
|
|
+ GTK_POLICY_AUTOMATIC,
|
|
+ GTK_POLICY_AUTOMATIC);
|
|
+
|
|
+ gtk_widget_set_size_request (sw, 140, 240);
|
|
+
|
|
+ model = create_categories_tree_model ();
|
|
+
|
|
+ treeview = gtk_tree_view_new_with_model (model);
|
|
+ g_object_unref (G_OBJECT (model));
|
|
+ gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
|
|
+
|
|
+ categories_tree = treeview;
|
|
+ categories_tree_model = model;
|
|
+
|
|
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
|
|
+
|
|
+ gtk_tree_selection_set_mode (selection,
|
|
+ GTK_SELECTION_SINGLE);
|
|
+
|
|
+ /* add column for category */
|
|
+ renderer = gtk_cell_renderer_text_new ();
|
|
+ g_object_set (G_OBJECT (renderer), "xalign", 0.0, NULL);
|
|
+
|
|
+ col_offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
|
|
+ -1, _("Categories"),
|
|
+ renderer, "text",
|
|
+ CATEGORY_COLUMN,
|
|
+ NULL);
|
|
+
|
|
+ column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), col_offset - 1);
|
|
+ gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), FALSE);
|
|
+
|
|
+ g_signal_connect (selection, "changed",
|
|
+ G_CALLBACK (categories_tree_selection_cb),
|
|
+ this);
|
|
+
|
|
+ gtk_container_add (GTK_CONTAINER (sw), treeview);
|
|
+
|
|
+ g_signal_connect (G_OBJECT (treeview), "realize",
|
|
+ G_CALLBACK (categories_tree_realize),
|
|
+ this);
|
|
+
|
|
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
|
|
+
|
|
+ categories_window=sw;
|
|
+}
|
|
+
|
|
+void PrefsDlg::setup_logo_page()
|
|
+{
|
|
+ GtkWidget *image = gtk_image_new_from_pixbuf(stardict_logo);
|
|
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook),image,NULL);
|
|
+}
|
|
+#endif
|
|
+
|
|
+static GtkWidget *prepare_page(GtkNotebook *notebook, const gchar *caption,
|
|
+ const gchar *stock_id)
|
|
+{
|
|
+ GtkWidget *vbox = gtk_vbox_new(FALSE, 12);
|
|
+#ifdef CONFIG_GPE
|
|
+ gtk_container_set_border_width(GTK_CONTAINER (vbox), 5);
|
|
+ GtkWidget *nb_label = gtk_label_new(caption);
|
|
+ gtk_notebook_append_page(notebook, vbox, nb_label);
|
|
+#else
|
|
+ gtk_notebook_append_page(notebook, vbox, NULL);
|
|
+#endif
|
|
+
|
|
+ GtkWidget *vbox1 = gtk_vbox_new(FALSE, 6);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox), vbox1, FALSE, FALSE, 6);
|
|
+ GtkWidget *hbox = gtk_hbox_new(FALSE, 6);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1), hbox, FALSE, FALSE, 0);
|
|
+ GtkWidget *image =
|
|
+ gtk_image_new_from_stock(stock_id,
|
|
+ GTK_ICON_SIZE_LARGE_TOOLBAR);
|
|
+ gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);
|
|
+ GtkWidget *label = gtk_label_new(NULL);
|
|
+ glib::CharStr label_caption(
|
|
+ g_markup_printf_escaped("<span weight=\"bold\" size=\"x-large\">%s</span>", caption));
|
|
+ gtk_label_set_markup(GTK_LABEL(label), get_impl(label_caption));
|
|
+ gtk_box_pack_start(GTK_BOX(hbox),label, FALSE, FALSE, 0);
|
|
+ GtkWidget *hseparator = gtk_hseparator_new();
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),hseparator,FALSE,FALSE,0);
|
|
+
|
|
+ return vbox;
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_dictionary_scan_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ gboolean b = gtk_toggle_button_get_active(button);
|
|
+ gtk_widget_set_sensitive(oPrefsDlg->scan_modifier_key_vbox,b);
|
|
+ conf->set_bool_at("dictionary/only_scan_while_modifier_key", b);
|
|
+}
|
|
+
|
|
+#ifdef _WIN32
|
|
+void PrefsDlg::on_setup_dictionary_scan_clipboard_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ gboolean b = gtk_toggle_button_get_active(button);
|
|
+ if (b) {
|
|
+ if (conf->get_bool_at("dictionary/scan_selection"))
|
|
+ gpAppFrame->oClipboard.start();
|
|
+ } else {
|
|
+ if (conf->get_bool_at("dictionary/scan_selection"))
|
|
+ gpAppFrame->oClipboard.stop();
|
|
+ }
|
|
+ conf->set_bool_at("dictionary/scan_clipboard", b);
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_dictionary_use_scan_hotkey_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ gboolean b = gtk_toggle_button_get_active(button);
|
|
+ if (b)
|
|
+ gpAppFrame->oHotkey.start_scan();
|
|
+ else
|
|
+ gpAppFrame->oHotkey.stop_scan();
|
|
+ conf->set_bool_at("dictionary/use_scan_hotkey", b);
|
|
+}
|
|
+#endif
|
|
+
|
|
+void PrefsDlg::on_setup_dictionary_scan_combobox_changed(GtkComboBox *combobox, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ gint key = gtk_combo_box_get_active(combobox);
|
|
+ conf->set_int_at("dictionary/scan_modifier_key", key);
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_dictionary_scan_hide_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ gboolean hide = gtk_toggle_button_get_active(button);
|
|
+ conf->set_bool_at("dictionary/hide_floatwin_when_modifier_key_released", hide);
|
|
+}
|
|
+
|
|
+void PrefsDlg::setup_dictionary_scan_page()
|
|
+{
|
|
+ GtkWidget *vbox = prepare_page(GTK_NOTEBOOK(notebook), _("Scan Selection"), GTK_STOCK_CONVERT);
|
|
+ GtkWidget *vbox1 = gtk_vbox_new(false, 0);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox),vbox1,false,false, 0);
|
|
+ GtkWidget *check_button = gtk_check_button_new_with_mnemonic(_("_Only scan while the modifier key is being pressed."));
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),check_button,false,false,0);
|
|
+ bool only_scan_while_modifier_key=
|
|
+ conf->get_bool_at("dictionary/only_scan_while_modifier_key");
|
|
+
|
|
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button),
|
|
+ only_scan_while_modifier_key);
|
|
+ g_signal_connect(G_OBJECT(check_button), "toggled",
|
|
+ G_CALLBACK(on_setup_dictionary_scan_ckbutton_toggled), this);
|
|
+
|
|
+ scan_modifier_key_vbox = gtk_vbox_new(FALSE, 6);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1), scan_modifier_key_vbox,
|
|
+ FALSE, FALSE, 12);
|
|
+ gtk_widget_set_sensitive(scan_modifier_key_vbox,
|
|
+ only_scan_while_modifier_key);
|
|
+
|
|
+ check_button = gtk_check_button_new_with_mnemonic(_("H_ide floating window when modifier key released."));
|
|
+ gtk_box_pack_start(GTK_BOX(scan_modifier_key_vbox),check_button,false,false,0);
|
|
+
|
|
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button),
|
|
+ conf->get_bool_at("dictionary/hide_floatwin_when_modifier_key_released"));
|
|
+ g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (on_setup_dictionary_scan_hide_ckbutton_toggled), this);
|
|
+
|
|
+ GtkWidget *hbox = gtk_hbox_new(false, 12);
|
|
+ gtk_box_pack_start(GTK_BOX(scan_modifier_key_vbox), hbox,false,false,0);
|
|
+ GtkWidget *label=gtk_label_new(NULL);
|
|
+ gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), _("Scan modifier _key:"));
|
|
+ gtk_box_pack_start(GTK_BOX(hbox),label,false,false,0);
|
|
+ gtk_misc_set_alignment (GTK_MISC (label), 0, .5);
|
|
+ GtkWidget *combobox = gtk_combo_box_new_text();
|
|
+ gtk_combo_box_set_focus_on_click(GTK_COMBO_BOX(combobox), FALSE);
|
|
+
|
|
+ for (std::list<std::string>::const_iterator p=key_combs.begin();
|
|
+ p!=key_combs.end(); ++p) {
|
|
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), p->c_str());
|
|
+ }
|
|
+
|
|
+ int scan_modifier_key=
|
|
+ conf->get_int_at("dictionary/scan_modifier_key");
|
|
+
|
|
+ gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), scan_modifier_key);
|
|
+
|
|
+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), combobox);
|
|
+ gtk_box_pack_start(GTK_BOX(hbox), combobox, FALSE, FALSE, 0);
|
|
+ g_signal_connect (G_OBJECT (combobox), "changed", G_CALLBACK (on_setup_dictionary_scan_combobox_changed), this);
|
|
+
|
|
+#ifdef _WIN32
|
|
+ check_button = gtk_check_button_new_with_mnemonic(_("_Scan clipboard."));
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),check_button,false,false,0);
|
|
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), conf->get_bool_at("dictionary/scan_clipboard"));
|
|
+ g_signal_connect(G_OBJECT(check_button), "toggled",
|
|
+ G_CALLBACK(on_setup_dictionary_scan_clipboard_ckbutton_toggled), this);
|
|
+
|
|
+ check_button = gtk_check_button_new_with_mnemonic(_("_Use scan hotkey: Ctrl+Alt+F1."));
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),check_button,false,false,0);
|
|
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), conf->get_bool_at("dictionary/use_scan_hotkey"));
|
|
+ g_signal_connect(G_OBJECT(check_button), "toggled",
|
|
+ G_CALLBACK(on_setup_dictionary_use_scan_hotkey_ckbutton_toggled), this);
|
|
+#endif
|
|
+}
|
|
+
|
|
+void PrefsDlg::change_font_for_all_widgets(const std::string& fontname)
|
|
+{
|
|
+ gchar *aa =
|
|
+ g_strdup_printf("style \"custom-font\" { font_name= \"%s\" }\n"
|
|
+ "class \"GtkWidget\" style \"custom-font\"\n", fontname.c_str());
|
|
+ gtk_rc_parse_string(aa);
|
|
+ g_free(aa);
|
|
+ GdkScreen *screen = gtk_window_get_screen(parent_window);
|
|
+ GtkSettings *settings=gtk_settings_get_for_screen(screen);
|
|
+ gtk_rc_reset_styles(settings);
|
|
+#ifndef CONFIG_GPE
|
|
+ resize_categories_tree();
|
|
+#endif
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_dictionary_font_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ gboolean b = gtk_toggle_button_get_active(button);
|
|
+ gtk_widget_set_sensitive(oPrefsDlg->custom_font_hbox, b);
|
|
+ conf->set_bool_at("dictionary/use_custom_font", b);
|
|
+ if (b) {
|
|
+ const std::string &custom_font=
|
|
+ conf->get_string_at("dictionary/custom_font");
|
|
+ oPrefsDlg->change_font_for_all_widgets(custom_font);
|
|
+ } else
|
|
+ oPrefsDlg->change_font_for_all_widgets("");
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_dictionary_font_button_clicked(GtkWidget *widget, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ GtkWidget *dlg = gtk_font_selection_dialog_new(_("Choose dictionary font"));
|
|
+ gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (oPrefsDlg->window));
|
|
+ const gchar *text = gtk_button_get_label(GTK_BUTTON(widget));
|
|
+ if (strcmp(text,_("Choose")))
|
|
+ gtk_font_selection_dialog_set_font_name(GTK_FONT_SELECTION_DIALOG(dlg), text);
|
|
+ gtk_font_selection_dialog_set_preview_text(GTK_FONT_SELECTION_DIALOG(dlg),_("Dictionary font"));
|
|
+ gint result = gtk_dialog_run (GTK_DIALOG (dlg));
|
|
+ if (result==GTK_RESPONSE_OK) {
|
|
+ gchar *font_name =
|
|
+ gtk_font_selection_dialog_get_font_name(GTK_FONT_SELECTION_DIALOG(dlg));
|
|
+ if (font_name) {
|
|
+ gtk_button_set_label(GTK_BUTTON(widget),font_name);
|
|
+ conf->set_string_at("dictionary/custom_font", std::string(font_name));
|
|
+ }
|
|
+ if (font_name && font_name[0]) {
|
|
+ oPrefsDlg->change_font_for_all_widgets(font_name);
|
|
+ }
|
|
+ }
|
|
+ gtk_widget_destroy (dlg);
|
|
+}
|
|
+
|
|
+void PrefsDlg::setup_dictionary_font_page()
|
|
+{
|
|
+ GtkWidget *vbox = prepare_page(GTK_NOTEBOOK(notebook), _("Font"), GTK_STOCK_SELECT_FONT);
|
|
+ GtkWidget *vbox1 = gtk_vbox_new(false,6);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox),vbox1,false,false, 0);
|
|
+ GtkWidget *check_button = gtk_check_button_new_with_mnemonic(_("_Use custom font."));
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),check_button,false,false,0);
|
|
+ bool use_custom_font=
|
|
+ conf->get_bool_at("dictionary/use_custom_font");
|
|
+
|
|
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button),
|
|
+ use_custom_font);
|
|
+ g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (on_setup_dictionary_font_ckbutton_toggled), this);
|
|
+ custom_font_hbox = gtk_hbox_new(false, 12);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),custom_font_hbox,false,false,0);
|
|
+ gtk_widget_set_sensitive(custom_font_hbox, use_custom_font);
|
|
+ GtkWidget *label=gtk_label_new(NULL);
|
|
+ gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), _("Dictionary _font:"));
|
|
+ gtk_box_pack_start(GTK_BOX(custom_font_hbox),label,false,false,0);
|
|
+ gtk_misc_set_alignment (GTK_MISC (label), 0, .5);
|
|
+ GtkWidget *button;
|
|
+ const std::string &custom_font=
|
|
+ conf->get_string_at("dictionary/custom_font");
|
|
+
|
|
+ if (!custom_font.empty())
|
|
+ button = gtk_button_new_with_label(custom_font.c_str());
|
|
+ else
|
|
+ button=gtk_button_new_with_label(_("Choose"));
|
|
+
|
|
+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), button);
|
|
+ gtk_box_pack_start(GTK_BOX(custom_font_hbox),button,false,false,0);
|
|
+ g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (on_setup_dictionary_font_button_clicked), this);
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_dictionary_cache_CreateCacheFile_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ gboolean enable = gtk_toggle_button_get_active(button);
|
|
+ conf->set_bool_at("dictionary/create_cache_file",enable);
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_dictionary_cache_EnableCollation_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ gboolean enable = gtk_toggle_button_get_active(button);
|
|
+ gtk_widget_set_sensitive(oPrefsDlg->collation_hbox, enable);
|
|
+ conf->set_bool_at("dictionary/enable_collation",enable);
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_dictionary_collation_combobox_changed(GtkComboBox *combobox, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ gint key = gtk_combo_box_get_active(combobox);
|
|
+ conf->set_int_at("dictionary/collate_function", key);
|
|
+}
|
|
+
|
|
+static void clean_dir(const gchar *dirname)
|
|
+{
|
|
+ GDir *dir = g_dir_open(dirname, 0, NULL);
|
|
+ if (dir) {
|
|
+ const gchar *filename;
|
|
+ gchar fullfilename[256];
|
|
+ while ((filename = g_dir_read_name(dir))!=NULL) {
|
|
+ sprintf(fullfilename, "%s" G_DIR_SEPARATOR_S "%s", dirname, filename);
|
|
+ if (g_file_test(fullfilename, G_FILE_TEST_IS_DIR)) {
|
|
+ clean_dir(fullfilename);
|
|
+ } else if (g_str_has_suffix(filename,".oft") || g_str_has_suffix(filename,".clt")) {
|
|
+ g_unlink(fullfilename);
|
|
+ }
|
|
+ }
|
|
+ g_dir_close(dir);
|
|
+ }
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_dictionary_cache_cleanbutton_clicked(GtkWidget *widget, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ std::string dirname = gStarDictDataDir+ G_DIR_SEPARATOR_S "dic";
|
|
+ clean_dir(dirname.c_str());
|
|
+ dirname = g_get_user_cache_dir();
|
|
+ dirname += G_DIR_SEPARATOR_S "stardict";
|
|
+ clean_dir(dirname.c_str());
|
|
+ g_rmdir(dirname.c_str());
|
|
+}
|
|
+
|
|
+void PrefsDlg::setup_dictionary_cache_page()
|
|
+{
|
|
+ GtkWidget *vbox = prepare_page(GTK_NOTEBOOK(notebook), _("Cache"), GTK_STOCK_HARDDISK);
|
|
+ GtkWidget *vbox1 = gtk_vbox_new(false, 6);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox),vbox1,false,false, 0);
|
|
+ GtkWidget *check_button;
|
|
+ check_button = gtk_check_button_new_with_mnemonic(_("Create c_ache files to speed up loading."));
|
|
+ bool enable = conf->get_bool_at("dictionary/create_cache_file");
|
|
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), enable);
|
|
+ g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (on_setup_dictionary_cache_CreateCacheFile_ckbutton_toggled), (gpointer)this);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),check_button,false,false,0);
|
|
+ check_button = gtk_check_button_new_with_mnemonic(_("_Sort word list by collation function."));
|
|
+ enable = conf->get_bool_at("dictionary/enable_collation");
|
|
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), enable);
|
|
+ g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (on_setup_dictionary_cache_EnableCollation_ckbutton_toggled), (gpointer)this);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),check_button,false,false,0);
|
|
+ collation_hbox = gtk_hbox_new(false,6);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),collation_hbox,false,false,0);
|
|
+ GtkWidget *label=gtk_label_new(NULL);
|
|
+ gtk_misc_set_alignment (GTK_MISC (label), 0, .5);
|
|
+ gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), _("\tCollation _function:"));
|
|
+ gtk_box_pack_start(GTK_BOX(collation_hbox),label,false,false,0);
|
|
+ GtkWidget *combobox = gtk_combo_box_new_text();
|
|
+ gtk_combo_box_set_focus_on_click(GTK_COMBO_BOX(combobox), FALSE);
|
|
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_general_ci");
|
|
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_unicode_ci");
|
|
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_bin");
|
|
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_czech_ci");
|
|
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_danish_ci");
|
|
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_esperanto_ci");
|
|
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_estonian_ci");
|
|
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_hungarian_ci");
|
|
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_icelandic_ci");
|
|
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_latvian_ci");
|
|
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_lithuanian_ci");
|
|
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_persian_ci");
|
|
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_polish_ci");
|
|
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_roman_ci");
|
|
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_romanian_ci");
|
|
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_slovak_ci");
|
|
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_slovenian_ci");
|
|
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_spanish_ci");
|
|
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_spanish2_ci");
|
|
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_swedish_ci");
|
|
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_turkish_ci");
|
|
+ int collate_function = conf->get_int_at("dictionary/collate_function");
|
|
+ gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), collate_function);
|
|
+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), combobox);
|
|
+ gtk_box_pack_start(GTK_BOX(collation_hbox), combobox, FALSE, FALSE, 0);
|
|
+ g_signal_connect (G_OBJECT (combobox), "changed", G_CALLBACK (on_setup_dictionary_collation_combobox_changed), this);
|
|
+ gtk_widget_set_sensitive(collation_hbox, enable);
|
|
+
|
|
+ label = gtk_label_new(_("After enabled collation, when load the dictionaries for the first time, it will take some time for sorting, please wait for a moment."));
|
|
+ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),label,false,false,0);
|
|
+
|
|
+ GtkWidget *hbox = gtk_hbox_new(false,6);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),hbox,false,false,0);
|
|
+ GtkWidget *button = gtk_button_new_with_mnemonic(_("C_lean all cache files"));
|
|
+ gtk_button_set_image(GTK_BUTTON(button), gtk_image_new_from_stock(GTK_STOCK_CLEAR, GTK_ICON_SIZE_BUTTON));
|
|
+ gtk_box_pack_end(GTK_BOX(hbox),button,false,false,0);
|
|
+ g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (on_setup_dictionary_cache_cleanbutton_clicked), this);
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
+void PrefsDlg::on_setup_dictionary_export_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ gboolean enable = gtk_toggle_button_get_active(button);
|
|
+ conf->set_bool_at("dictionary/only_export_word", enable);
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_dictionary_export_browse_button_clicked(GtkButton *button, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ GtkWidget *dialog;
|
|
+ dialog = gtk_file_chooser_dialog_new (_("Open file..."),
|
|
+ GTK_WINDOW(oPrefsDlg->window),
|
|
+ GTK_FILE_CHOOSER_ACTION_OPEN,
|
|
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
|
+ GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
|
|
+ NULL);
|
|
+ gtk_file_chooser_set_filename(GTK_FILE_CHOOSER (dialog), gtk_entry_get_text(oPrefsDlg->eExportFile));
|
|
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
|
|
+ gchar *filename;
|
|
+ filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
|
|
+ gtk_entry_set_text(oPrefsDlg->eExportFile, filename);
|
|
+ g_free (filename);
|
|
+ }
|
|
+ gtk_widget_destroy (dialog);
|
|
+}
|
|
+
|
|
+void PrefsDlg::setup_dictionary_export_page()
|
|
+{
|
|
+ GtkWidget *vbox = prepare_page(GTK_NOTEBOOK(notebook), _("Export"), GTK_STOCK_SAVE);
|
|
+ GtkWidget *vbox1 = gtk_vbox_new(false, 6);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox),vbox1,false,false, 0);
|
|
+
|
|
+ GtkWidget *check_button;
|
|
+ check_button = gtk_check_button_new_with_mnemonic(_("_Only export words."));
|
|
+ bool enable= conf->get_bool_at("dictionary/only_export_word");
|
|
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), enable);
|
|
+ g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (on_setup_dictionary_export_ckbutton_toggled), this);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),check_button,false,false,0);
|
|
+
|
|
+ GtkWidget *hbox1 = gtk_hbox_new(FALSE, 6);
|
|
+ GtkWidget *label=gtk_label_new(_("File name:"));
|
|
+ gtk_box_pack_start(GTK_BOX(hbox1), label, FALSE, FALSE, 0);
|
|
+ GtkWidget *e = gtk_entry_new();
|
|
+ const std::string &exportfile= conf->get_string_at("dictionary/export_file");
|
|
+ gtk_entry_set_text(GTK_ENTRY(e), exportfile.c_str());
|
|
+ gtk_box_pack_start(GTK_BOX(hbox1), e, TRUE, TRUE, 0);
|
|
+ eExportFile=GTK_ENTRY(e);
|
|
+
|
|
+ GtkWidget *button;
|
|
+ button = gtk_button_new_with_mnemonic(_("_Browse..."));
|
|
+ GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS);
|
|
+ g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(on_setup_dictionary_export_browse_button_clicked), this);
|
|
+ gtk_box_pack_start (GTK_BOX (hbox1), button, FALSE, FALSE, 0);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, FALSE, 0);
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_markup_search_word(GtkToggleButton *button, PrefsDlg *)
|
|
+{
|
|
+ conf->set_bool_at("dictionary/markup_search_word",
|
|
+ gtk_toggle_button_get_active(button));
|
|
+}
|
|
+
|
|
+void PrefsDlg::setup_dict_article_rendering()
|
|
+{
|
|
+ GtkWidget *vbox = prepare_page(GTK_NOTEBOOK(notebook), _("Article rendering"),
|
|
+ GTK_STOCK_CONVERT);
|
|
+ GtkWidget *vbox1 = gtk_vbox_new(FALSE, 6);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox), vbox1, FALSE, FALSE, 0);
|
|
+
|
|
+ GtkWidget *ck_btn =
|
|
+ gtk_check_button_new_with_mnemonic(_("_Highlight search term"));
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1), ck_btn, FALSE, FALSE, 0);
|
|
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ck_btn),
|
|
+ conf->get_bool_at("dictionary/markup_search_word"));
|
|
+ g_signal_connect(G_OBJECT(ck_btn), "toggled",
|
|
+ G_CALLBACK(on_markup_search_word), this);
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_dictionary_sound_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ gboolean enable = gtk_toggle_button_get_active(button);
|
|
+ conf->set_bool_at("dictionary/enable_sound_event",enable);
|
|
+}
|
|
+
|
|
+#ifndef _WIN32
|
|
+void PrefsDlg::on_setup_dictionary_use_tts_program_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ gboolean enable = gtk_toggle_button_get_active(button);
|
|
+ gtk_widget_set_sensitive(oPrefsDlg->use_tts_program_hbox,enable);
|
|
+ conf->set_bool("/apps/stardict/preferences/dictionary/use_tts_program", enable);
|
|
+ gpAppFrame->oReadWord.use_command_tts = enable;
|
|
+ gpAppFrame->oMidWin.oToolWin.UpdatePronounceMenu();
|
|
+}
|
|
+#endif
|
|
+
|
|
+void PrefsDlg::setup_dictionary_sound_page()
|
|
+{
|
|
+ GtkWidget *vbox = prepare_page(GTK_NOTEBOOK(notebook), _("Sound"), GTK_STOCK_YES);
|
|
+ GtkWidget *vbox1 = gtk_vbox_new(false, 6);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox),vbox1,false,false, 0);
|
|
+
|
|
+ GtkWidget *check_button;
|
|
+ check_button = gtk_check_button_new_with_mnemonic(_("_Enable sound event."));
|
|
+ bool enable=
|
|
+ conf->get_bool_at("dictionary/enable_sound_event");
|
|
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), enable);
|
|
+ g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (on_setup_dictionary_sound_ckbutton_toggled), (gpointer)this);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),check_button,false,false,0);
|
|
+ GtkWidget *label;
|
|
+#if defined(CONFIG_GTK) || defined(CONFIG_GPE)
|
|
+ GtkWidget *hbox2 = gtk_hbox_new(FALSE, 6);
|
|
+ label=gtk_label_new(_("Command for playing wav files:"));
|
|
+ gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
|
|
+ GtkWidget *e = gtk_entry_new();
|
|
+ gtk_widget_set_size_request(e, 50, -1);
|
|
+ const std::string &playcmd=
|
|
+ conf->get_string_at("dictionary/play_command");
|
|
+ gtk_entry_set_text(GTK_ENTRY(e), playcmd.c_str());
|
|
+ gtk_box_pack_start(GTK_BOX(hbox2), e, TRUE, TRUE, 0);
|
|
+ gtk_widget_set_sensitive(hbox2, enable);
|
|
+ ePlayCommand=GTK_ENTRY(e);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1), hbox2, FALSE, FALSE, 0);
|
|
+#endif
|
|
+
|
|
+ label = gtk_label_new(_("RealPeopleTTS search path:"));
|
|
+ gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),label,false,false,0);
|
|
+ tts_textview = gtk_text_view_new();
|
|
+ gtk_widget_set_size_request(tts_textview, -1, 70);
|
|
+ gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(tts_textview), GTK_WRAP_CHAR);
|
|
+ const std::string &ttspath = conf->get_string_at("dictionary/tts_path");
|
|
+ GtkTextBuffer *text_view_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tts_textview));
|
|
+ gtk_text_buffer_set_text(text_view_buffer, ttspath.c_str(), -1);
|
|
+ GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
|
|
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
|
|
+ GTK_SHADOW_ETCHED_IN);
|
|
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
|
|
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
|
+ gtk_container_add(GTK_CONTAINER(scrolled_window), tts_textview);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),scrolled_window,false,false,0);
|
|
+
|
|
+#ifndef _WIN32
|
|
+ check_button = gtk_check_button_new_with_mnemonic(_("_Use TTS program."));
|
|
+ enable = conf->get_bool("/apps/stardict/preferences/dictionary/use_tts_program");
|
|
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), enable);
|
|
+ g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (on_setup_dictionary_use_tts_program_ckbutton_toggled), this);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),check_button,false,false,0);
|
|
+ use_tts_program_hbox = gtk_hbox_new(FALSE, 6);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),use_tts_program_hbox,false,false,0);
|
|
+ gtk_widget_set_sensitive(use_tts_program_hbox,enable);
|
|
+ label = gtk_label_new(_("Commandline:"));
|
|
+ gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
|
|
+ gtk_box_pack_start(GTK_BOX(use_tts_program_hbox),label,false,false,0);
|
|
+ GtkWidget *comboboxentry = gtk_combo_box_entry_new_text();
|
|
+ gtk_widget_set_size_request(comboboxentry, 30, -1);
|
|
+ gtk_combo_box_append_text(GTK_COMBO_BOX(comboboxentry), "echo %s | festival --tts &");
|
|
+ gtk_combo_box_append_text(GTK_COMBO_BOX(comboboxentry), "espeak %s &");
|
|
+ eTTSCommandline = GTK_ENTRY(GTK_BIN(comboboxentry)->child);
|
|
+ const std::string &tts_program_cmdline = conf->get_string("/apps/stardict/preferences/dictionary/tts_program_cmdline");
|
|
+ gtk_entry_set_text(eTTSCommandline, tts_program_cmdline.c_str());
|
|
+ gtk_box_pack_start(GTK_BOX(use_tts_program_hbox),comboboxentry,true,true,0);
|
|
+#endif
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_network_netdict_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ conf->set_bool_at("network/enable_netdict",
|
|
+ gtk_toggle_button_get_active(button));
|
|
+}
|
|
+
|
|
+static void on_account_passwd_entry_activated(GtkEntry *entry, GtkDialog *dialog)
|
|
+{
|
|
+ gtk_dialog_response(dialog, GTK_RESPONSE_OK);
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_network_account_button_clicked(GtkWidget *widget, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ GtkWidget *account_dialog;
|
|
+ account_dialog =
|
|
+ gtk_dialog_new_with_buttons (_("Account"),
|
|
+ GTK_WINDOW (oPrefsDlg->window),
|
|
+ GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
+ GTK_STOCK_CANCEL,
|
|
+ GTK_RESPONSE_CANCEL,
|
|
+ GTK_STOCK_OK,
|
|
+ GTK_RESPONSE_OK,
|
|
+ NULL);
|
|
+ GtkWidget *table = gtk_table_new(2, 2, FALSE);
|
|
+ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(account_dialog)->vbox), table);
|
|
+ gtk_container_set_border_width(GTK_CONTAINER(table), 6);
|
|
+ GtkWidget *label = gtk_label_new_with_mnemonic(_("_User Name:"));
|
|
+ gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
|
|
+ GtkWidget *user_entry = gtk_entry_new ();
|
|
+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), user_entry);
|
|
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, (GtkAttachOptions)0, 6, 4);
|
|
+ gtk_table_attach(GTK_TABLE(table), user_entry, 1, 2, 0, 1, GTK_EXPAND, (GtkAttachOptions)0, 0, 4);
|
|
+ label = gtk_label_new_with_mnemonic(_("_Password:"));
|
|
+ gtk_misc_set_alignment (GTK_MISC (label), 0, .5);
|
|
+ GtkWidget *passwd_entry = gtk_entry_new ();
|
|
+ gtk_entry_set_visibility(GTK_ENTRY(passwd_entry), FALSE);
|
|
+ g_signal_connect(G_OBJECT(passwd_entry),"activate", G_CALLBACK(on_account_passwd_entry_activated), account_dialog);
|
|
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), passwd_entry);
|
|
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, (GtkAttachOptions)0, 6, 4);
|
|
+ gtk_table_attach(GTK_TABLE(table), passwd_entry, 1, 2, 1, 2, GTK_EXPAND, (GtkAttachOptions)0, 0, 4);
|
|
+ gtk_dialog_set_default_response(GTK_DIALOG(account_dialog), GTK_RESPONSE_OK);
|
|
+ gtk_window_set_resizable(GTK_WINDOW(account_dialog), FALSE);
|
|
+ gtk_widget_show_all(GTK_WIDGET(account_dialog));
|
|
+ while (gtk_dialog_run(GTK_DIALOG(account_dialog))==GTK_RESPONSE_OK) {
|
|
+ const gchar *user = gtk_entry_get_text(GTK_ENTRY(user_entry));
|
|
+ if (!user[0]) {
|
|
+ conf->set_string_at("network/user", "");
|
|
+ conf->set_string_at("network/md5passwd", "");
|
|
+ gtk_button_set_label(oPrefsDlg->bAccount, "Guest");
|
|
+ gpAppFrame->oStarDictClient.set_auth("", "");
|
|
+ break;
|
|
+ }
|
|
+ gchar *error_msg = NULL;
|
|
+ const gchar *passwd = gtk_entry_get_text(GTK_ENTRY(passwd_entry));
|
|
+ if (!passwd[0])
|
|
+ error_msg = _("Please input the password.");
|
|
+ if (error_msg) {
|
|
+ GtkWidget *message_dlg =
|
|
+ gtk_message_dialog_new(
|
|
+ GTK_WINDOW(account_dialog),
|
|
+ (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
|
|
+ GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
|
|
+ error_msg);
|
|
+ gtk_dialog_set_default_response(GTK_DIALOG(message_dlg), GTK_RESPONSE_OK);
|
|
+ gtk_window_set_resizable(GTK_WINDOW(message_dlg), FALSE);
|
|
+ gtk_dialog_run(GTK_DIALOG(message_dlg));
|
|
+ gtk_widget_destroy(message_dlg);
|
|
+ continue;
|
|
+ }
|
|
+ conf->set_string_at("network/user", user);
|
|
+ struct MD5Context ctx;
|
|
+ unsigned char digest[16];
|
|
+ MD5Init(&ctx);
|
|
+ MD5Update(&ctx, (const unsigned char*)passwd, strlen(passwd));
|
|
+ MD5Final(digest, &ctx );
|
|
+ char hex[33];
|
|
+ for (int i = 0; i < 16; i++)
|
|
+ sprintf( hex+2*i, "%02x", digest[i] );
|
|
+ hex[32] = '\0';
|
|
+ conf->set_string_at("network/md5passwd", hex);
|
|
+ gtk_button_set_label(oPrefsDlg->bAccount, user);
|
|
+ gpAppFrame->oStarDictClient.set_auth(user, hex);
|
|
+ break;
|
|
+ }
|
|
+ gtk_widget_destroy(account_dialog);
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_register_end(const char *msg)
|
|
+{
|
|
+ gtk_button_set_label(bAccount, register_user.c_str());
|
|
+ conf->set_string_at("network/user", register_user);
|
|
+ conf->set_string_at("network/md5passwd", register_hex);
|
|
+ gpAppFrame->oStarDictClient.set_auth(register_user.c_str(), register_hex.c_str());
|
|
+
|
|
+ GtkWidget *message_dlg = gtk_message_dialog_new(GTK_WINDOW(window),
|
|
+ (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
|
|
+ GTK_MESSAGE_INFO, GTK_BUTTONS_OK, msg);
|
|
+ gtk_dialog_set_default_response(GTK_DIALOG(message_dlg), GTK_RESPONSE_OK);
|
|
+ gtk_window_set_resizable(GTK_WINDOW(message_dlg), FALSE);
|
|
+ g_signal_connect_swapped (message_dlg, "response", G_CALLBACK (gtk_widget_destroy), message_dlg);
|
|
+ gtk_widget_show(message_dlg);
|
|
+}
|
|
+
|
|
+static void on_register_email_button_activated(GtkEntry *entry, GtkDialog *dialog)
|
|
+{
|
|
+ gtk_dialog_response(dialog, GTK_RESPONSE_OK);
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_network_register_button_clicked(GtkWidget *widget, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ GtkWidget *register_dialog;
|
|
+ register_dialog =
|
|
+ gtk_dialog_new_with_buttons (_("Register"),
|
|
+ GTK_WINDOW (oPrefsDlg->window),
|
|
+ GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
+ GTK_STOCK_CANCEL,
|
|
+ GTK_RESPONSE_CANCEL,
|
|
+ GTK_STOCK_OK,
|
|
+ GTK_RESPONSE_OK,
|
|
+ NULL);
|
|
+ GtkWidget *table = gtk_table_new(3, 2, FALSE);
|
|
+ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(register_dialog)->vbox), table);
|
|
+ gtk_container_set_border_width(GTK_CONTAINER(table), 6);
|
|
+ GtkWidget *label = gtk_label_new_with_mnemonic(_("_User Name:"));
|
|
+ gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
|
|
+ GtkWidget *user_entry = gtk_entry_new ();
|
|
+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), user_entry);
|
|
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, (GtkAttachOptions)0, 6, 4);
|
|
+ gtk_table_attach(GTK_TABLE(table), user_entry, 1, 2, 0, 1, GTK_EXPAND, (GtkAttachOptions)0, 0, 4);
|
|
+ label = gtk_label_new_with_mnemonic(_("_Password:"));
|
|
+ gtk_misc_set_alignment (GTK_MISC (label), 0, .5);
|
|
+ GtkWidget *passwd_entry = gtk_entry_new ();
|
|
+ gtk_entry_set_visibility(GTK_ENTRY(passwd_entry), FALSE);
|
|
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), passwd_entry);
|
|
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, (GtkAttachOptions)0, 6, 4);
|
|
+ gtk_table_attach(GTK_TABLE(table), passwd_entry, 1, 2, 1, 2, GTK_EXPAND, (GtkAttachOptions)0, 0, 4);
|
|
+ label = gtk_label_new_with_mnemonic(_("_Email:"));
|
|
+ gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
|
|
+ GtkWidget *email_entry = gtk_entry_new ();
|
|
+ g_signal_connect(G_OBJECT(email_entry),"activate", G_CALLBACK(on_register_email_button_activated), register_dialog);
|
|
+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), email_entry);
|
|
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL, (GtkAttachOptions)0, 6, 4);
|
|
+ gtk_table_attach(GTK_TABLE(table), email_entry, 1, 2, 2, 3, GTK_EXPAND, (GtkAttachOptions)0, 0, 4);
|
|
+ gtk_dialog_set_default_response(GTK_DIALOG(register_dialog), GTK_RESPONSE_OK);
|
|
+ gtk_window_set_resizable(GTK_WINDOW(register_dialog), FALSE);
|
|
+ gtk_widget_show_all(GTK_WIDGET(register_dialog));
|
|
+ while (gtk_dialog_run(GTK_DIALOG(register_dialog))==GTK_RESPONSE_OK) {
|
|
+ gchar *error_msg = NULL;
|
|
+ const gchar *user = gtk_entry_get_text(GTK_ENTRY(user_entry));
|
|
+ const gchar *passwd = gtk_entry_get_text(GTK_ENTRY(passwd_entry));
|
|
+ const gchar *email = gtk_entry_get_text(GTK_ENTRY(email_entry));
|
|
+ if (!user[0])
|
|
+ error_msg = _("Please input the user name.");
|
|
+ else if (!passwd[0])
|
|
+ error_msg = _("Please input the password.");
|
|
+ else if (!email[0])
|
|
+ error_msg = _("Please input the email.");
|
|
+ else if (strchr(email, '@')==NULL)
|
|
+ error_msg = _("Please input a valid email.");
|
|
+ if (error_msg) {
|
|
+ GtkWidget *message_dlg =
|
|
+ gtk_message_dialog_new(
|
|
+ GTK_WINDOW(register_dialog),
|
|
+ (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
|
|
+ GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
|
|
+ error_msg);
|
|
+ gtk_dialog_set_default_response(GTK_DIALOG(message_dlg), GTK_RESPONSE_OK);
|
|
+ gtk_window_set_resizable(GTK_WINDOW(message_dlg), FALSE);
|
|
+ gtk_dialog_run(GTK_DIALOG(message_dlg));
|
|
+ gtk_widget_destroy(message_dlg);
|
|
+ continue;
|
|
+ }
|
|
+ struct MD5Context ctx;
|
|
+ unsigned char digest[16];
|
|
+ MD5Init(&ctx);
|
|
+ MD5Update(&ctx, (const unsigned char*)passwd, strlen(passwd));
|
|
+ MD5Final(digest, &ctx );
|
|
+ char hex[33];
|
|
+ for (int i = 0; i < 16; i++)
|
|
+ sprintf( hex+2*i, "%02x", digest[i] );
|
|
+ hex[32] = '\0';
|
|
+ const gchar *server = gtk_entry_get_text(oPrefsDlg->eStarDictServer);
|
|
+ int port = atoi(gtk_entry_get_text(oPrefsDlg->eStarDictServerPort));
|
|
+ gpAppFrame->oStarDictClient.set_server(server, port);
|
|
+ gpAppFrame->oStarDictClient.set_auth("", "");
|
|
+ oPrefsDlg->register_user = user;
|
|
+ oPrefsDlg->register_hex = hex;
|
|
+ STARDICT::Cmd *c = new STARDICT::Cmd(STARDICT::CMD_REGISTER, user, hex, email);
|
|
+ gpAppFrame->oStarDictClient.send_commands(1, c);
|
|
+ break;
|
|
+ }
|
|
+ gtk_widget_destroy(register_dialog);
|
|
+}
|
|
+
|
|
+void PrefsDlg::setup_network_netdict()
|
|
+{
|
|
+ GtkWidget *vbox = prepare_page(GTK_NOTEBOOK(notebook), _("Net Dict"),
|
|
+ GTK_STOCK_NETWORK);
|
|
+ GtkWidget *vbox1 = gtk_vbox_new(FALSE, 6);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox), vbox1, FALSE, FALSE, 0);
|
|
+
|
|
+ GtkWidget *ck_btn =
|
|
+ gtk_check_button_new_with_mnemonic(_("Enable _network dictionaries."));
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1), ck_btn, FALSE, FALSE, 0);
|
|
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ck_btn),
|
|
+ conf->get_bool_at("network/enable_netdict"));
|
|
+ g_signal_connect(G_OBJECT(ck_btn), "toggled",
|
|
+ G_CALLBACK(on_setup_network_netdict_ckbutton_toggled), this);
|
|
+
|
|
+ GtkWidget *table;
|
|
+ table = gtk_table_new(3, 2, FALSE);
|
|
+ gtk_table_set_row_spacings(GTK_TABLE(table), 6);
|
|
+ gtk_table_set_col_spacings(GTK_TABLE(table), 6);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),table,false,false,0);
|
|
+ GtkWidget *label=gtk_label_new(_("StarDict server:"));
|
|
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
|
|
+ GtkWidget *comboboxentry = gtk_combo_box_entry_new_text();
|
|
+ gtk_table_attach(GTK_TABLE(table), comboboxentry, 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
|
|
+ gtk_combo_box_append_text(GTK_COMBO_BOX(comboboxentry), "dict.stardict.org");
|
|
+ gtk_combo_box_append_text(GTK_COMBO_BOX(comboboxentry), "dict.stardict.cn");
|
|
+ eStarDictServer=GTK_ENTRY(GTK_BIN(comboboxentry)->child);
|
|
+ const std::string &server= conf->get_string_at("network/server");
|
|
+ gtk_entry_set_text(eStarDictServer, server.c_str());
|
|
+ label=gtk_label_new(_("Port:"));
|
|
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
|
|
+ GtkWidget *e = gtk_entry_new();
|
|
+ int port = conf->get_int_at("network/port");
|
|
+ gchar *str = g_strdup_printf("%d", port);
|
|
+ gtk_entry_set_text(GTK_ENTRY(e), str);
|
|
+ g_free(str);
|
|
+ gtk_table_attach(GTK_TABLE(table), e, 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
|
|
+ eStarDictServerPort=GTK_ENTRY(e);
|
|
+ label=gtk_label_new(_("Account:"));
|
|
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL, GTK_FILL, 0, 0);
|
|
+ const std::string &user= conf->get_string_at("network/user");
|
|
+ GtkWidget *button;
|
|
+ if (user.empty())
|
|
+ button = gtk_button_new_with_label("Guest");
|
|
+ else
|
|
+ button = gtk_button_new_with_label(user.c_str());
|
|
+ g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(on_setup_network_account_button_clicked), this);
|
|
+ gtk_table_attach(GTK_TABLE(table), button, 1, 2, 2, 3, GTK_FILL, GTK_FILL, 0, 0);
|
|
+ bAccount = GTK_BUTTON(button);
|
|
+ button = gtk_button_new_with_mnemonic(_("_Register an account"));
|
|
+ g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(on_setup_network_register_button_clicked), this);
|
|
+ GtkWidget *hbox1 = gtk_hbox_new(FALSE, 6);
|
|
+ gtk_box_pack_start(GTK_BOX(hbox1),button,false,false,0);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),hbox1,false,false,0);
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_mainwin_searchWhileTyping_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ conf->set_bool_at("main_window/search_while_typing",
|
|
+ gtk_toggle_button_get_active(button));
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_mainwin_showfirstWhenNotfound_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ conf->set_bool_at("main_window/showfirst_when_notfound",
|
|
+ gtk_toggle_button_get_active(button));
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_mainwin_input_timeout_spinbutton_changed(GtkSpinButton *button, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ gint timeout = gtk_spin_button_get_value_as_int(button);
|
|
+ conf->set_int_at("main_window/word_change_timeout", timeout);
|
|
+ gpAppFrame->word_change_timeout = timeout;
|
|
+}
|
|
+
|
|
+void PrefsDlg::setup_mainwin_input_page()
|
|
+{
|
|
+ GtkWidget *vbox = prepare_page(GTK_NOTEBOOK(notebook), _("Input"),
|
|
+ GTK_STOCK_EDIT);
|
|
+
|
|
+ GtkWidget *vbox1 = gtk_vbox_new(FALSE, 6);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox),vbox1,FALSE,FALSE, 0);
|
|
+
|
|
+ GtkWidget *check_button =
|
|
+ gtk_check_button_new_with_mnemonic(_("_Search while typing."));
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1), check_button, FALSE, FALSE, 0);
|
|
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button),
|
|
+ conf->get_bool_at("main_window/search_while_typing"));
|
|
+ g_signal_connect(G_OBJECT(check_button), "toggled",
|
|
+ G_CALLBACK(on_setup_mainwin_searchWhileTyping_ckbutton_toggled), this);
|
|
+ GtkWidget *hbox = gtk_hbox_new(false, 5);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),hbox,FALSE,FALSE, 0);
|
|
+ GtkWidget *label=gtk_label_new(NULL);
|
|
+ gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), _("Word change _timeout:"));
|
|
+ gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE, 0);
|
|
+ GtkWidget *spin_button;
|
|
+ spin_button = gtk_spin_button_new_with_range(50,2000,50);
|
|
+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), spin_button);
|
|
+ gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin_button), GTK_UPDATE_IF_VALID);
|
|
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_button), conf->get_int_at("main_window/word_change_timeout"));
|
|
+ g_signal_connect(G_OBJECT(spin_button), "value-changed", G_CALLBACK(on_setup_mainwin_input_timeout_spinbutton_changed), this);
|
|
+ gtk_box_pack_start(GTK_BOX(hbox),spin_button,FALSE,FALSE, 0);
|
|
+ label=gtk_label_new(_("(default:300)"));
|
|
+ gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE, 0);
|
|
+ check_button = gtk_check_button_new_with_mnemonic(_("Show the _first word when not found."));
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),check_button,FALSE,FALSE,0);
|
|
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), conf->get_bool_at("main_window/showfirst_when_notfound"));
|
|
+ g_signal_connect(G_OBJECT(check_button), "toggled",
|
|
+ G_CALLBACK(on_setup_mainwin_showfirstWhenNotfound_ckbutton_toggled), this);
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_mainwin_startup_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ conf->set_bool_at("main_window/hide_on_startup",
|
|
+ gtk_toggle_button_get_active(button));
|
|
+}
|
|
+
|
|
+#ifdef _WIN32
|
|
+void PrefsDlg::on_setup_mainwin_autorun_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ gboolean b = gtk_toggle_button_get_active(button);
|
|
+ HKEY hKEY;
|
|
+ LONG lRet;
|
|
+ if (b) {
|
|
+ lRet =RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Run",0,KEY_ALL_ACCESS,&hKEY);
|
|
+ if(lRet==ERROR_SUCCESS) {
|
|
+ std::string path = gStarDictDataDir+ G_DIR_SEPARATOR_S "stardict.exe";
|
|
+ RegSetValueEx(hKEY, "StarDict", 0, REG_SZ, (const BYTE*)path.c_str(), path.length()+1);
|
|
+ RegCloseKey(hKEY);
|
|
+ }
|
|
+ } else {
|
|
+ lRet =RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Run",0,KEY_ALL_ACCESS,&hKEY);
|
|
+ if(lRet==ERROR_SUCCESS) {
|
|
+ RegDeleteValue(hKEY, "StarDict");
|
|
+ RegCloseKey(hKEY);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_mainwin_use_mainwindow_hotkey_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ gboolean b = gtk_toggle_button_get_active(button);
|
|
+ if (b)
|
|
+ gpAppFrame->oHotkey.start_mainwindow();
|
|
+ else
|
|
+ gpAppFrame->oHotkey.stop_mainwindow();
|
|
+ conf->set_bool_at("dictionary/use_mainwindow_hotkey", b);
|
|
+}
|
|
+#endif
|
|
+
|
|
+void PrefsDlg::on_setup_mainwin_transparent_scale_changed(GtkRange *range, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ gint transparent = (gint)gtk_range_get_value(range);
|
|
+ conf->set_int_at("main_window/transparent", transparent);
|
|
+ gtk_window_set_opacity(GTK_WINDOW(gpAppFrame->window), (100-transparent)/100.0);
|
|
+}
|
|
+
|
|
+void PrefsDlg::setup_mainwin_options_page()
|
|
+{
|
|
+ GtkWidget *vbox = prepare_page(GTK_NOTEBOOK(notebook), _("Options"), GTK_STOCK_EXECUTE);
|
|
+ GtkWidget *vbox1 = gtk_vbox_new(FALSE, 6);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox),vbox1,FALSE,FALSE, 0);
|
|
+
|
|
+ GtkWidget *check_button;
|
|
+#ifdef _WIN32
|
|
+ check_button = gtk_check_button_new_with_mnemonic(_("_Auto run StarDict after boot."));
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),check_button,FALSE,FALSE,0);
|
|
+ gboolean autorun;
|
|
+
|
|
+ HKEY hKEY;
|
|
+ LONG lRet =RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Run",0,KEY_QUERY_VALUE,&hKEY);
|
|
+ if(lRet!=ERROR_SUCCESS) {
|
|
+ autorun = false;
|
|
+ } else {
|
|
+ char owner_Get[80];
|
|
+ DWORD cbData_1=80;
|
|
+ DWORD type_1=REG_SZ;
|
|
+ lRet=RegQueryValueEx(hKEY,"StarDict",NULL,&type_1,(LPBYTE)owner_Get,&cbData_1);
|
|
+ RegCloseKey(hKEY);
|
|
+ if((lRet!=ERROR_SUCCESS)||(cbData_1 > 80)) {
|
|
+ autorun = false;
|
|
+ } else {
|
|
+ std::string path = gStarDictDataDir+ G_DIR_SEPARATOR_S "stardict.exe";
|
|
+ if (strcmp(path.c_str(), owner_Get)==0)
|
|
+ autorun = true;
|
|
+ else
|
|
+ autorun = false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), autorun);
|
|
+ g_signal_connect(G_OBJECT(check_button), "toggled",
|
|
+ G_CALLBACK(on_setup_mainwin_autorun_ckbutton_toggled), this);
|
|
+#endif
|
|
+
|
|
+ check_button = gtk_check_button_new_with_mnemonic(_("Hide main window when _starting StarDict."));
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1), check_button, FALSE, FALSE, 0);
|
|
+ bool hide=
|
|
+ conf->get_bool_at("main_window/hide_on_startup");
|
|
+
|
|
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), hide);
|
|
+ g_signal_connect(G_OBJECT(check_button), "toggled",
|
|
+ G_CALLBACK(on_setup_mainwin_startup_ckbutton_toggled), this);
|
|
+
|
|
+#ifdef _WIN32
|
|
+ check_button = gtk_check_button_new_with_mnemonic(_("_Use open main window hotkey: Ctrl+Alt+Z."));
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),check_button,false,false,0);
|
|
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), conf->get_bool_at("dictionary/use_mainwindow_hotkey"));
|
|
+ g_signal_connect(G_OBJECT(check_button), "toggled",
|
|
+ G_CALLBACK(on_setup_mainwin_use_mainwindow_hotkey_ckbutton_toggled), this);
|
|
+#endif
|
|
+
|
|
+ GtkWidget *hbox = gtk_hbox_new(false, 5);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),hbox,FALSE,FALSE, 0);
|
|
+ GtkWidget *label=gtk_label_new(NULL);
|
|
+ gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), _("_Transparency:"));
|
|
+ gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE, 0);
|
|
+ GtkWidget *hscale;
|
|
+ hscale = gtk_hscale_new_with_range(0,80,1);
|
|
+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), hscale);
|
|
+ int transparent=conf->get_int_at("main_window/transparent");
|
|
+ gtk_range_set_value(GTK_RANGE(hscale), transparent);
|
|
+ g_signal_connect(G_OBJECT(hscale), "value-changed", G_CALLBACK(on_setup_mainwin_transparent_scale_changed), this);
|
|
+ gtk_box_pack_start(GTK_BOX(hbox),hscale,TRUE,TRUE, 0);
|
|
+}
|
|
+
|
|
+void PrefsDlg::write_mainwin_searchwebsite_list()
|
|
+{
|
|
+ GtkTreeIter iter;
|
|
+ gboolean have_iter;
|
|
+ gchar *website_name, *website_link, *website_searchlink;
|
|
+ std::list<std::string> searchwebsite_list;
|
|
+ GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW (searchwebsite_treeview));
|
|
+
|
|
+ have_iter = gtk_tree_model_get_iter_first(model, &iter);
|
|
+ while (have_iter) {
|
|
+ gtk_tree_model_get (model, &iter, 0, &website_name, 1, &website_link, 2, &website_searchlink, -1);
|
|
+ std::string website(std::string(website_name)+'\t'+website_link+'\t'+website_searchlink);
|
|
+ g_free(website_name);
|
|
+ g_free(website_link);
|
|
+ g_free(website_searchlink);
|
|
+ searchwebsite_list.push_back(website);
|
|
+ have_iter = gtk_tree_model_iter_next(model, &iter);
|
|
+ }
|
|
+ conf->set_strlist_at("main_window/search_website_list", searchwebsite_list);
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_mainwin_searchwebsite_moveup_button_clicked(GtkWidget *widget, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ GtkTreeSelection *selection;
|
|
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (oPrefsDlg->searchwebsite_treeview));
|
|
+ GtkTreeModel *model;
|
|
+ GtkTreeIter iter;
|
|
+ if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
|
|
+ GtkTreePath* path = gtk_tree_model_get_path(model, &iter);
|
|
+ if (gtk_tree_path_prev(path)) {
|
|
+ GtkTreeIter prev;
|
|
+ gtk_tree_model_get_iter(model, &prev, path);
|
|
+ gtk_list_store_swap(GTK_LIST_STORE(model), &iter, &prev);
|
|
+ gtk_tree_selection_select_path(selection, path);
|
|
+ gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW (oPrefsDlg->searchwebsite_treeview), path, NULL, false, 0, 0);
|
|
+ oPrefsDlg->write_mainwin_searchwebsite_list();
|
|
+ }
|
|
+ gtk_tree_path_free(path);
|
|
+ }
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_mainwin_searchwebsite_movedown_button_clicked(GtkWidget *widget, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ GtkTreeSelection *selection;
|
|
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (oPrefsDlg->searchwebsite_treeview));
|
|
+ GtkTreeModel *model;
|
|
+ GtkTreeIter iter;
|
|
+ if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
|
|
+ GtkTreePath* path = gtk_tree_model_get_path(model, &iter);
|
|
+ gtk_tree_path_next(path);
|
|
+ GtkTreeIter next;
|
|
+ if (gtk_tree_model_get_iter(model, &next, path)) {
|
|
+ gtk_list_store_swap(GTK_LIST_STORE(model), &iter, &next);
|
|
+ gtk_tree_selection_select_path(selection, path);
|
|
+ gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW (oPrefsDlg->searchwebsite_treeview), path, NULL, false, 0, 0);
|
|
+ oPrefsDlg->write_mainwin_searchwebsite_list();
|
|
+ }
|
|
+ gtk_tree_path_free(path);
|
|
+ }
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_mainwin_searchwebsite_add_button_clicked(GtkWidget *widget, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ GtkWidget *searchwebsite_add_dialog;
|
|
+ GtkWidget *searchwebsite_add_dialog_name_entry;
|
|
+ GtkWidget *searchwebsite_add_dialog_link_entry;
|
|
+ GtkWidget *searchwebsite_add_dialog_searchlink_entry;
|
|
+
|
|
+ searchwebsite_add_dialog =
|
|
+ gtk_dialog_new_with_buttons (_("Add"),
|
|
+ GTK_WINDOW (oPrefsDlg->window),
|
|
+ GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
+ GTK_STOCK_CANCEL,
|
|
+ GTK_RESPONSE_CANCEL,
|
|
+ GTK_STOCK_OK,
|
|
+ GTK_RESPONSE_OK,
|
|
+ NULL);
|
|
+ GtkWidget *table = gtk_table_new(3, 2, FALSE);
|
|
+ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(searchwebsite_add_dialog)->vbox), table);
|
|
+#ifndef CONFIG_GPE
|
|
+ gtk_container_set_border_width(GTK_CONTAINER(table), 6);
|
|
+#endif
|
|
+ GtkWidget *label = gtk_label_new_with_mnemonic(_("Website Name"));
|
|
+ gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
|
|
+ searchwebsite_add_dialog_name_entry = gtk_entry_new ();
|
|
+#ifdef CONFIG_GPE
|
|
+ gtk_widget_set_size_request(searchwebsite_add_dialog_name_entry, 100, -1);
|
|
+#endif
|
|
+ gtk_entry_set_activates_default(GTK_ENTRY(searchwebsite_add_dialog_name_entry), TRUE);
|
|
+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), searchwebsite_add_dialog_name_entry);
|
|
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, (GtkAttachOptions)0, 6, 4);
|
|
+ gtk_table_attach(GTK_TABLE(table), searchwebsite_add_dialog_name_entry, 1, 2, 0, 1, GTK_EXPAND, (GtkAttachOptions)0, 0, 4);
|
|
+
|
|
+
|
|
+ label = gtk_label_new_with_mnemonic(_("Website link"));
|
|
+ gtk_misc_set_alignment (GTK_MISC (label), 0, .5);
|
|
+ searchwebsite_add_dialog_link_entry = gtk_entry_new ();
|
|
+#ifdef CONFIG_GPE
|
|
+ gtk_widget_set_size_request(searchwebsite_add_dialog_link_entry, 100, -1);
|
|
+#endif
|
|
+ gtk_entry_set_activates_default (GTK_ENTRY (searchwebsite_add_dialog_link_entry), TRUE);
|
|
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), searchwebsite_add_dialog_link_entry);
|
|
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, (GtkAttachOptions)0, 6, 4);
|
|
+ gtk_table_attach(GTK_TABLE(table), searchwebsite_add_dialog_link_entry, 1, 2, 1, 2, GTK_EXPAND, (GtkAttachOptions)0, 0, 4);
|
|
+
|
|
+ label = gtk_label_new_with_mnemonic(_("Website search link"));
|
|
+ gtk_misc_set_alignment (GTK_MISC (label), 0, .5);
|
|
+ searchwebsite_add_dialog_searchlink_entry = gtk_entry_new ();
|
|
+#ifdef CONFIG_GPE
|
|
+ gtk_widget_set_size_request(searchwebsite_add_dialog_searchlink_entry, 100, -1);
|
|
+#endif
|
|
+ gtk_entry_set_activates_default (GTK_ENTRY (searchwebsite_add_dialog_searchlink_entry), TRUE);
|
|
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), searchwebsite_add_dialog_searchlink_entry);
|
|
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL, (GtkAttachOptions)0, 6, 4);
|
|
+ gtk_table_attach(GTK_TABLE(table), searchwebsite_add_dialog_searchlink_entry, 1, 2, 2, 3, GTK_EXPAND, (GtkAttachOptions)0, 0, 4);
|
|
+
|
|
+ gtk_dialog_set_default_response(GTK_DIALOG(searchwebsite_add_dialog), GTK_RESPONSE_OK);
|
|
+ gtk_window_set_resizable(GTK_WINDOW(searchwebsite_add_dialog), FALSE);
|
|
+
|
|
+ gtk_widget_show_all(GTK_WIDGET(searchwebsite_add_dialog));
|
|
+ while (gtk_dialog_run(GTK_DIALOG(searchwebsite_add_dialog))==GTK_RESPONSE_OK) {
|
|
+ gchar *error_msg = NULL;
|
|
+ const gchar *website_name = gtk_entry_get_text(GTK_ENTRY(searchwebsite_add_dialog_name_entry));
|
|
+ const gchar *website_link = gtk_entry_get_text(GTK_ENTRY(searchwebsite_add_dialog_link_entry));
|
|
+ const gchar *website_searchlink = gtk_entry_get_text(GTK_ENTRY(searchwebsite_add_dialog_searchlink_entry));
|
|
+ if (!website_name[0])
|
|
+ error_msg = _("Please input the website name.");
|
|
+ else if (!website_link[0])
|
|
+ error_msg = _("Please input the website link.");
|
|
+ else if (!website_searchlink[0])
|
|
+ error_msg = _("Please input the website search link.");
|
|
+ else if (!strstr(website_searchlink, "%s")) {
|
|
+ error_msg = _("The website search link should contain a \"%%s\" string for querying a word.");
|
|
+ }
|
|
+
|
|
+ if (error_msg) {
|
|
+ GtkWidget *message_dlg =
|
|
+ gtk_message_dialog_new(
|
|
+ GTK_WINDOW(searchwebsite_add_dialog),
|
|
+ (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
|
|
+ GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
|
|
+ error_msg);
|
|
+
|
|
+ gtk_dialog_set_default_response(GTK_DIALOG(message_dlg), GTK_RESPONSE_OK);
|
|
+ gtk_window_set_resizable(GTK_WINDOW(message_dlg), FALSE);
|
|
+
|
|
+ gtk_dialog_run(GTK_DIALOG(message_dlg));
|
|
+ gtk_widget_destroy(message_dlg);
|
|
+ continue;
|
|
+ }
|
|
+ GtkListStore *model =
|
|
+ GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(oPrefsDlg->searchwebsite_treeview)));
|
|
+ GtkTreeIter iter;
|
|
+ gtk_list_store_prepend(model, &iter);
|
|
+ gtk_list_store_set(model, &iter,
|
|
+ 0, website_name,
|
|
+ 1, website_link,
|
|
+ 2, website_searchlink,
|
|
+ 3, TRUE,
|
|
+ -1);
|
|
+ oPrefsDlg->write_mainwin_searchwebsite_list();
|
|
+ break;
|
|
+ }
|
|
+ gtk_widget_destroy(searchwebsite_add_dialog);
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_mainwin_searchwebsite_remove_button_clicked(GtkWidget *widget, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ GtkTreeSelection *selection;
|
|
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (oPrefsDlg->searchwebsite_treeview));
|
|
+ GtkTreeModel *model;
|
|
+ GtkTreeIter iter;
|
|
+ if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
|
|
+ if (gtk_list_store_remove(GTK_LIST_STORE(model), &iter)) {
|
|
+ GtkTreePath* path = gtk_tree_model_get_path(model, &iter);
|
|
+ gtk_tree_selection_select_path(selection, path);
|
|
+ gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW (oPrefsDlg->searchwebsite_treeview), path, NULL, false, 0, 0);
|
|
+ gtk_tree_path_free(path);
|
|
+ }
|
|
+ oPrefsDlg->write_mainwin_searchwebsite_list();
|
|
+ }
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_mainwin_searchwebsite_cell_edited(GtkCellRendererText *cell, const gchar *path_string, const gchar *new_text, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW (oPrefsDlg->searchwebsite_treeview));
|
|
+ GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
|
|
+ GtkTreeIter iter;
|
|
+
|
|
+ glong column;
|
|
+ column = (glong)(g_object_get_data (G_OBJECT (cell), "column"));
|
|
+ gtk_tree_model_get_iter (model, &iter, path);
|
|
+
|
|
+ switch (column) {
|
|
+ case 0:
|
|
+ case 1:
|
|
+ if (new_text[0]) {
|
|
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter, column, new_text, -1);
|
|
+ oPrefsDlg->write_mainwin_searchwebsite_list();
|
|
+ }
|
|
+ break;
|
|
+ case 2:
|
|
+ if (new_text[0]) {
|
|
+ if (!strstr(new_text, "%s")) {
|
|
+ GtkWidget *message_dlg;
|
|
+
|
|
+ message_dlg = gtk_message_dialog_new (
|
|
+ GTK_WINDOW (oPrefsDlg->window),
|
|
+ (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
|
|
+ GTK_MESSAGE_INFO,
|
|
+ GTK_BUTTONS_OK,
|
|
+ _("The website search link should contain a \"%%s\" string for querying a word."));
|
|
+
|
|
+ gtk_dialog_set_default_response (GTK_DIALOG (message_dlg), GTK_RESPONSE_OK);
|
|
+
|
|
+ gtk_window_set_resizable (GTK_WINDOW (message_dlg), FALSE);
|
|
+
|
|
+ gtk_dialog_run (GTK_DIALOG (message_dlg));
|
|
+ gtk_widget_destroy (message_dlg);
|
|
+ }
|
|
+ else {
|
|
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter, 2, new_text, -1);
|
|
+ oPrefsDlg->write_mainwin_searchwebsite_list();
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ }
|
|
+
|
|
+ gtk_tree_path_free (path);
|
|
+}
|
|
+
|
|
+void PrefsDlg::setup_mainwin_searchwebsite_page()
|
|
+{
|
|
+ GtkWidget *vbox = prepare_page(GTK_NOTEBOOK(notebook), _("Search website"), GTK_STOCK_JUMP_TO);
|
|
+ GtkWidget *vbox2;
|
|
+ vbox2 = gtk_vbox_new(false, 6);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox), vbox2, true, true,0);
|
|
+
|
|
+ GtkListStore *model;
|
|
+ model = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
|
|
+
|
|
+ const std::list<std::string> &web_list=
|
|
+ conf->get_strlist_at("main_window/search_website_list");
|
|
+
|
|
+ GtkTreeIter iter;
|
|
+ for (std::list<std::string>::const_iterator wit=web_list.begin();
|
|
+ wit!=web_list.end(); ++wit) {
|
|
+ std::vector<std::string> l=split(*wit, '\t');
|
|
+ if (l.size()==3) {
|
|
+ gtk_list_store_append(model, &iter);
|
|
+ gtk_list_store_set(model, &iter,
|
|
+ 0, l[0].c_str(),
|
|
+ 1, l[1].c_str(),
|
|
+ 2, l[2].c_str(),
|
|
+ 3, TRUE,
|
|
+ -1);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ GtkWidget *sw;
|
|
+ sw = gtk_scrolled_window_new (NULL, NULL);
|
|
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
|
|
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
|
|
+ GTK_POLICY_AUTOMATIC,
|
|
+ GTK_POLICY_AUTOMATIC);
|
|
+
|
|
+ gtk_widget_set_size_request (sw, 300, 180);
|
|
+
|
|
+ searchwebsite_treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL(model));
|
|
+ g_object_unref (G_OBJECT (model));
|
|
+ gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (searchwebsite_treeview), TRUE);
|
|
+
|
|
+ GtkTreeSelection *selection;
|
|
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (searchwebsite_treeview));
|
|
+
|
|
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
|
|
+
|
|
+ GtkCellRenderer *renderer;
|
|
+ GtkTreeViewColumn *column;
|
|
+
|
|
+ renderer = gtk_cell_renderer_text_new ();
|
|
+ g_signal_connect (renderer, "edited", G_CALLBACK (on_setup_mainwin_searchwebsite_cell_edited), this);
|
|
+ g_object_set (G_OBJECT (renderer), "xalign", 0.0, NULL);
|
|
+ g_object_set_data (G_OBJECT (renderer), "column", GINT_TO_POINTER(0));
|
|
+ column = gtk_tree_view_column_new_with_attributes (_("Website Name"), renderer, "text", 0, "editable", 3, NULL);
|
|
+ gtk_tree_view_append_column (GTK_TREE_VIEW(searchwebsite_treeview), column);
|
|
+ gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), FALSE);
|
|
+
|
|
+ renderer = gtk_cell_renderer_text_new ();
|
|
+ g_signal_connect (renderer, "edited", G_CALLBACK (on_setup_mainwin_searchwebsite_cell_edited), this);
|
|
+ g_object_set (G_OBJECT (renderer), "xalign", 0.0, NULL);
|
|
+ g_object_set_data (G_OBJECT (renderer), "column", GINT_TO_POINTER(1));
|
|
+ column = gtk_tree_view_column_new_with_attributes (_("Website link"), renderer, "text", 1, "editable", 3, NULL);
|
|
+ gtk_tree_view_append_column (GTK_TREE_VIEW(searchwebsite_treeview), column);
|
|
+ gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), FALSE);
|
|
+
|
|
+ renderer = gtk_cell_renderer_text_new ();
|
|
+ g_signal_connect (renderer, "edited", G_CALLBACK (on_setup_mainwin_searchwebsite_cell_edited), this);
|
|
+ g_object_set (G_OBJECT (renderer), "xalign", 0.0, NULL);
|
|
+ g_object_set_data (G_OBJECT (renderer), "column", GINT_TO_POINTER(2));
|
|
+ column = gtk_tree_view_column_new_with_attributes (_("Website search link"), renderer, "text", 2, "editable", 3, NULL);
|
|
+ gtk_tree_view_append_column (GTK_TREE_VIEW(searchwebsite_treeview), column);
|
|
+ gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), FALSE);
|
|
+
|
|
+ gtk_container_add (GTK_CONTAINER (sw), searchwebsite_treeview);
|
|
+ gtk_box_pack_start (GTK_BOX (vbox2), sw, TRUE, TRUE, 0);
|
|
+
|
|
+ GtkWidget *hbox1;
|
|
+ hbox1 = gtk_hbox_new(false,6);
|
|
+ GtkWidget *button;
|
|
+ button = gtk_button_new();
|
|
+ GtkWidget *image = gtk_image_new_from_stock(GTK_STOCK_GO_UP, GTK_ICON_SIZE_BUTTON);
|
|
+ gtk_container_add(GTK_CONTAINER(button), image);
|
|
+ GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS);
|
|
+ g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(on_setup_mainwin_searchwebsite_moveup_button_clicked), this);
|
|
+ gtk_box_pack_start (GTK_BOX (hbox1), button, FALSE, FALSE, 0);
|
|
+ button = gtk_button_new();
|
|
+ image = gtk_image_new_from_stock(GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_BUTTON);
|
|
+ gtk_container_add(GTK_CONTAINER(button), image);
|
|
+ GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS);
|
|
+ g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(on_setup_mainwin_searchwebsite_movedown_button_clicked), this);
|
|
+ gtk_box_pack_start (GTK_BOX (hbox1), button, FALSE, FALSE, 0);
|
|
+ button = gtk_button_new_from_stock(GTK_STOCK_REMOVE);
|
|
+ GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS);
|
|
+ g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(on_setup_mainwin_searchwebsite_remove_button_clicked), this);
|
|
+ gtk_box_pack_end (GTK_BOX (hbox1), button, FALSE, FALSE, 0);
|
|
+
|
|
+/* button = gtk_button_new();
|
|
+ GtkWidget *align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
|
|
+ gtk_container_add (GTK_CONTAINER (button), align);
|
|
+ GtkWidget *hbox2 = gtk_hbox_new (FALSE, 2);
|
|
+ gtk_container_add (GTK_CONTAINER (align), hbox2);
|
|
+ label = gtk_label_new(NULL);
|
|
+ gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), _("_Modify"));
|
|
+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), button);
|
|
+ image = gtk_image_new_from_stock (GTK_STOCK_CONVERT, GTK_ICON_SIZE_BUTTON);
|
|
+ gtk_box_pack_start (GTK_BOX (hbox2), image, FALSE, FALSE, 0);
|
|
+ gtk_box_pack_end (GTK_BOX (hbox2), label, FALSE, FALSE, 0);
|
|
+ GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS);
|
|
+ g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(on_setup_mainwin_searchwebsite_edit_button_clicked), this);
|
|
+ gtk_box_pack_end (GTK_BOX (hbox1), button, FALSE, FALSE, 0);*/
|
|
+
|
|
+ button = gtk_button_new_from_stock(GTK_STOCK_ADD);
|
|
+ GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS);
|
|
+ g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(on_setup_mainwin_searchwebsite_add_button_clicked), this);
|
|
+ gtk_box_pack_end (GTK_BOX (hbox1), button, FALSE, FALSE, 0);
|
|
+
|
|
+ gtk_box_pack_start (GTK_BOX (vbox2), hbox1, false, false, 0);
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_NotificationAreaIcon_QueryInFloatWin_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ gboolean queryin = gtk_toggle_button_get_active(button);
|
|
+ conf->set_bool_at("notification_area_icon/query_in_floatwin",
|
|
+ queryin);
|
|
+}
|
|
+
|
|
+void PrefsDlg::setup_NotificationAreaIcon_options_page()
|
|
+{
|
|
+ GtkWidget *vbox = prepare_page(GTK_NOTEBOOK(notebook), _("Options"), GTK_STOCK_DND);
|
|
+ GtkWidget *hbox1;
|
|
+ hbox1 = gtk_hbox_new(false,0);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox),hbox1,false,false,0);
|
|
+
|
|
+ GtkWidget *check_button;
|
|
+ check_button = gtk_check_button_new_with_mnemonic(_("_Query in the floating window when middle mouse\nbutton is clicked."));
|
|
+ bool query_in_floatwin=
|
|
+ conf->get_bool_at("notification_area_icon/query_in_floatwin");
|
|
+
|
|
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button),
|
|
+ query_in_floatwin);
|
|
+ g_signal_connect(G_OBJECT(check_button), "toggled",
|
|
+ G_CALLBACK(on_setup_NotificationAreaIcon_QueryInFloatWin_ckbutton_toggled), this);
|
|
+ gtk_box_pack_start(GTK_BOX(hbox1),check_button,false,false,0);
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_floatwin_pronounce_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ conf->set_bool_at("floating_window/pronounce_when_popup",
|
|
+ gtk_toggle_button_get_active(button));
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_show_float_if_not_found(GtkToggleButton *button, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ conf->set_bool_at("floating_window/show_if_not_found",
|
|
+ gtk_toggle_button_get_active(button));
|
|
+}
|
|
+
|
|
+void PrefsDlg::setup_floatwin_options_page()
|
|
+{
|
|
+ GtkWidget *vbox = prepare_page(GTK_NOTEBOOK(notebook), _("Options"), GTK_STOCK_DND);
|
|
+ GtkWidget *vbox1 = gtk_vbox_new(false, 6);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox),vbox1,false,false, 0);
|
|
+ GtkWidget *check_button = gtk_check_button_new_with_mnemonic(_("_Pronounce the word when it pops up."));
|
|
+ bool pronounce_when_popup=
|
|
+ conf->get_bool_at("floating_window/pronounce_when_popup");
|
|
+
|
|
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button),
|
|
+ pronounce_when_popup);
|
|
+ g_signal_connect(G_OBJECT(check_button), "toggled", G_CALLBACK(on_setup_floatwin_pronounce_ckbutton_toggled), this);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1), check_button, FALSE, FALSE, 0);
|
|
+
|
|
+ check_button = gtk_check_button_new_with_mnemonic(_("_Show floating window if word not found."));
|
|
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), conf->get_bool_at("floating_window/show_if_not_found"));
|
|
+ g_signal_connect(G_OBJECT(check_button), "toggled", G_CALLBACK(on_setup_show_float_if_not_found), this);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1), check_button, FALSE, FALSE, 0);
|
|
+}
|
|
+
|
|
+#ifndef CONFIG_GPE
|
|
+void PrefsDlg::on_setup_floatwin_size_max_width_spinbutton_changed(GtkSpinButton *button, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ gint width = gtk_spin_button_get_value_as_int(button);
|
|
+ conf->set_int_at("floating_window/max_window_width", width);
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_floatwin_size_max_height_spinbutton_changed(GtkSpinButton *button, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ gint height = gtk_spin_button_get_value_as_int(button);
|
|
+ conf->set_int_at("floating_window/max_window_height", height);
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_floatwin_use_custom_bg_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ gboolean use = gtk_toggle_button_get_active(button);
|
|
+ conf->set_bool_at("floating_window/use_custom_bg", use);
|
|
+ if (use) {
|
|
+ GdkColor color;
|
|
+ color.red = conf->get_int_at("floating_window/bg_red");
|
|
+ color.green = conf->get_int_at("floating_window/bg_green");
|
|
+ color.blue = conf->get_int_at("floating_window/bg_blue");
|
|
+ gpAppFrame->oFloatWin.set_bg(&color);
|
|
+ } else {
|
|
+ gpAppFrame->oFloatWin.set_bg(NULL);
|
|
+ }
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_floatwin_color_set(GtkColorButton *widget, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ GdkColor color;
|
|
+ gtk_color_button_get_color(widget, &color);
|
|
+ conf->set_int_at("floating_window/bg_red", color.red);
|
|
+ conf->set_int_at("floating_window/bg_green", color.green);
|
|
+ conf->set_int_at("floating_window/bg_blue", color.blue);
|
|
+ if (conf->get_bool_at("floating_window/use_custom_bg")) {
|
|
+ gpAppFrame->oFloatWin.set_bg(&color);
|
|
+ }
|
|
+}
|
|
+
|
|
+void PrefsDlg::on_setup_floatwin_transparent_scale_changed(GtkRange *range, PrefsDlg *oPrefsDlg)
|
|
+{
|
|
+ gint transparent = (gint)gtk_range_get_value(range);
|
|
+ conf->set_int_at("floating_window/transparent", transparent);
|
|
+ gtk_window_set_opacity(GTK_WINDOW(gpAppFrame->oFloatWin.FloatWindow), (100-transparent)/100.0);
|
|
+}
|
|
+
|
|
+void PrefsDlg::setup_floatwin_size_page()
|
|
+{
|
|
+ GtkWidget *vbox = prepare_page(GTK_NOTEBOOK(notebook), _("Settings"), GTK_STOCK_ZOOM_FIT);
|
|
+ GtkWidget *vbox1 = gtk_vbox_new(false, 6);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox),vbox1,false,false, 0);
|
|
+ GtkWidget *table;
|
|
+ table = gtk_table_new(3, 2, FALSE);
|
|
+ gtk_table_set_row_spacings(GTK_TABLE(table), 6);
|
|
+ gtk_table_set_col_spacings(GTK_TABLE(table), 6);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),table,false,false,0);
|
|
+
|
|
+ int max_width=
|
|
+ conf->get_int_at("floating_window/max_window_width");
|
|
+ int max_height=
|
|
+ conf->get_int_at("floating_window/max_window_height");
|
|
+
|
|
+ GdkScreen *screen = gtk_window_get_screen(parent_window);
|
|
+ gint screen_width = gdk_screen_get_width(screen);
|
|
+ gint screen_height = gdk_screen_get_height(screen);
|
|
+
|
|
+ GtkWidget *label=gtk_label_new(NULL);
|
|
+ gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), _("Max window _width:"));
|
|
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
|
|
+ GtkWidget *spin_button;
|
|
+ spin_button = gtk_spin_button_new_with_range(MIN_MAX_FLOATWIN_WIDTH,screen_width,1);
|
|
+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), spin_button);
|
|
+ gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin_button), GTK_UPDATE_IF_VALID);
|
|
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_button), max_width);
|
|
+ g_signal_connect(G_OBJECT(spin_button), "value-changed",
|
|
+ G_CALLBACK(on_setup_floatwin_size_max_width_spinbutton_changed), this);
|
|
+ gtk_table_attach(GTK_TABLE(table), spin_button, 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
|
|
+ label=gtk_label_new(_("(default:320)"));
|
|
+ gtk_table_attach(GTK_TABLE(table), label, 2, 3, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
|
|
+
|
|
+ label=gtk_label_new(NULL);
|
|
+ gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), _("Max window hei_ght:"));
|
|
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
|
|
+ spin_button = gtk_spin_button_new_with_range(MIN_MAX_FLOATWIN_HEIGHT,screen_height,1);
|
|
+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), spin_button);
|
|
+ gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin_button), GTK_UPDATE_IF_VALID);
|
|
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_button), max_height);
|
|
+ g_signal_connect (G_OBJECT (spin_button), "value-changed", G_CALLBACK (on_setup_floatwin_size_max_height_spinbutton_changed), (gpointer)this);
|
|
+ gtk_table_attach(GTK_TABLE(table), spin_button, 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
|
|
+ label=gtk_label_new(_("(default:240)"));
|
|
+ gtk_table_attach(GTK_TABLE(table), label, 2, 3, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
|
|
+
|
|
+ GtkWidget*hbox1 = gtk_hbox_new(false, 5);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),hbox1,false,false,0);
|
|
+ GtkWidget *check_button = gtk_check_button_new_with_mnemonic(_("_Use custom background color:"));
|
|
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), conf->get_bool_at("floating_window/use_custom_bg"));
|
|
+ g_signal_connect(G_OBJECT(check_button), "toggled", G_CALLBACK(on_setup_floatwin_use_custom_bg_toggled), this);
|
|
+ gtk_box_pack_start(GTK_BOX(hbox1),check_button,false,false,0);
|
|
+ GdkColor color;
|
|
+ color.red = conf->get_int_at("floating_window/bg_red");
|
|
+ color.green = conf->get_int_at("floating_window/bg_green");
|
|
+ color.blue = conf->get_int_at("floating_window/bg_blue");
|
|
+ GtkWidget *colorbutton = gtk_color_button_new_with_color(&color);
|
|
+ g_signal_connect(G_OBJECT(colorbutton), "color-set", G_CALLBACK(on_setup_floatwin_color_set), this);
|
|
+ gtk_box_pack_start(GTK_BOX(hbox1),colorbutton,false,false,0);
|
|
+
|
|
+ GtkWidget *hbox = gtk_hbox_new(false, 5);
|
|
+ gtk_box_pack_start(GTK_BOX(vbox1),hbox,FALSE,FALSE, 0);
|
|
+ label=gtk_label_new(NULL);
|
|
+ gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), _("_Transparency:"));
|
|
+ gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE, 0);
|
|
+ GtkWidget *hscale;
|
|
+ hscale = gtk_hscale_new_with_range(0,80,1);
|
|
+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), hscale);
|
|
+ int transparent=conf->get_int_at("floating_window/transparent");
|
|
+ gtk_range_set_value(GTK_RANGE(hscale), transparent);
|
|
+ g_signal_connect(G_OBJECT(hscale), "value-changed", G_CALLBACK(on_setup_floatwin_transparent_scale_changed), this);
|
|
+ gtk_box_pack_start(GTK_BOX(hbox),hscale,TRUE,TRUE, 0);
|
|
+}
|
|
+#endif
|
|
+
|
|
+GtkWidget* PrefsDlg::create_notebook ()
|
|
+{
|
|
+ notebook = gtk_notebook_new();
|
|
+ GtkNotebook *nb = GTK_NOTEBOOK(notebook);
|
|
+#ifdef CONFIG_GPE
|
|
+ gtk_notebook_set_scrollable(nb, true);
|
|
+#else
|
|
+ gtk_notebook_set_show_tabs(nb,false);
|
|
+ gtk_notebook_set_show_border(nb,false);
|
|
+ setup_logo_page ();
|
|
+#endif
|
|
+ setup_dictionary_scan_page ();
|
|
+ setup_dictionary_font_page ();
|
|
+ setup_dictionary_cache_page ();
|
|
+ setup_dictionary_export_page ();
|
|
+ setup_dictionary_sound_page ();
|
|
+ setup_dict_article_rendering();
|
|
+ setup_network_netdict();
|
|
+ setup_mainwin_input_page ();
|
|
+ setup_mainwin_options_page ();
|
|
+ setup_mainwin_searchwebsite_page();
|
|
+ setup_NotificationAreaIcon_options_page();
|
|
+ setup_floatwin_options_page ();
|
|
+#ifdef CONFIG_GPE
|
|
+ gtk_notebook_set_current_page (nb, 0);
|
|
+#else
|
|
+ setup_floatwin_size_page ();
|
|
+ gtk_notebook_set_current_page (nb, LOGO);
|
|
+#endif
|
|
+ return notebook;
|
|
+}
|
|
+
|
|
+
|
|
+PrefsDlg::PrefsDlg(GtkWindow *parent, GdkPixbuf *logo, const std::list<std::string>& key_combs_) :
|
|
+ key_combs(key_combs_)
|
|
+{
|
|
+ parent_window=parent;
|
|
+#ifndef CONFIG_GPE
|
|
+ stardict_logo=logo;
|
|
+#endif
|
|
+
|
|
+ window = NULL;
|
|
+}
|
|
+
|
|
+bool PrefsDlg::ShowModal()
|
|
+{
|
|
+ window = gtk_dialog_new();
|
|
+ gtk_window_set_transient_for(GTK_WINDOW(window), parent_window);
|
|
+
|
|
+ gtk_dialog_add_button(GTK_DIALOG(window),
|
|
+ GTK_STOCK_HELP,
|
|
+ GTK_RESPONSE_HELP);
|
|
+
|
|
+ gtk_dialog_add_button(GTK_DIALOG(window),
|
|
+ GTK_STOCK_CLOSE,
|
|
+ GTK_RESPONSE_CLOSE);
|
|
+ gtk_dialog_set_default_response(GTK_DIALOG(window),
|
|
+ GTK_RESPONSE_CLOSE);
|
|
+ g_signal_connect(G_OBJECT(window), "response",
|
|
+ G_CALLBACK(response_handler), this);
|
|
+#ifndef CONFIG_GPE
|
|
+ GtkWidget *hbox;
|
|
+ hbox = gtk_hbox_new (FALSE, 18);
|
|
+ gtk_container_set_border_width (GTK_CONTAINER (hbox), 10);
|
|
+ GtkWidget *r;
|
|
+ r = gtk_vbox_new (FALSE, 6);
|
|
+
|
|
+ GtkWidget *label;
|
|
+ label = gtk_label_new_with_mnemonic (_("Cat_egories:"));
|
|
+ gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
|
|
+ g_object_set (G_OBJECT (label), "xalign", 0.0, NULL);
|
|
+ create_categories_tree();
|
|
+
|
|
+
|
|
+ gtk_box_pack_start(GTK_BOX(r), label, FALSE, FALSE, 0);
|
|
+ gtk_box_pack_start(GTK_BOX(r), categories_window, TRUE, TRUE, 0);
|
|
+#endif
|
|
+
|
|
+ GtkWidget *l = create_notebook ();
|
|
+
|
|
+#ifdef CONFIG_GPE
|
|
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), l, true, true, 0);
|
|
+#else
|
|
+ gtk_box_pack_start (GTK_BOX (hbox), r, FALSE, FALSE, 0);
|
|
+ gtk_box_pack_start (GTK_BOX (hbox), l, TRUE, TRUE, 0);
|
|
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), hbox, true, true, 0);
|
|
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), categories_tree);
|
|
+#endif
|
|
+
|
|
+ gtk_widget_show_all (GTK_DIALOG (window)->vbox);
|
|
+ gtk_window_set_title (GTK_WINDOW (window), _("Preferences"));
|
|
+
|
|
+#ifndef CONFIG_GPE
|
|
+ resize_categories_tree();
|
|
+#endif
|
|
+ gint result;
|
|
+ while ((result = gtk_dialog_run(GTK_DIALOG(window)))==GTK_RESPONSE_HELP)
|
|
+ ;
|
|
+ if (result != GTK_RESPONSE_NONE) {
|
|
+ const gchar *ch;
|
|
+ ch = gtk_entry_get_text(eExportFile);
|
|
+ if (ch[0])
|
|
+ conf->set_string_at("dictionary/export_file", ch);
|
|
+#ifndef _WIN32
|
|
+ ch = gtk_entry_get_text(eTTSCommandline);
|
|
+ if (ch[0]) {
|
|
+ conf->set_string("/apps/stardict/preferences/dictionary/tts_program_cmdline", ch);
|
|
+ gpAppFrame->oReadWord.tts_program_cmdline = ch;
|
|
+ }
|
|
+#endif
|
|
+ const gchar *server;
|
|
+ ch = gtk_entry_get_text(eStarDictServer);
|
|
+ if (ch[0])
|
|
+ server = ch;
|
|
+ else
|
|
+ server = _("dict.stardict.org");
|
|
+ conf->set_string_at("network/server", server);
|
|
+ int port;
|
|
+ ch = gtk_entry_get_text(eStarDictServerPort);
|
|
+ if (ch[0])
|
|
+ port = atoi(ch);
|
|
+ else
|
|
+ port = 2628;
|
|
+ conf->set_int_at("network/port", port);
|
|
+ gpAppFrame->oStarDictClient.set_server(server, port);
|
|
+#if defined(CONFIG_GTK) || defined(CONFIG_GPE)
|
|
+ ch = gtk_entry_get_text(ePlayCommand);
|
|
+ if (ch[0])
|
|
+ conf->set_string_at("dictionary/play_command", ch);
|
|
+#endif
|
|
+ GtkTextBuffer *text_view_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tts_textview));
|
|
+ GtkTextIter start_iter;
|
|
+ GtkTextIter end_iter;
|
|
+ gtk_text_buffer_get_start_iter(text_view_buffer, &start_iter);
|
|
+ gtk_text_buffer_get_end_iter(text_view_buffer, &end_iter);
|
|
+ gchar *text = gtk_text_buffer_get_text(text_view_buffer, &start_iter, &end_iter, FALSE);
|
|
+ conf->set_string_at("dictionary/tts_path", text);
|
|
+ gpAppFrame->oReadWord.LoadRealTtsPath(text);
|
|
+ g_free(text);
|
|
+ gtk_widget_destroy(GTK_WIDGET(window));
|
|
+ window = NULL;
|
|
+ return false;
|
|
+ } else {
|
|
+ return true;
|
|
+ }
|
|
+}
|
|
+
|
|
+void PrefsDlg::Close()
|
|
+{
|
|
+ if (window) {
|
|
+ gtk_widget_destroy (window);
|
|
+ window = NULL;
|
|
+ }
|
|
+}
|
|
+
|
|
+#ifndef CONFIG_GPE
|
|
+void PrefsDlg::resize_categories_tree(void)
|
|
+{
|
|
+ //this is hack for prevet horizontaly scrolling
|
|
+ //if you know how it make better, just write
|
|
+ GtkRequisition rtv, rsw;
|
|
+ gtk_widget_size_request(categories_tree, &rtv);
|
|
+ gtk_widget_size_request(GTK_SCROLLED_WINDOW(categories_window)->vscrollbar, &rsw);
|
|
+ gtk_widget_set_size_request(categories_window, rtv.width+rsw.width+25, -1);
|
|
+}
|
|
+#endif
|
|
diff -Nur stardict-3.0.1.orig//src/readword.cpp stardict-3.0.1/src/readword.cpp
|
|
--- stardict-3.0.1.orig//src/readword.cpp 2007-07-10 02:16:04.000000000 -0500
|
|
+++ stardict-3.0.1/src/readword.cpp 2010-05-24 00:53:36.380667202 -0500
|
|
@@ -3,6 +3,7 @@
|
|
#endif
|
|
|
|
#include <cstring>
|
|
+#include <cstdlib>
|
|
#include <string>
|
|
|
|
#include <glib/gi18n.h>
|
|
diff -Nur stardict-3.0.1.orig//src/sigc++/signal.h stardict-3.0.1/src/sigc++/signal.h
|
|
--- stardict-3.0.1.orig//src/sigc++/signal.h 2007-07-10 02:16:01.000000000 -0500
|
|
+++ stardict-3.0.1/src/sigc++/signal.h 2010-05-24 00:53:36.381666157 -0500
|
|
@@ -18,7 +18,7 @@
|
|
//Compilers, such as older versions of SUN Forte C++, that do not allow this also often
|
|
//do not allow a typedef to have the same name as a class in the typedef's definition.
|
|
//For Sun Forte CC 5.7 (SUN Workshop 10), comment this out to fix the build.
|
|
- #define SIGC_TYPEDEF_REDEFINE_ALLOWED 1
|
|
+// #define SIGC_TYPEDEF_REDEFINE_ALLOWED 1
|
|
#endif
|
|
|
|
namespace sigc {
|
|
diff -Nur stardict-3.0.1.orig//src/utils.cpp stardict-3.0.1/src/utils.cpp
|
|
--- stardict-3.0.1.orig//src/utils.cpp 2007-10-21 21:25:02.000000000 -0500
|
|
+++ stardict-3.0.1/src/utils.cpp 2010-05-24 00:53:36.381666157 -0500
|
|
@@ -22,6 +22,8 @@
|
|
# include "config.h"
|
|
#endif
|
|
|
|
+#include <cstring>
|
|
+
|
|
#include <glib.h>
|
|
#include <glib/gi18n.h>
|
|
#include <cstdlib>
|
|
diff -Nur stardict-3.0.1.orig//src/utils.cpp~ stardict-3.0.1/src/utils.cpp~
|
|
--- stardict-3.0.1.orig//src/utils.cpp~ 1969-12-31 18:00:00.000000000 -0600
|
|
+++ stardict-3.0.1/src/utils.cpp~ 2007-10-21 21:25:02.000000000 -0500
|
|
@@ -0,0 +1,203 @@
|
|
+/*
|
|
+ * This file part of StarDict - A international dictionary for GNOME.
|
|
+ * http://stardict.sourceforge.net
|
|
+ * Copyright (C) 2005-2006 Evgeniy <dushistov@mail.ru>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 3 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU Library General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
+ */
|
|
+
|
|
+#ifdef HAVE_CONFIG_H
|
|
+# include "config.h"
|
|
+#endif
|
|
+
|
|
+#include <glib.h>
|
|
+#include <glib/gi18n.h>
|
|
+#include <cstdlib>
|
|
+#include <gtk/gtk.h>
|
|
+
|
|
+#ifdef CONFIG_GNOME
|
|
+# include <libgnome/libgnome.h>
|
|
+# include <libgnomeui/libgnomeui.h>
|
|
+#elif defined(_WIN32)
|
|
+# include <gdk/gdkwin32.h>
|
|
+#endif
|
|
+
|
|
+#include "utils.h"
|
|
+
|
|
+
|
|
+void ProcessGtkEvent()
|
|
+{
|
|
+ while (gtk_events_pending())
|
|
+ gtk_main_iteration();
|
|
+}
|
|
+
|
|
+std::string get_user_config_dir()
|
|
+{
|
|
+ const gchar *config_path_from_env = g_getenv("STARDICT_CONFIG_PATH");
|
|
+ if (config_path_from_env)
|
|
+ return config_path_from_env;
|
|
+#ifdef _WIN32
|
|
+ std::string res = g_get_user_config_dir();
|
|
+ res += G_DIR_SEPARATOR_S "StarDict";
|
|
+ return res;
|
|
+#else
|
|
+ std::string res;
|
|
+ gchar *tmp = g_build_filename(g_get_home_dir(), ".stardict", NULL);
|
|
+ res=tmp;
|
|
+ g_free(tmp);
|
|
+ return res;
|
|
+#endif
|
|
+}
|
|
+
|
|
+std::string combnum2str(gint comb_code)
|
|
+{
|
|
+ switch (comb_code) {
|
|
+#ifdef _WIN32
|
|
+ case 0:
|
|
+ return "Shift";
|
|
+ case 1:
|
|
+ return "Alt";
|
|
+ case 2:
|
|
+ return "Ctrl";
|
|
+ case 3:
|
|
+ return "Ctrl+Alt";
|
|
+#else
|
|
+ case 0:
|
|
+ return "Win";
|
|
+ case 1:
|
|
+ return "Shift";
|
|
+ case 2:
|
|
+ return "Alt";
|
|
+ case 3:
|
|
+ return "Ctrl";
|
|
+ case 4:
|
|
+ return "Ctrl+Alt";
|
|
+ case 5:
|
|
+ return "Ctrl+e";
|
|
+ case 6:
|
|
+ return "F1";
|
|
+ case 7:
|
|
+ return "F2";
|
|
+ case 8:
|
|
+ return "F3";
|
|
+ case 9:
|
|
+ return "F4";
|
|
+#endif
|
|
+ default:
|
|
+ return "";
|
|
+ }
|
|
+}
|
|
+
|
|
+std::vector<std::string> split(const std::string& str, char sep)
|
|
+{
|
|
+ std::vector<std::string> res;
|
|
+ std::string::size_type prev_pos=0, pos = 0;
|
|
+ while ((pos=str.find(sep, prev_pos))!=std::string::npos) {
|
|
+ res.push_back(std::string(str, prev_pos, pos-prev_pos));
|
|
+ prev_pos=pos+1;
|
|
+ }
|
|
+ res.push_back(std::string(str, prev_pos, str.length()-prev_pos));
|
|
+
|
|
+ return res;
|
|
+}
|
|
+
|
|
+GdkPixbuf *load_image_from_file(const std::string& filename)
|
|
+{
|
|
+ GError *err=NULL;
|
|
+ GdkPixbuf *res=gdk_pixbuf_new_from_file(filename.c_str(), &err);
|
|
+ if (!res) {
|
|
+ GtkWidget *message_dlg =
|
|
+ gtk_message_dialog_new(
|
|
+ NULL,
|
|
+ (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
|
|
+ GTK_MESSAGE_ERROR,
|
|
+ GTK_BUTTONS_OK,
|
|
+ _("Can not load image. %s"), err->message);
|
|
+
|
|
+ gtk_dialog_set_default_response(GTK_DIALOG(message_dlg), GTK_RESPONSE_OK);
|
|
+
|
|
+ gtk_window_set_resizable(GTK_WINDOW(message_dlg), FALSE);
|
|
+
|
|
+ gtk_dialog_run(GTK_DIALOG(message_dlg));
|
|
+ gtk_widget_destroy(message_dlg);
|
|
+ g_error_free(err);
|
|
+ exit(EXIT_FAILURE);
|
|
+ }
|
|
+
|
|
+ return res;
|
|
+}
|
|
+
|
|
+static gchar * byte_to_hex(unsigned char nr) {
|
|
+ gchar *result = NULL;
|
|
+
|
|
+ result = g_strdup_printf("%%%x%x", nr / 0x10, nr % 0x10);
|
|
+ return result;
|
|
+}
|
|
+
|
|
+char *common_encode_uri_string(const char *string)
|
|
+{
|
|
+ gchar *newURIString;
|
|
+ gchar *hex, *tmp = NULL;
|
|
+ int i, j, len, bytes;
|
|
+
|
|
+ /* the UTF-8 string is casted to ASCII to treat
|
|
+ the characters bytewise and convert non-ASCII
|
|
+ compatible chars to URI hexcodes */
|
|
+ newURIString = g_strdup("");
|
|
+ len = strlen(string);
|
|
+ for(i = 0; i < len; i++) {
|
|
+ if(g_ascii_isalnum(string[i]) || strchr("-_.!~*'()", (int)string[i]))
|
|
+ tmp = g_strdup_printf("%s%c", newURIString, string[i]);
|
|
+ else if(string[i] == ' ')
|
|
+ tmp = g_strdup_printf("%s%%20", newURIString);
|
|
+ else if((unsigned char)string[i] <= 127) {
|
|
+ tmp = g_strdup_printf("%s%s", newURIString, hex = byte_to_hex(string[i]));g_free(hex);
|
|
+ } else {
|
|
+ bytes = 0;
|
|
+ if(((unsigned char)string[i] >= 192) && ((unsigned char)string[i] <= 223))
|
|
+ bytes = 2;
|
|
+ else if(((unsigned char)string[i] > 223) && ((unsigned char)string[i] <= 239))
|
|
+ bytes = 3;
|
|
+ else if(((unsigned char)string[i] > 239) && ((unsigned char)string[i] <= 247))
|
|
+ bytes = 4;
|
|
+ else if(((unsigned char)string[i] > 247) && ((unsigned char)string[i] <= 251))
|
|
+ bytes = 5;
|
|
+ else if(((unsigned char)string[i] > 247) && ((unsigned char)string[i] <= 251))
|
|
+ bytes = 6;
|
|
+
|
|
+ if(0 != bytes) {
|
|
+ if((i + (bytes - 1)) > len) {
|
|
+ g_warning(("Unexpected end of character sequence or corrupt UTF-8 encoding! Some characters were dropped!"));
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ for(j=0; j < (bytes - 1); j++) {
|
|
+ tmp = g_strdup_printf("%s%s", newURIString, hex = byte_to_hex((unsigned char)string[i++]));
|
|
+ g_free(hex);
|
|
+ g_free(newURIString);
|
|
+ newURIString = tmp;
|
|
+ }
|
|
+ tmp = g_strdup_printf("%s%s", newURIString, hex = byte_to_hex((unsigned char)string[i]));
|
|
+ g_free(hex);
|
|
+ } else {
|
|
+ /* sh..! */
|
|
+ g_error("Internal error while converting UTF-8 chars to HTTP URI!");
|
|
+ }
|
|
+ }
|
|
+ g_free(newURIString);
|
|
+ newURIString = tmp;
|
|
+ }
|
|
+ return newURIString;
|
|
+}
|
|
diff -Nur stardict-3.0.1.orig//src/x11_iskeyspressed.hpp stardict-3.0.1/src/x11_iskeyspressed.hpp
|
|
--- stardict-3.0.1.orig//src/x11_iskeyspressed.hpp 2007-07-10 02:16:04.000000000 -0500
|
|
+++ stardict-3.0.1/src/x11_iskeyspressed.hpp 2010-05-24 00:53:36.381666157 -0500
|
|
@@ -1,6 +1,8 @@
|
|
#ifndef _X11_ISKEYSPRESSED_HPP_
|
|
#define _X11_ISKEYSPRESSED_HPP_
|
|
|
|
+#include <memory>
|
|
+
|
|
#include <gdk/gdkx.h>
|
|
#include <X11/keysym.h>
|
|
#include <gtk/gtk.h>
|
|
diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-dictdotcn-plugin/stardict_dictdotcn.cpp stardict-3.0.1/stardict-plugins/stardict-dictdotcn-plugin/stardict_dictdotcn.cpp
|
|
--- stardict-3.0.1.orig//stardict-plugins/stardict-dictdotcn-plugin/stardict_dictdotcn.cpp 2007-10-10 04:28:29.000000000 -0500
|
|
+++ stardict-3.0.1/stardict-plugins/stardict-dictdotcn-plugin/stardict_dictdotcn.cpp 2010-05-24 00:53:36.381666157 -0500
|
|
@@ -1,6 +1,6 @@
|
|
#include "stardict_dictdotcn.h"
|
|
#include <glib/gi18n.h>
|
|
-#include <string>
|
|
+#include <cstring>
|
|
#include <list>
|
|
|
|
#ifdef _WIN32
|
|
diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-espeak-tts-plugin/stardict_espeak.cpp stardict-3.0.1/stardict-plugins/stardict-espeak-tts-plugin/stardict_espeak.cpp
|
|
--- stardict-3.0.1.orig//stardict-plugins/stardict-espeak-tts-plugin/stardict_espeak.cpp 2007-09-19 03:27:18.000000000 -0500
|
|
+++ stardict-3.0.1/stardict-plugins/stardict-espeak-tts-plugin/stardict_espeak.cpp 2010-05-24 00:53:36.382665737 -0500
|
|
@@ -1,4 +1,5 @@
|
|
#include "stardict_espeak.h"
|
|
+#include <cstring>
|
|
#include <espeak/speak_lib.h>
|
|
#include <glib/gi18n.h>
|
|
|
|
diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-gucharmap-plugin/stardict_gucharmap.cpp stardict-3.0.1/stardict-plugins/stardict-gucharmap-plugin/stardict_gucharmap.cpp
|
|
--- stardict-3.0.1.orig//stardict-plugins/stardict-gucharmap-plugin/stardict_gucharmap.cpp 2007-08-31 02:10:41.000000000 -0500
|
|
+++ stardict-3.0.1/stardict-plugins/stardict-gucharmap-plugin/stardict_gucharmap.cpp 2010-05-24 00:53:36.382665737 -0500
|
|
@@ -1,7 +1,8 @@
|
|
#include "stardict_gucharmap.h"
|
|
#include <glib/gi18n.h>
|
|
#include <gucharmap/gucharmap.h>
|
|
-#include <string>
|
|
+#include <cstring>
|
|
+#include <cstdlib>
|
|
|
|
static char *build_dictdata(char type, const char *definition)
|
|
{
|
|
diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-html-parsedata-plugin/stardict_html_parsedata.cpp stardict-3.0.1/stardict-plugins/stardict-html-parsedata-plugin/stardict_html_parsedata.cpp
|
|
--- stardict-3.0.1.orig//stardict-plugins/stardict-html-parsedata-plugin/stardict_html_parsedata.cpp 2007-09-13 02:51:55.000000000 -0500
|
|
+++ stardict-3.0.1/stardict-plugins/stardict-html-parsedata-plugin/stardict_html_parsedata.cpp 2010-05-24 00:53:36.382665737 -0500
|
|
@@ -1,4 +1,6 @@
|
|
#include "stardict_html_parsedata.h"
|
|
+#include <cstring>
|
|
+#include <cstdlib>
|
|
#include <glib/gi18n.h>
|
|
|
|
#ifdef _WIN32
|
|
diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-man-plugin/stardict_man.cpp stardict-3.0.1/stardict-plugins/stardict-man-plugin/stardict_man.cpp
|
|
--- stardict-3.0.1.orig//stardict-plugins/stardict-man-plugin/stardict_man.cpp 2007-09-19 03:30:54.000000000 -0500
|
|
+++ stardict-3.0.1/stardict-plugins/stardict-man-plugin/stardict_man.cpp 2010-05-24 00:53:36.382665737 -0500
|
|
@@ -1,6 +1,6 @@
|
|
#include "stardict_man.h"
|
|
#include <glib/gi18n.h>
|
|
-#include <string>
|
|
+#include <cstring>
|
|
|
|
static const StarDictPluginSystemInfo *plugin_info = NULL;
|
|
static bool need_prefix;
|
|
diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-powerword-parsedata-plugin/stardict_powerword_parsedata.cpp stardict-3.0.1/stardict-plugins/stardict-powerword-parsedata-plugin/stardict_powerword_parsedata.cpp
|
|
--- stardict-3.0.1.orig//stardict-plugins/stardict-powerword-parsedata-plugin/stardict_powerword_parsedata.cpp 2007-10-25 03:16:37.000000000 -0500
|
|
+++ stardict-3.0.1/stardict-plugins/stardict-powerword-parsedata-plugin/stardict_powerword_parsedata.cpp 2010-05-24 00:53:36.382665737 -0500
|
|
@@ -1,4 +1,5 @@
|
|
#include "stardict_powerword_parsedata.h"
|
|
+#include <cstring>
|
|
#include <glib/gi18n.h>
|
|
|
|
#ifdef _WIN32
|
|
diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-qqwry-plugin/stardict_qqwry.cpp stardict-3.0.1/stardict-plugins/stardict-qqwry-plugin/stardict_qqwry.cpp
|
|
--- stardict-3.0.1.orig//stardict-plugins/stardict-qqwry-plugin/stardict_qqwry.cpp 2007-11-02 03:41:26.000000000 -0500
|
|
+++ stardict-3.0.1/stardict-plugins/stardict-qqwry-plugin/stardict_qqwry.cpp 2010-05-24 00:53:36.382665737 -0500
|
|
@@ -1,7 +1,8 @@
|
|
#include "stardict_qqwry.h"
|
|
#include <glib/gi18n.h>
|
|
#include <glib/gstdio.h>
|
|
-#include <string>
|
|
+#include <cstring>
|
|
+#include <cstdlib>
|
|
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-spell-plugin/stardict_spell.cpp stardict-3.0.1/stardict-plugins/stardict-spell-plugin/stardict_spell.cpp
|
|
--- stardict-3.0.1.orig//stardict-plugins/stardict-spell-plugin/stardict_spell.cpp 2007-09-19 03:29:21.000000000 -0500
|
|
+++ stardict-3.0.1/stardict-plugins/stardict-spell-plugin/stardict_spell.cpp 2010-05-24 00:53:36.383666084 -0500
|
|
@@ -1,4 +1,5 @@
|
|
#include "stardict_spell.h"
|
|
+#include <cstring>
|
|
#include <glib.h>
|
|
#include <glib/gi18n.h>
|
|
#include <enchant.h>
|
|
diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-wiki-parsedata-plugin/stardict_wiki2xml.cpp stardict-3.0.1/stardict-plugins/stardict-wiki-parsedata-plugin/stardict_wiki2xml.cpp
|
|
--- stardict-3.0.1.orig//stardict-plugins/stardict-wiki-parsedata-plugin/stardict_wiki2xml.cpp 2007-07-10 02:16:15.000000000 -0500
|
|
+++ stardict-3.0.1/stardict-plugins/stardict-wiki-parsedata-plugin/stardict_wiki2xml.cpp 2010-05-24 00:53:36.383666084 -0500
|
|
@@ -1,5 +1,6 @@
|
|
#include "stardict_wiki2xml.h"
|
|
#include "WIKI2XML.h"
|
|
+#include <cstring>
|
|
#include <glib.h>
|
|
|
|
std::string wiki2xml(std::string &str)
|
|
diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-wiki-parsedata-plugin/stardict_wiki_parsedata.cpp stardict-3.0.1/stardict-plugins/stardict-wiki-parsedata-plugin/stardict_wiki_parsedata.cpp
|
|
--- stardict-3.0.1.orig//stardict-plugins/stardict-wiki-parsedata-plugin/stardict_wiki_parsedata.cpp 2007-08-31 01:41:21.000000000 -0500
|
|
+++ stardict-3.0.1/stardict-plugins/stardict-wiki-parsedata-plugin/stardict_wiki_parsedata.cpp 2010-05-24 00:53:36.383666084 -0500
|
|
@@ -1,5 +1,6 @@
|
|
#include "stardict_wiki_parsedata.h"
|
|
#include "stardict_wiki2xml.h"
|
|
+#include <cstring>
|
|
#include <glib/gi18n.h>
|
|
|
|
#ifdef _WIN32
|
|
diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-wordnet-plugin/court_widget.cpp stardict-3.0.1/stardict-plugins/stardict-wordnet-plugin/court_widget.cpp
|
|
--- stardict-3.0.1.orig//stardict-plugins/stardict-wordnet-plugin/court_widget.cpp 2007-10-17 20:36:22.000000000 -0500
|
|
+++ stardict-3.0.1/stardict-plugins/stardict-wordnet-plugin/court_widget.cpp 2010-05-24 00:53:36.383666084 -0500
|
|
@@ -1,4 +1,5 @@
|
|
#include "court_widget.h"
|
|
+#include <cstring>
|
|
#include <math.h>
|
|
#include <list>
|
|
|
|
diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-wordnet-plugin/stardict_wordnet.cpp stardict-3.0.1/stardict-plugins/stardict-wordnet-plugin/stardict_wordnet.cpp
|
|
--- stardict-3.0.1.orig//stardict-plugins/stardict-wordnet-plugin/stardict_wordnet.cpp 2007-10-14 22:32:04.000000000 -0500
|
|
+++ stardict-3.0.1/stardict-plugins/stardict-wordnet-plugin/stardict_wordnet.cpp 2010-05-24 00:53:36.383666084 -0500
|
|
@@ -1,5 +1,6 @@
|
|
#include "stardict_wordnet.h"
|
|
#include "court_widget.h"
|
|
+#include <cstring>
|
|
#include <glib/gi18n.h>
|
|
|
|
#ifdef _WIN32
|
|
diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-wordnet-plugin/stardict_wordnet_parsedata.cpp stardict-3.0.1/stardict-plugins/stardict-wordnet-plugin/stardict_wordnet_parsedata.cpp
|
|
--- stardict-3.0.1.orig//stardict-plugins/stardict-wordnet-plugin/stardict_wordnet_parsedata.cpp 2007-10-10 04:39:10.000000000 -0500
|
|
+++ stardict-3.0.1/stardict-plugins/stardict-wordnet-plugin/stardict_wordnet_parsedata.cpp 2010-05-24 00:53:36.383666084 -0500
|
|
@@ -1,4 +1,5 @@
|
|
#include "stardict_wordnet_parsedata.h"
|
|
+#include <cstring>
|
|
#include <glib/gi18n.h>
|
|
|
|
#ifdef _WIN32
|
|
diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-xdxf-parsedata-plugin/stardict_xdxf_parsedata.cpp stardict-3.0.1/stardict-plugins/stardict-xdxf-parsedata-plugin/stardict_xdxf_parsedata.cpp
|
|
--- stardict-3.0.1.orig//stardict-plugins/stardict-xdxf-parsedata-plugin/stardict_xdxf_parsedata.cpp 2007-08-31 01:41:54.000000000 -0500
|
|
+++ stardict-3.0.1/stardict-plugins/stardict-xdxf-parsedata-plugin/stardict_xdxf_parsedata.cpp 2010-05-24 00:53:36.384665734 -0500
|
|
@@ -1,4 +1,5 @@
|
|
#include "stardict_xdxf_parsedata.h"
|
|
+#include <cstring>
|
|
#include <glib/gi18n.h>
|
|
|
|
#ifdef _WIN32
|
|
diff -Nur stardict-3.0.1.orig//tests/t_config_file.cpp stardict-3.0.1/tests/t_config_file.cpp
|
|
--- stardict-3.0.1.orig//tests/t_config_file.cpp 2007-07-10 02:16:04.000000000 -0500
|
|
+++ stardict-3.0.1/tests/t_config_file.cpp 2010-05-24 00:53:36.384665734 -0500
|
|
@@ -8,6 +8,7 @@
|
|
#include <cstring>
|
|
#include <iterator>
|
|
#include <iostream>
|
|
+#include <memory>
|
|
#include <gtk/gtk.h>
|
|
|
|
#include "config_file.hpp"
|
|
diff -Nur stardict-3.0.1.orig//tests/t_xml.cpp stardict-3.0.1/tests/t_xml.cpp
|
|
--- stardict-3.0.1.orig//tests/t_xml.cpp 2007-07-10 02:16:04.000000000 -0500
|
|
+++ stardict-3.0.1/tests/t_xml.cpp 2010-05-24 00:53:36.384665734 -0500
|
|
@@ -5,6 +5,7 @@
|
|
#include <glib.h>
|
|
#include <cstdlib>
|
|
#include <string>
|
|
+#include <cstring>
|
|
|
|
|
|
static void xml_decode(const char *str, std::string& decoded)
|