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 + #include #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 + * + * 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 + +#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::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& 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(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& slist) +{ + if (!gconf_client) + return; + + GSList *gslist = NULL; + for (std::list::const_iterator p = slist.begin(); + p!=slist.end(); ++p) + gslist = g_slist_append(gslist, const_cast(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 *ch = + static_cast< sigc::signal *>(user_data); + std::auto_ptr cv; + switch (entry->value->type) { + case GCONF_VALUE_BOOL: + cv.reset(new confval); + static_cast *>(cv.get())->val_ = + gconf_value_get_bool(entry->value); + break; + case GCONF_VALUE_INT: + cv.reset(new confval); + static_cast *>(cv.get())->val_ = + gconf_value_get_int(entry->value); + break; + case GCONF_VALUE_STRING: { + cv.reset(new confval); + const gchar *gconf_val = gconf_value_get_string(entry->value); + if (gconf_val) + static_cast *>(cv.get())->val_ = + gconf_val; + } + case GCONF_VALUE_LIST: { + confval > *newval = + new confval >; + cv.reset(newval); + GSList *gslist = gconf_value_get_list(entry->value); + + + GSList *p = gslist; + while (p) { + newval->val_.push_back(static_cast(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 *bcv = + static_cast< sigc::signal *>(data); + delete bcv; +} + +void gconf_file::notify_add(const gchar *sect, const gchar *key, + const sigc::slot& slot) +{ + std::string name = std::string(sect) + "/" + key; + sigc::signal *ch = + new sigc::signal; + 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 #include #include +#include #include #include #include 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 + * + * 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 +#include +#include +#include +#include +#include + +#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 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& 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& slist) +{ + size_t len = slist.size(); + std::vector glib_list(len + 1); + + std::list::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& slot) +{ + std::string name = std::string(sect) + "/" + key; + + ChangeEventsMap::iterator it = + change_events_map_.insert( + std::make_pair(name, + sigc::signal())).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 +#include 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 +#include 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; iread(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; iread(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 &SearchWords, guint32 idxitem_offset, guint32 idxitem_size, gchar *origin_data) +{ + int nWord = SearchWords.size(); + std::vector 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 #include +#include #ifndef _WIN32 # include 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 +#include 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 +#include +#include #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 + * + * 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 +#include + +#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 StarDictClient::on_error_; +sigc::signal StarDictClient::on_lookup_end_; +sigc::signal StarDictClient::on_floatwin_lookup_end_; +sigc::signal StarDictClient::on_register_end_; +sigc::signal StarDictClient::on_getdictmask_end_; +sigc::signal StarDictClient::on_dirinfo_end_; +sigc::signal StarDictClient::on_dictinfo_end_; +sigc::signal StarDictClient::on_maxdictcount_end_; +sigc::signal *> StarDictClient::on_previous_end_; +sigc::signal *> 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::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::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::iterator i = datalist.begin(); i != datalist.end(); ++i) { + g_free(*i); + } +} + +STARDICT::LookupResponse::~LookupResponse() +{ + if (listtype == ListType_List) { + for (std::list::iterator i = wordlist->begin(); i != wordlist->end(); ++i) { + g_free(*i); + } + delete wordlist; + } else if (listtype == ListType_Tree) { + for (std::list::iterator i = wordtree->begin(); i != wordtree->end(); ++i) { + g_free((*i)->bookname); + for (std::list::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::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::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::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::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::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::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 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::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::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(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(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; + 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; + } 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; + } + 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 #include "getuint32.h" +#include 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 +#include + +#include "common.hpp" +#include "distance.h" +#include "kmp.h" +#include "mapfile.hpp" + +#include "stddict.hpp" +#include +#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 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 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; i255. + return wordentry_buf; +} + +inline const gchar *offset_index::get_first_on_page_key(glong page_idx) +{ + if (page_idxmiddle.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_mtimebegin()+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; iwordoffset[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; iwordoffset[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; i0) { + 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; i0) { + 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; i255. + return wordentry_buf; +} + +inline const gchar *synonym_file::get_first_on_page_key(glong page_idx) +{ + if (page_idxmiddle.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; i0) { + 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 (idx2wordcount-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; igetWord(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; igetWord(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; igetWord(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; igetWord(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::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::iterator> eraselist; + for (std::list::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::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::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::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::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 > map_fromto; + gen_fromto_info(root_info_item, map_fromto); + cache_fromto+=""; + for (std::map >::iterator map_it = map_fromto.begin(); map_it != map_fromto.end(); ++map_it){ + cache_fromto+="first; + cache_fromto+="\">"; + std::list &fromTo = map_it->second; + for (std::list::iterator i = fromTo.begin() ; i!= fromTo.end(); ++i){ + cache_fromto+="to; + cache_fromto+="\">"; + std::list &fromtoinfo = i->fromto_info; + for (std::list::iterator j = fromtoinfo.begin() ; j!= fromtoinfo.end(); ++j){ + cache_fromto+=""; + cache_fromto+=j->uid; + cache_fromto+=""; + cache_fromto+= j->bookname; + cache_fromto+=""; + } + cache_fromto+=""; + } + cache_fromto+=""; + } + cache_fromto+=""; + } + return cache_fromto; +} + +void Libs::gen_fromto_info(struct DictInfoItem *info_item, std::map > &map_fromto) { + gchar *etext; + for(std::list::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 >::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 list_fromtoinfo ; + list_fromtoinfo.push_back(fromtoinfo); + FromTo new_fromTo; + new_fromTo.to = to_str; + new_fromTo.fromto_info = list_fromtoinfo; + std::list 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_list = fromto1->second; + std::string from_name1 = fromto1->first; + bool found = false; + for (std::list::iterator new_fromTo = fromTo_list.begin(); new_fromTo != fromTo_list.end(); ++new_fromTo) { + if(to_str == new_fromTo->to) { + std::list &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 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::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 += ""; + dir->info_string += path; + dir->info_string += ""; + gchar *etext; + for (std::list::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->info_string += (*i)->dir->name; + dir->info_string += ""; + dir->info_string += (*i)->dir->dirname; + dir->info_string += ""; + gchar *dictcount = g_strdup_printf("%u", (*i)->dir->dictcount); + dir->info_string += dictcount; + g_free(dictcount); + dir->info_string += ""; + } else { + dir->info_string += ""; + if ((*i)->isdir == 2) + dir->info_string += "1"; + if ((*i)->dict->level != 0) { + dir->info_string += ""; + gchar *level = g_strdup_printf("%u", (*i)->dict->level); + dir->info_string += level; + g_free(level); + dir->info_string += ""; + } + dir->info_string += ""; + dir->info_string += (*i)->dict->uid; + dir->info_string += ""; + etext = g_markup_escape_text(oLib[(*i)->dict->id]->dict_name().c_str(), -1); + dir->info_string += etext; + g_free(etext); + dir->info_string += ""; + gchar *wc = g_strdup_printf("%ld", oLib[(*i)->dict->id]->narticles()); + dir->info_string += wc; + g_free(wc); + dir->info_string += ""; + } + } + } + return &(dir->info_string); +} + +int Libs::get_dict_level(const char *uid) +{ + std::map::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 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::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::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->short_info_string += uid; + dict->short_info_string += ""; + 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 += ""; + gchar *wc = g_strdup_printf("%ld", oLib[dict->id]->narticles()); + dict->short_info_string += wc; + g_free(wc); + dict->short_info_string += ""; + } + 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 += ""; + etext = g_markup_escape_text(dict_info.bookname.c_str(), -1); + dict->info_string += etext; + g_free(etext); + dict->info_string += ""; + gchar *wc = g_strdup_printf("%u", dict_info.wordcount); + dict->info_string += wc; + g_free(wc); + dict->info_string += ""; + if (dict_info.synwordcount!=0) { + dict->info_string += ""; + wc = g_strdup_printf("%u", dict_info.synwordcount); + dict->info_string += wc; + g_free(wc); + dict->info_string += ""; + } + dict->info_string += ""; + etext = g_markup_escape_text(dict_info.author.c_str(), -1); + dict->info_string += etext; + g_free(etext); + dict->info_string += ""; + etext = g_markup_escape_text(dict_info.email.c_str(), -1); + dict->info_string += etext; + g_free(etext); + dict->info_string += ""; + etext = g_markup_escape_text(dict_info.website.c_str(), -1); + dict->info_string += etext; + g_free(etext); + dict->info_string += ""; + etext = g_markup_escape_text(dict_info.description.c_str(), -1); + dict->info_string += etext; + g_free(etext); + dict->info_string += ""; + etext = g_markup_escape_text(dict_info.date.c_str(), -1); + dict->info_string += etext; + g_free(etext); + dict->info_string += ""; + etext = g_markup_escape_text(dict->download.c_str(), -1); + dict->info_string += etext; + g_free(etext); + dict->info_string += ""; + } + return &(dict->info_string); + } +} + +void Libs::SetServerDictMask(std::vector &dictmask, const char *dicts, int max, int userLevel) +{ + InstantDictIndex instance_dict_index; + instance_dict_index.type = InstantDictType_LOCAL; + dictmask.clear(); + std::list 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::iterator uid_iter; + for (std::list::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 &dictmask, CollateFunctions cltfuc) +{ + for (std::vector::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::size_type i =0; i < oLib.size(); i++) { + if (oLib[i]->ifofilename() == filename) { + iLib = i; + return true; + } + } + return false; +} + +void Libs::load(std::list &load_list) +{ + for (std::list::iterator i = load_list.begin(); i != load_list.end(); ++i) { + load_dict(*i, show_progress); + } +} + +void Libs::reload(std::list &load_list, int is_coll_enb, int collf) +{ + if (is_coll_enb == EnableCollationLevel && collf == CollateFunction) { + std::vector prev(oLib); + oLib.clear(); + for (std::list::iterator i = load_list.begin(); i != load_list.end(); ++i) { + std::vector::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::iterator it=prev.begin(); it!=prev.end(); ++it) { + delete *it; + } + } else { + for (std::vector::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 &dictmask, int servercollatefunc) +{ + const gchar *poCurrentWord = NULL; + const gchar *word; + gint best =0; + gint back; + std::vector::size_type iLib; + std::vector::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 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 &dictmask, int servercollatefunc) +{ + const gchar *poCurrentWord = NULL; + const gchar *word; + std::vector::size_type iLib; + std::vector::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=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 &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::size_type iCurrentLib=0, iCurrentRealLib=0; + bool isLib = false; + const gchar *word; + + std::vector::size_type iLib; + std::vector::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 &dictmask, int servercollatefunc) +{ + // used by TopWin::PreviousCallback(); the iCurrent is cached by AppCore::TopWinWordChange(); + const gchar *poCurrentWord = NULL; + std::vector::size_type iCurrentLib=0, iCurrentRealLib=0; + bool isLib = false; + + const gchar *word; + glong pidx; + std::vector::size_type iLib; + std::vector::size_type iRealLib; + for (iLib=0;iLibLookup(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;iLibLookupSynonym(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=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=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 &dictmask) +{ + if (sWord[0] == '\0') + return false; + + std::vector oFuzzystruct(reslist_size); + + for (int i=0; i::size_type iRealLib; + for (std::vector::size_type iLib=0; iLibsyn_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=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) + 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 &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::size_type iRealLib; + for (std::vector::size_type iLib=0; iLibLookupWithRule(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; jLookupWithRuleSynonym(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 &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::size_type iRealLib; + for (std::vector::size_type iLib=0; iLibLookupWithRegex(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; jLookupWithRegexSynonym(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 *reslist, updateSearchDialog_func search_func, gpointer search_data, bool *cancel, std::vector &dictmask) +{ + std::vector 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::size_type i=0; i::size_type iRealLib; + for (std::vector::size_type i=0; icontainSearchData()) + continue; + const gulong iwords = narticles(iRealLib); + const gchar *key; + guint32 offset, size; + for (gulong j=0; jget_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::size_type i; + for (i=0; istorage == 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 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::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 + #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 + * + * 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 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 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::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("[Image:%s]", label); + append_pango_text(markup); + g_free(markup); + } else { + append_pango_text("[Image]"); + } +} + +void LabelPangoWidget::append_widget(GtkWidget *widget) +{ + append_pango_text("[Widget]"); + 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::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(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(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 + #include #include 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 +#include + +#ifdef _WIN32 +# include +#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("%s", 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::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 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 &web_list= + conf->get_strlist_at("main_window/search_website_list"); + + GtkTreeIter iter; + for (std::list::const_iterator wit=web_list.begin(); + wit!=web_list.end(); ++wit) { + std::vector 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& 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 +#include #include #include 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 + #include #include #include 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 + * + * 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 +#include +#include +#include + +#ifdef CONFIG_GNOME +# include +# include +#elif defined(_WIN32) +# include +#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 split(const std::string& str, char sep) +{ + std::vector 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 + #include #include #include 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 -#include +#include #include #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 #include #include 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 #include -#include +#include +#include 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 +#include #include #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 -#include +#include 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 #include #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 #include -#include +#include +#include #ifdef _WIN32 #include 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 #include #include #include 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 #include 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 #include #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 #include #include 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 #include #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 #include #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 #include #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 #include #include +#include #include #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 #include #include +#include static void xml_decode(const char *str, std::string& decoded)