1 /* StarDict - A international dictionary for GNOME.
2  * Copyright (C) 2003-2007 Hu Zheng <huzheng001@gmail.com>
3  * Copyright 2011 kubtek <kubtek@mail.com>
4  *
5  * This file is part of StarDict.
6  *
7  * StarDict is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * StarDict is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with StarDict.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 /*
22  * Modified by the StarDict Team and others 2003-2006.  See the AUTHORS
23  * file for a list of people on the StarDict Team.  See the ChangeLog
24  * files for a list of changes.  These files are distributed with
25  * StarDict at http://www.stardict.org.
26  */
27 
28 
29 #ifdef HAVE_CONFIG_H
30 #  include "config.h"
31 #endif
32 
33 #include <cstring>
34 #include <cstdlib>
35 #include <cerrno>
36 #include <glib/gstdio.h>
37 #include <glib/gi18n.h>
38 #include <gdk/gdkkeysyms.h>
39 #include <iostream>
40 #include <sstream>
41 
42 #ifdef CONFIG_GNOME
43 #  include <libgnome/libgnome.h>
44 #endif
45 
46 #ifdef CONFIG_GNOME
47 #  include <bonobo/bonobo-main.h>
48 #  include "stardict-application-server.h"
49 #  include "GNOME_Stardict.h"
50 #endif
51 
52 #ifdef CONFIG_GPE
53 #  include <gpe/init.h>
54 #endif
55 
56 #ifdef CONFIG_MAEMO
57 #include "hildon-widgets/hildon-program.h"
58 #include "hildon-widgets/hildon-window.h"
59 #endif
60 
61 #ifdef _WIN32
62 #  include <gdk/gdkwin32.h>
63 #  include <windows.h>
64 #  include <io.h>
65 #  include <fcntl.h>
66 #  include "win32/intl.h"
67 #endif
68 
69 #include "desktop.h"
70 #include "splash.h"
71 #include "conf.h"
72 #include "lib/utils.h"
73 #include "prefsdlg.h"
74 #include "iskeyspressed.h"
75 #include "class_factory.h"
76 #include "progresswin.h"
77 #include "dictmanagedlg.h"
78 #include "pluginmanagedlg.h"
79 #include "prefsdlg.h"
80 #include "lib/netdictcache.h"
81 #include "lib/full_text_trans.h"
82 #include "log.h"
83 #include "cmdlineopts.h"
84 
85 #include "stardict.h"
86 
87 AppCore *gpAppFrame;
88 
89 /********************************************************************/
90 class change_cursor {
91 public:
change_cursor(GdkWindow * win_,GdkCursor * busy,GdkCursor * norm_)92 	change_cursor(GdkWindow *win_,GdkCursor *busy, GdkCursor *norm_):
93 		win(win_), norm(norm_) { gdk_window_set_cursor(win, busy); }
~change_cursor()94 	~change_cursor() { gdk_window_set_cursor(win, norm); }
95 private:
96 	GdkWindow *win;
97 	GdkCursor *norm;
98 };
99 /********************************************************************/
100 class gtk_show_progress_t : public show_progress_t {
101 public:
notify_about_work()102 	void notify_about_work() { ProcessGtkEvent(); }
103 } gtk_show_progress;
104 
105 /********************************************************************/
106 class reload_show_progress_t : public show_progress_t {
107 public:
reload_show_progress_t(progress_win & pw_)108 	reload_show_progress_t(progress_win &pw_) : pw(pw_) {}
notify_about_start(const std::string & title)109 	void notify_about_start(const std::string& title) {
110 		pw.display_action(title);
111 	}
notify_about_work()112 	void notify_about_work() {
113 		ProcessGtkEvent();
114 	}
115 private:
116 	progress_win &pw;
117 };
118 
119 /********************************************************************/
120 class load_show_progress_t : public show_progress_t {
121 public:
notify_about_start(const std::string & title)122 	void notify_about_start(const std::string& title) {
123 		stardict_splash.display_action(title);
124 	}
125 } load_show_progress;
126 
127 /********************************************************************/
AppCore()128 AppCore::AppCore() :
129 	oLibs(&gtk_show_progress,
130 	      conf->get_bool_at("dictionary/create_cache_file"),
131 	      conf->get_bool_at("dictionary/enable_collation") ? CollationLevel_SINGLE : CollationLevel_NONE,
132 	      int_to_colate_func(conf->get_int_at("dictionary/collate_function")))
133 {
134 	iCurrentIndex = NULL;
135 	word_change_timeout_id = 0;
136 	window = NULL; //need by save_yourself_cb().
137 	dict_manage_dlg = NULL;
138 	plugin_manage_dlg = NULL;
139 	prefs_dlg = NULL;
140 	oStarDictPlugins = NULL;
141 }
142 
~AppCore()143 AppCore::~AppCore()
144 {
145 	stop_word_change_timer();
146 	delete dict_manage_dlg;
147 	delete plugin_manage_dlg;
148 	delete prefs_dlg;
149 	g_free(iCurrentIndex);
150 	delete oStarDictPlugins;
151 	// window?
152 }
153 
on_change_scan(bool val)154 void AppCore::on_change_scan(bool val)
155 {
156 	conf->set_bool_at("dictionary/scan_selection", val);
157 }
158 
on_maximize()159 void AppCore::on_maximize()
160 {
161 	if (oTopWin.get_text()[0]) {
162 //so user can input word directly.
163 		gtk_widget_grab_focus(oMidWin.oTextWin.view->widget());
164 	} else {
165 		//this won't change selection text.
166 		oTopWin.grab_focus();
167 	}
168 }
169 
on_docklet_middle_button_click()170 void AppCore::on_docklet_middle_button_click()
171 {
172 	TNotifAreaMiddleClickAction action = TNotifAreaMiddleClickAction(
173 		conf->get_int_at("notification_area_icon/middle_click_action"));
174 	if (action == namclaQueryFloatWindow) {
175 		oSelection.LastClipWord.clear();
176 		gtk_selection_convert(oSelection.selection_widget,
177 				      GDK_SELECTION_PRIMARY,
178 				      oSelection.UTF8_STRING_Atom, GDK_CURRENT_TIME);
179 	} else if(action == namclaQueryMainWindow){
180 		oDockLet->maximize_from_tray();
181 		gtk_selection_convert(oMidWin.oTextWin.view->widget(),
182 				      GDK_SELECTION_PRIMARY,
183 				      oSelection.UTF8_STRING_Atom, GDK_CURRENT_TIME);
184 	}
185 }
186 
on_link_click(const std::string & link)187 void AppCore::on_link_click(const std::string &link)
188 {
189 	if (g_str_has_prefix(link.c_str(), "query://")) {
190 		oTopWin.InsertHisList(oTopWin.get_text());
191 		oTopWin.InsertBackList();
192 		oTopWin.SetText(link.c_str() + sizeof("query://") -1);
193 	} else if (g_str_has_prefix(link.c_str(), "bword://")) {
194 		oTopWin.InsertHisList(oTopWin.get_text());
195 		oTopWin.InsertBackList();
196 		oTopWin.SetText(link.c_str() + sizeof("bword://") -1);
197 	} else {
198 		show_url(link.c_str());
199 	}
200 }
201 
do_send_http_request(const char * shost,const char * sfile,get_http_response_func_t callback_func,gpointer userdata)202 void AppCore::do_send_http_request(const char* shost, const char* sfile, get_http_response_func_t callback_func, gpointer userdata)
203 {
204 	HttpClient *client = new HttpClient();
205 	client->on_error_.connect(sigc::mem_fun(gpAppFrame, &AppCore::on_http_client_error));
206 	client->on_response_.connect(sigc::mem_fun(gpAppFrame, &AppCore::on_http_client_response));
207 	gpAppFrame->oHttpManager.Add(client);
208 	client->SendHttpGetRequestWithCallback(shost, sfile, callback_func, userdata);
209 }
210 
set_news(const char * news,const char * links)211 void AppCore::set_news(const char *news, const char *links)
212 {
213 	gpAppFrame->oBottomWin.set_news(news, links);
214 }
215 
show_netdict_resp(const char * dict,NetDictResponse * resp,bool ismainwin)216 void AppCore::show_netdict_resp(const char *dict, NetDictResponse *resp, bool ismainwin)
217 {
218 	if (ismainwin)
219 		gpAppFrame->oMidWin.oTextWin.Show(resp);
220 	else {
221 		if(gpAppFrame->composite_lookup_float_win.got_net_dict_responce(dict, resp->word))
222 			gpAppFrame->oFloatWin.AppendTextNetDict(resp);
223 		if(gpAppFrame->composite_lookup_float_win.is_got_all_responses())
224 			gpAppFrame->oFloatWin.EndLookup();
225 	}
226 }
227 
lookup_dict(size_t dictid,const char * sWord,char **** Word,char ***** WordData)228 void AppCore::lookup_dict(size_t dictid, const char *sWord, char ****Word, char *****WordData)
229 {
230 	InstantDictIndex instance_dict_index;
231 	instance_dict_index.type = InstantDictType_LOCAL;
232 	instance_dict_index.index = dictid;
233 	std::vector<InstantDictIndex> dictmask;
234 	dictmask.push_back(instance_dict_index);
235 	bool bFound = false;
236 	gchar ***pppWord = (gchar ***)g_malloc(sizeof(gchar **) * dictmask.size());
237 	gchar ****ppppWordData = (gchar ****)g_malloc(sizeof(gchar ***) * dictmask.size());
238 	CurrentIndex *iIndex = (CurrentIndex *)g_malloc(sizeof(CurrentIndex) * dictmask.size());
239 	gpAppFrame->BuildResultData(dictmask, sWord, iIndex, NULL, 0, pppWord, ppppWordData, bFound, 2);
240 	*Word = pppWord;
241 	*WordData = ppppWordData;
242 	g_free(iIndex);
243 }
244 
ShowPangoTips(const char * word,const char * text)245 void AppCore::ShowPangoTips(const char *word, const char *text)
246 {
247 	gpAppFrame->oFloatWin.ShowPangoTips(word, text);
248 }
249 
Create(const gchar * queryword)250 void AppCore::Create(const gchar *queryword)
251 {
252 	if (conf->get_bool_at("dictionary/use_custom_font")) {
253 		const std::string &custom_font(conf->get_string_at("dictionary/custom_font"));
254 
255 		if (!custom_font.empty())	{
256 			gchar *aa =
257 				g_strdup_printf("style \"custom-font\" { font_name= \"%s\" }\n"
258 						"class \"GtkWidget\" style \"custom-font\"\n",
259 						custom_font.c_str());
260 #if GTK_MAJOR_VERSION >= 3
261 			GtkCssProvider *css_provider = gtk_css_provider_get_default();
262 			gtk_css_provider_load_from_data(css_provider, aa, -1, NULL);
263 #else
264 			gtk_rc_parse_string(aa);
265 #endif
266 			g_free(aa);
267 		}
268 	}
269 
270 #ifdef CONFIG_MAEMO
271 	HildonProgram *program;
272 	program = HILDON_PROGRAM(hildon_program_get_instance());
273 	g_set_application_name(_("StarDict"));
274 	window = hildon_window_new();
275 	hildon_program_add_window(program, HILDON_WINDOW(window));
276 #else
277 	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
278 #endif
279 
280 // Init oStarDictPlugins after we get window.
281 	oStarDictPluginSystemInfo.datadir = conf_dirs->get_data_dir();
282 	oStarDictPluginSystemInfo.mainwin = window;
283 	oStarDictPluginSystemService.send_http_request = do_send_http_request;
284 	oStarDictPluginSystemService.show_url = show_url;
285 	oStarDictPluginSystemService.set_news = set_news;
286 	oStarDictPluginSystemService.encode_uri_string = common_encode_uri_string;
287 	oStarDictPluginSystemService.netdict_save_cache_resp = netdict_save_cache_resp;
288 	oStarDictPluginSystemService.show_netdict_resp = show_netdict_resp;
289 	oStarDictPluginSystemService.lookup_dict = lookup_dict;
290 	oStarDictPluginSystemService.FreeResultData = FreeResultData;
291 	oStarDictPluginSystemService.ShowPangoTips = ShowPangoTips;
292 	std::list<DictItemId> plugin_new_install_list;
293 	UpdatePluginList(plugin_new_install_list);
294 #ifdef _WIN32
295 	std::list<std::string> plugin_order_list;
296 	std::list<std::string> plugin_disable_list;
297 	{
298 		const std::list<std::string>& plugin_order_list_rel
299 			= conf->get_strlist("/apps/stardict/manage_plugins/plugin_order_list");
300 		const std::list<std::string>& plugin_disable_list_rel
301 			= conf->get_strlist("/apps/stardict/manage_plugins/plugin_disable_list");
302 		abs_path_to_data_dir(plugin_order_list_rel, plugin_order_list);
303 		abs_path_to_data_dir(plugin_disable_list_rel, plugin_disable_list);
304 	}
305 #else
306 	const std::list<std::string>& plugin_order_list
307 		= conf->get_strlist("/apps/stardict/manage_plugins/plugin_order_list");
308 	const std::list<std::string>& plugin_disable_list
309 		= conf->get_strlist("/apps/stardict/manage_plugins/plugin_disable_list");
310 #endif
311 	oStarDictPlugins = new StarDictPlugins(conf_dirs->get_plugin_dir(),
312 		plugin_order_list,
313 		plugin_disable_list);
314 
315 	oLibs.set_show_progress(&load_show_progress);
316 	std::list<DictItemId> dict_new_install_list;
317 	bool verify_dict = conf->get_bool_at("dictionary/do_not_load_bad_dict");
318 	UpdateDictList(dict_new_install_list, &load_show_progress, verify_dict);
319 	UpdateConfigXML(dict_new_install_list, plugin_new_install_list, oStarDictPlugins);
320 	LoadDictInfo();
321 	{
322 		std::list<DictItemId> load_list;
323 		GetUsedDictList(load_list);
324 		std::list<std::string> s_load_list;
325 		DictItemId::convert(s_load_list, load_list);
326 		oLibs.load(s_load_list);
327 	}
328 	oLibs.set_show_progress(&gtk_show_progress);
329 
330 	oStarDictClient.set_server(conf->get_string_at("network/server").c_str(), conf->get_int_at("network/port"));
331 	const std::string &user = conf->get_string_at("network/user");
332 	const std::string &md5passwd = conf->get_string_at("network/md5passwd");
333 	if (!user.empty() && !md5passwd.empty()) {
334 		oStarDictClient.set_auth(user.c_str(), md5passwd.c_str());
335 	}
336 	oStarDictClient.on_error_.connect(sigc::mem_fun(this, &AppCore::on_stardict_client_error));
337 	oStarDictClient.on_lookup_end_.connect(sigc::mem_fun(this, &AppCore::on_stardict_client_lookup_end));
338 	oStarDictClient.on_floatwin_lookup_end_.connect(sigc::mem_fun(this, &AppCore::on_stardict_client_floatwin_lookup_end));
339 	oStarDictClient.on_register_end_.connect(sigc::mem_fun(this, &AppCore::on_stardict_client_register_end));
340 	oStarDictClient.on_getdictmask_end_.connect(sigc::mem_fun(this, &AppCore::on_stardict_client_getdictmask_end));
341 	oStarDictClient.on_getadinfo_end_.connect(sigc::mem_fun(this, &AppCore::on_stardict_client_getadinfo_end));
342 	oStarDictClient.on_dirinfo_end_.connect(sigc::mem_fun(this, &AppCore::on_stardict_client_dirinfo_end));
343 	oStarDictClient.on_dictinfo_end_.connect(sigc::mem_fun(this, &AppCore::on_stardict_client_dictinfo_end));
344 	oStarDictClient.on_maxdictcount_end_.connect(sigc::mem_fun(this, &AppCore::on_stardict_client_maxdictcount_end));
345 	oStarDictClient.on_previous_end_.connect(sigc::mem_fun(this, &AppCore::on_stardict_client_previous_end));
346 	oStarDictClient.on_next_end_.connect(sigc::mem_fun(this, &AppCore::on_stardict_client_next_end));
347 
348 	UpdateDictMask();
349 
350 	gtk_container_set_border_width(GTK_CONTAINER(window),2);
351 	bool maximized=conf->get_bool_at("main_window/maximized");
352 
353 	int width=conf->get_int_at("main_window/window_width");
354 	int height=conf->get_int_at("main_window/window_height");
355 
356 	if (width < MIN_WINDOW_WIDTH)
357 		width = MIN_WINDOW_WIDTH;
358 	if (height < MIN_WINDOW_HEIGHT)
359 		height = MIN_WINDOW_HEIGHT;
360 	gtk_window_set_default_size (GTK_WINDOW(window), width, height);
361 	if (maximized)
362 		gtk_window_maximize(GTK_WINDOW(window));
363 	int transparent=conf->get_int_at("main_window/transparent");
364 	if (transparent != 0)
365 		gtk_window_set_opacity(GTK_WINDOW(window), (100-transparent)/100.0);
366 	gtk_window_set_title (GTK_WINDOW (window), _("StarDict"));
367 	gtk_window_set_icon(GTK_WINDOW(window),
368 			    get_impl(oAppSkin.icon));
369 	gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
370 	g_signal_connect (G_OBJECT (window), "show", G_CALLBACK (on_mainwin_show_event), this);
371 	g_signal_connect (G_OBJECT (window), "delete_event", G_CALLBACK (on_delete_event), this);
372 	g_signal_connect (G_OBJECT (window), "window_state_event", G_CALLBACK (on_window_state_event), this);
373 	g_signal_connect (G_OBJECT (window), "key_press_event", G_CALLBACK (vKeyPressReleaseCallback), this);
374 	g_signal_connect (G_OBJECT (window), "key_release_event", G_CALLBACK (vKeyPressReleaseCallback), this);
375 
376 #if GTK_MAJOR_VERSION >= 3
377 	GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
378 #else
379 	GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
380 #endif
381 	gtk_widget_show(vbox);
382 	gtk_container_add(GTK_CONTAINER(window),vbox);
383 	oTopWin.Create(vbox);
384 	oMidWin.Create(vbox);
385 	oBottomWin.Create(vbox);
386 	unlock_keys.reset(static_cast<hotkeys *>(PlatformFactory::create_class_by_name("hotkeys",
387 										       GTK_WINDOW(window))));
388 	unlock_keys->set_comb(combnum2str(conf->get_int_at("dictionary/scan_modifier_key")));
389 	oFloatWin.Create();
390 	bool scan=conf->get_bool_at("dictionary/scan_selection");
391 	oDockLet.reset(PlatformFactory::create_tray_icon(window, scan,
392 							 oAppSkin));
393 	oDockLet->on_quit_.connect(sigc::mem_fun(this, &AppCore::Quit));
394 	oDockLet->on_change_scan_.connect(
395 		sigc::mem_fun(this, &AppCore::on_change_scan));
396 	oDockLet->on_maximize_.connect(
397 		sigc::mem_fun(this, &AppCore::on_maximize));
398 	oDockLet->on_middle_btn_click_.connect(
399 		sigc::mem_fun(this, &AppCore::on_docklet_middle_button_click));
400 	oSelection.Init();
401 #ifdef _WIN32
402 	oClipboard.Init();
403 	oMouseover.Init();
404 #endif
405 	oHotkey.Init();
406 #ifdef ENABLE_LOG_WINDOW
407 	gLogWindow.Init();
408 #endif
409 
410 	if (scan) {
411 		oSelection.start();
412 #ifdef _WIN32
413 		if (conf->get_bool_at("dictionary/scan_clipboard")) {
414 			oClipboard.start();
415 		}
416 		oMouseover.start();
417 #endif
418 	}
419 	if (conf->get_bool_at("dictionary/use_scan_hotkey")) {
420 		const std::string &hotkey = conf->get_string_at(
421 		  "dictionary/scan_hotkey");
422 		oHotkey.start_scan(hotkey.c_str());
423 	}
424 	if (conf->get_bool_at("dictionary/use_mainwindow_hotkey")) {
425 		const std::string &hotkey = conf->get_string_at(
426 		  "dictionary/mainwindow_hotkey");
427 		oHotkey.start_mainwindow(hotkey.c_str());
428 	}
429 
430 	bool hide=conf->get_bool_at("main_window/hide_on_startup");
431 
432 	//NOTICE: when docklet embedded failed,it should always show the window,but,how to detect the failure?
433 	// As stardict is FOR GNOME,so i don't want to consider the case that haven't the Notification area applet.
434 	if (!CmdLineOptions::get_hide() && (queryword || !hide)) {
435 		oDockLet->hide_state();
436 		gtk_widget_show(window);
437 	} else {
438 // This may be needed, so gtk_window_get_screen() in gtk_iskeyspressed.cpp can always work.
439 		gtk_widget_realize(window);
440 		gdk_notify_startup_complete();
441 	}
442 
443 	bool have_netdict = false;
444 	for (size_t iLib=0; iLib<query_dictmask.size(); iLib++) {
445 		if (query_dictmask[iLib].type == InstantDictType_NET) {
446 			have_netdict = true;
447 			break;
448 		}
449 	}
450 	if (oLibs.has_dict() || conf->get_bool_at("network/enable_netdict") || have_netdict) {
451 		if (queryword) {
452 			Query(queryword);
453 		} else {
454 			oMidWin.oTextWin.ShowTips();
455 		}
456 	} else {
457 		oMidWin.oTextWin.ShowInitFailed();
458 	}
459 }
460 
on_mainwin_show_event(GtkWidget * window,AppCore * app)461 void AppCore::on_mainwin_show_event(GtkWidget * window, AppCore *app)
462 {
463 	static bool loaded = false;
464 	if (!loaded) {
465 		loaded = true;
466 		// We need to set the hpaned position after the window showed, or it will become incorrect.
467 		int pos=conf->get_int_at("main_window/hpaned_pos");
468 		gtk_paned_set_position(GTK_PANED(app->oMidWin.hpaned), pos);
469 	}
470 }
471 
on_delete_event(GtkWidget * window,GdkEvent * event,AppCore * app)472 gboolean AppCore::on_delete_event(GtkWidget * window, GdkEvent *event , AppCore *app)
473 {
474 #ifdef CONFIG_DARWIN
475 	gtk_window_iconify(GTK_WINDOW(window));
476 #else
477 	app->oDockLet->minimize_to_tray();
478 #endif
479 	return TRUE;
480 }
481 
on_window_state_event(GtkWidget * window,GdkEventWindowState * event,AppCore * app)482 gboolean AppCore::on_window_state_event(GtkWidget *window,
483 					GdkEventWindowState *event, AppCore *app)
484 {
485 	switch (event->changed_mask) {
486 	case GDK_WINDOW_STATE_WITHDRAWN:
487 		if (conf->get_bool_at("dictionary/scan_selection"))
488 			app->oDockLet->set_scan_mode(true);
489 		else
490 			app->oDockLet->set_scan_mode(false);
491 		if (!(event->new_window_state & GDK_WINDOW_STATE_WITHDRAWN)) {
492 			app->oDockLet->hide_state();
493 			if (app->oTopWin.get_text()[0])
494 				gtk_widget_grab_focus(app->oMidWin.oTextWin.view->widget());
495 		}
496 		break;
497 	case GDK_WINDOW_STATE_ICONIFIED:
498 		if (!(event->new_window_state & GDK_WINDOW_STATE_ICONIFIED)) {
499 			if (app->oTopWin.get_text()[0]) {
500 				//this is better than the next two line because it don't change selection.
501 				gtk_widget_grab_focus(app->oMidWin.oTextWin.view->widget());
502 			} else {
503 				app->oTopWin.grab_focus();
504 			}
505 		}
506 		break;
507 	case GDK_WINDOW_STATE_MAXIMIZED:
508 		conf->set_bool_at("main_window/maximized",
509 				  (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED));
510 		break;
511 	default:
512 		/* nothing */break;
513 	}
514 
515 	return FALSE;
516 }
517 
vKeyPressReleaseCallback(GtkWidget * window,GdkEventKey * event,AppCore * oAppCore)518 gboolean AppCore::vKeyPressReleaseCallback(GtkWidget * window, GdkEventKey *event , AppCore *oAppCore)
519 {
520 	gboolean return_val=true;  //if return TRUE,the widget which in the main window will not receive any keyboard event.
521 
522 	gboolean only_ctrl_pressed = ((event->state & GDK_CONTROL_MASK)&&(!(event->state & GDK_MOD1_MASK))&&(!(event->state & GDK_SHIFT_MASK)));
523 	gboolean only_mod1_pressed = ((event->state & GDK_MOD1_MASK)&&(!(event->state & GDK_CONTROL_MASK))&&(!(event->state & GDK_SHIFT_MASK)));
524 	if ((event->keyval==GDK_KEY_q || event->keyval==GDK_KEY_Q) && only_ctrl_pressed) {
525 		if (event->type==GDK_KEY_PRESS)
526 			oAppCore->Quit();
527 	}
528 	else if ((event->keyval==GDK_KEY_x || event->keyval==GDK_KEY_X) && only_mod1_pressed) {
529 		if (event->type==GDK_KEY_PRESS) {
530 			oAppCore->oDockLet->minimize_to_tray();
531 		}
532 	}
533 	else if ((event->keyval==GDK_KEY_z || event->keyval==GDK_KEY_Z) && only_mod1_pressed) {
534 		if (event->type==GDK_KEY_PRESS) {
535 			gtk_window_iconify(GTK_WINDOW(window));
536 		}
537 	}
538 	else if ((event->keyval==GDK_KEY_e || event->keyval==GDK_KEY_E) && only_mod1_pressed) {
539 		if (event->type==GDK_KEY_PRESS) {
540 			oAppCore->oMidWin.oToolWin.do_save();
541 		}
542 	}
543 	else if (event->keyval==GDK_KEY_F1 && (!(event->state & GDK_CONTROL_MASK)) && (!(event->state & GDK_MOD1_MASK)) && (!(event->state & GDK_SHIFT_MASK))) {
544 		if (event->type==GDK_KEY_PRESS)
545 		  show_help(NULL);
546 	}
547 	else if ((event->keyval==GDK_KEY_f || event->keyval==GDK_KEY_F) && only_ctrl_pressed) {
548 		if (event->type==GDK_KEY_PRESS)
549 			oAppCore->oMidWin.oToolWin.do_search();
550 	}
551 	else if ((event->keyval==GDK_KEY_Left) && only_mod1_pressed) {
552 		if (event->type==GDK_KEY_PRESS)
553 			oAppCore->oTopWin.do_back();
554 	}
555 	else if ((event->keyval==GDK_KEY_Right) && only_mod1_pressed) {
556 		if (event->type==GDK_KEY_PRESS)
557 			oAppCore->oTopWin.do_forward();
558 	}
559 	else if ((event->keyval==GDK_KEY_Up) && only_mod1_pressed) {
560 		if (event->type==GDK_KEY_PRESS)
561 			oAppCore->oTopWin.do_prev();
562 	}
563 	else if ((event->keyval==GDK_KEY_Down) && only_mod1_pressed) {
564 		if (event->type==GDK_KEY_PRESS)
565 			oAppCore->oTopWin.do_next();
566 	}
567 	else if ((event->keyval==GDK_KEY_c || event->keyval==GDK_KEY_C) && only_mod1_pressed) {
568 		if (event->type==GDK_KEY_PRESS)
569 			oAppCore->oTopWin.clear_entry();
570 	}
571 	else if ((event->keyval==GDK_KEY_m || event->keyval==GDK_KEY_M) && only_mod1_pressed) {
572 		if (event->type==GDK_KEY_PRESS)
573 			oAppCore->oTopWin.do_menu();
574 	}
575 	else if ((event->keyval==GDK_KEY_u || event->keyval==GDK_KEY_U) && only_ctrl_pressed) {
576 		if (event->type==GDK_KEY_PRESS)
577 			oAppCore->oTopWin.clear_entry();
578 	}
579 	else if ((event->keyval==GDK_KEY_v || event->keyval==GDK_KEY_V) && only_ctrl_pressed &&
580 			!oAppCore->oTopWin.has_focus() &&
581 			!oAppCore->oMidWin.oTransWin.IsInputViewHasFocus() &&
582 			!oAppCore->oMidWin.oTextWin.IsSearchPanelHasFocus()) {
583 		if (event->type==GDK_KEY_PRESS) {
584 			gtk_clipboard_request_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), oAppCore->oTopWin.ClipboardReceivedCallback, &(oAppCore->oTopWin));
585 		}
586 	}
587 	else if (event->type==GDK_KEY_PRESS &&
588 						 event->keyval >= 0x21 && event->keyval <= 0x7E &&
589 						 !(event->state & GDK_CONTROL_MASK) &&
590 						 !(event->state & GDK_MOD1_MASK) &&
591 						 !oAppCore->oTopWin.has_focus() &&
592 						 !oAppCore->oMidWin.oTransWin.IsInputViewHasFocus() &&
593 						 !oAppCore->oMidWin.oTextWin.IsSearchPanelHasFocus()) {
594 		oAppCore->oTopWin.InsertHisList(oAppCore->oTopWin.get_text());
595 		oAppCore->oTopWin.InsertBackList();
596 		gchar str[2] = { (gchar)(event->keyval), '\0' };
597 		oAppCore->oTopWin.grab_focus();
598 		oAppCore->oTopWin.SetText(str, conf->get_bool_at("main_window/search_while_typing"));
599 		oAppCore->oTopWin.set_position_in_text(1);
600 	} else if (event->type==GDK_KEY_PRESS && event->keyval == GDK_KEY_BackSpace &&
601 		!oAppCore->oTopWin.has_focus() &&
602 		!oAppCore->oMidWin.oTransWin.IsInputViewHasFocus() &&
603 		!oAppCore->oMidWin.oTextWin.IsSearchPanelHasFocus()) {
604 		oAppCore->oTopWin.clear_entry();
605 	} else if (event->type == GDK_KEY_PRESS &&
606 		   event->keyval == GDK_KEY_Return &&
607 		   !oAppCore->oTopWin.has_focus() &&
608 		   !oAppCore->oMidWin.oTransWin.IsInputViewHasFocus() &&
609 		   !oAppCore->oMidWin.oTextWin.IsSearchPanelHasFocus()) {
610 		if (oAppCore->oMidWin.oIndexWin.oListWin.treeview_has_focus()) {
611 			GtkTreeModel *model;
612 			GtkTreeIter iter;
613 
614 			GtkTreeSelection *selection =
615 				gtk_tree_view_get_selection(oAppCore->oMidWin.oIndexWin.oListWin.treeview_);
616 			if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
617 				if (gtk_tree_model_iter_has_child(model, &iter)) {
618 					GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
619 					if (gtk_tree_view_row_expanded(
620 						    oAppCore->oMidWin.oIndexWin.oListWin.treeview_,
621 						    path))
622 						gtk_tree_view_collapse_row(
623 							oAppCore->oMidWin.oIndexWin.oListWin.treeview_, path);
624 					else
625 						gtk_tree_view_expand_row(
626 							oAppCore->oMidWin.oIndexWin.oListWin.treeview_,
627 							path, FALSE);
628 					gtk_tree_path_free(path);
629 				} else {
630 					gchar *word;
631 					gtk_tree_model_get(model, &iter, 0, &word, -1);
632 					oAppCore->ListClick(word);
633 					g_free(word);
634 				}
635 			}
636 		}
637 		else {
638 			oAppCore->oTopWin.grab_focus();
639 			oAppCore->TopWinEnterWord();
640 		}
641 	} else if (event->type==GDK_KEY_PRESS &&
642 						 event->keyval == 0x20 &&
643 						 !oAppCore->oTopWin.has_focus() &&
644 						 !oAppCore->oMidWin.oTransWin.IsInputViewHasFocus() &&
645 						 !oAppCore->oMidWin.oTextWin.IsSearchPanelHasFocus()) {
646 		oAppCore->oTopWin.InsertHisList(oAppCore->oTopWin.get_text());
647 		oAppCore->oTopWin.InsertBackList();
648 		oAppCore->oTopWin.grab_focus();
649 	} else if(event->type==GDK_KEY_PRESS && event->keyval == GDK_KEY_Escape) {
650 		if(oAppCore->oMidWin.oTextWin.IsSearchPanelHasFocus())
651 			oAppCore->oMidWin.oTextWin.HideSearchPanel();
652 		else
653 			oAppCore->oTopWin.clear_entry();
654 	} else {
655 		return_val=false;
656 	}
657 	return return_val;
658 }
659 
SimpleLookupToFloat(const char * sWord,bool IgnoreScanModifierKey)660 void AppCore::SimpleLookupToFloat(const char* sWord, bool IgnoreScanModifierKey)
661 {
662 	oFloatWin.StartLookup(sWord, IgnoreScanModifierKey);
663 	composite_lookup_float_win.new_lookup();
664 	if (IsASCII(sWord)) {
665 		if (SimpleLookupToFloatLocal(sWord)) {
666 			//found
667 		} else {
668 			gchar *sWord2 = g_strdup(sWord);
669 			gchar *a = GetPureEnglishAlpha(sWord2);
670 			if (*a) {
671 				if (strcmp(sWord, a) == 0) {
672 					// Not found.
673 					oTopWin.InsertHisList(a); //really need?
674 				} else {
675 					SimpleLookupToFloatLocal(a);
676 				}
677 			} else {
678 				// The string is too strange, don't show any thing.
679 			}
680 			g_free(sWord2);
681 		}
682 	} else {
683 		SimpleLookupToFloatLocal(sWord);
684 	}
685 	bool enable_netdict = conf->get_bool_at("network/enable_netdict");
686 	if (enable_netdict) {
687 		STARDICT::Cmd *c = new STARDICT::Cmd(STARDICT::CMD_SELECT_QUERY, sWord);
688 		if (!oStarDictClient.try_cache(c)) {
689 			composite_lookup_float_win.send_StarDict_net_request(c->seq);
690 			oStarDictClient.send_commands(1, c);
691 		}
692 	}
693 	LookupNetDict(sWord, false);
694 	composite_lookup_float_win.done_lookup();
695 	if(composite_lookup_float_win.is_got_all_responses())
696 		oFloatWin.EndLookup();
697 }
698 
SimpleLookupToFloatLocal(const char * sWord)699 bool AppCore::SimpleLookupToFloatLocal(const char* sWord)
700 {
701 	if (sWord==NULL || sWord[0]=='\0')
702 		return true;
703 	char *SearchWord = (char *)g_malloc(strlen(sWord)+1);
704 	copy_normalize_trim_spaces(SearchWord, sWord);
705 	if (SearchWord[0]=='\0') {
706 		strcpy(SearchWord, sWord);
707 	}
708 	char *EndPointer = SearchWord+strlen(SearchWord);
709 
710 	gchar ***pppWord = (gchar ***)g_malloc(sizeof(gchar **) * scan_dictmask.size());
711 	gchar ****ppppWordData = (gchar ****)g_malloc(sizeof(gchar ***) * scan_dictmask.size());
712 	CurrentIndex *iIndex = (CurrentIndex *)g_malloc(sizeof(CurrentIndex) * scan_dictmask.size());
713 
714 	//find the word use most biggest length
715 	while (EndPointer>SearchWord) {
716 		EndPointer = delete_trailing_spaces_ASCII(SearchWord, EndPointer);
717 
718 		bool bFound = false;
719 		for (size_t iLib=0;iLib<scan_dictmask.size();iLib++)
720 			BuildResultData(scan_dictmask, SearchWord, iIndex, NULL, iLib, pppWord, ppppWordData, bFound, 2);
721 		for (size_t iLib=0; iLib<scan_dictmask.size(); iLib++)
722 			BuildVirtualDictData(scan_dictmask, SearchWord, iLib, pppWord, ppppWordData, bFound);
723 		if (bFound) {
724 			oFloatWin.AppendTextLocalDict(pppWord, ppppWordData, SearchWord);
725 			oTopWin.InsertHisList(SearchWord);
726 			FreeResultData(scan_dictmask.size(), pppWord, ppppWordData);
727 			g_free(iIndex);
728 			g_free(SearchWord);
729 			return true;
730 		}
731 		if (IsASCII(SearchWord)) {
732 			EndPointer = delete_trailing_word_ASCII(SearchWord, EndPointer);
733 		} else {
734 			EndPointer = delete_trailing_char(SearchWord, EndPointer);
735 		}
736 	}
737 	FreeResultData(scan_dictmask.size(), pppWord, ppppWordData);
738 	g_free(iIndex);
739 	g_free(SearchWord);
740 	return false;
741 }
742 
743 #ifdef _WIN32
SmartLookupToFloat(const gchar * sWord,int BeginPos,bool IgnoreScanModifierKey)744 void AppCore::SmartLookupToFloat(const gchar* sWord, int BeginPos, bool IgnoreScanModifierKey)
745 {
746 	oFloatWin.StartLookup(sWord, IgnoreScanModifierKey);
747 	composite_lookup_float_win.new_lookup();
748 	LocalSmartLookupToFloat(sWord, BeginPos);
749 	/* sWord is not a candidate to search in net dictionaries */
750 	composite_lookup_float_win.done_lookup();
751 	if(composite_lookup_float_win.is_got_all_responses())
752 		oFloatWin.EndLookup();
753 }
754 
LocalSmartLookupToFloat(const gchar * sWord,int BeginPos)755 bool AppCore::LocalSmartLookupToFloat(const gchar* sWord, int BeginPos)
756 {
757 	if (sWord==NULL || sWord[0]=='\0')
758 		return false;
759 	char *SearchWord = (char *)g_malloc(strlen(sWord)+1);
760 	std::string TriedSearchWord;
761 
762 	gchar ***pppWord = (gchar ***)g_malloc(sizeof(gchar **) * scan_dictmask.size());
763 	gchar ****ppppWordData = (gchar ****)g_malloc(sizeof(gchar ***) * scan_dictmask.size());
764 	CurrentIndex *iIndex = (CurrentIndex *)g_malloc(sizeof(CurrentIndex) * scan_dictmask.size());
765 
766 	int try_cnt = 0;
767 	while(true) {
768 		bool skip_try = false;
769 		switch(try_cnt)
770 		{
771 			case 0:
772 				extract_word(SearchWord, sWord, BeginPos, is_space_or_punct);
773 				TriedSearchWord = SearchWord;
774 				++try_cnt;
775 				break;
776 			case 1:
777 				extract_word(SearchWord, sWord, BeginPos, is_not_alpha);
778 				if(SearchWord[0])
779 					TriedSearchWord = SearchWord;
780 				++try_cnt;
781 				break;
782 			case 2:
783 				{
784 					gunichar c = g_utf8_get_char(sWord + BeginPos);
785 					if(g_unichar_islower(c))
786 						extract_word(SearchWord, sWord, BeginPos, is_not_lower);
787 					else if(g_unichar_isupper(c))
788 						extract_word(SearchWord, sWord, BeginPos, is_not_upper);
789 					else
790 						skip_try = true;
791 					if(SearchWord[0])
792 						TriedSearchWord = SearchWord;
793 					++try_cnt;
794 					break;
795 				}
796 			case 3:
797 				extract_capitalized_word(SearchWord, sWord, BeginPos,
798 					g_unichar_isupper, g_unichar_islower);
799 				if(SearchWord[0])
800 					TriedSearchWord = SearchWord;
801 				++try_cnt;
802 				break;
803 			case 4:
804 				strcpy(SearchWord, TriedSearchWord.c_str());
805 				++try_cnt;
806 				skip_try = true;
807 			case 5:
808 				{ // cut last char
809 					char *end = SearchWord + strlen(SearchWord);
810 					end = g_utf8_prev_char(end);
811 					*end = '\0';
812 					if(!SearchWord[0]) {
813 						++try_cnt;
814 						skip_try = true;
815 					}
816 					break;
817 				}
818 			default:
819 				goto loop_end;
820 		}
821 		if(!SearchWord[0] || skip_try)
822 			continue;
823 
824 		bool bFound = false;
825 		for (size_t iLib=0;iLib<scan_dictmask.size();iLib++)
826 			BuildResultData(scan_dictmask, SearchWord, iIndex, false, iLib, pppWord, ppppWordData, bFound, 2);
827 		for (size_t iLib=0; iLib<scan_dictmask.size(); iLib++)
828 			BuildVirtualDictData(scan_dictmask, SearchWord, iLib, pppWord, ppppWordData, bFound);
829 
830 		if (bFound) {
831 			oFloatWin.AppendTextLocalDict(pppWord, ppppWordData, SearchWord);
832 			oTopWin.InsertHisList(SearchWord);
833 			FreeResultData(scan_dictmask.size(), pppWord, ppppWordData);
834 			g_free(iIndex);
835 			g_free(SearchWord);
836 			return true;
837 		}
838 	}
839 loop_end:
840 	FreeResultData(scan_dictmask.size(), pppWord, ppppWordData);
841 	g_free(iIndex);
842 	g_free(SearchWord);
843 	return false;
844 }
845 #endif
846 
BuildVirtualDictData(std::vector<InstantDictIndex> & dictmask,const char * sWord,int iLib,gchar *** pppWord,gchar **** ppppWordData,bool & bFound)847 void AppCore::BuildVirtualDictData(std::vector<InstantDictIndex> &dictmask, const char* sWord, int iLib, gchar ***pppWord, gchar ****ppppWordData, bool &bFound)
848 {
849 	if (dictmask[iLib].type == InstantDictType_NET) {
850 		const char *dict_cacheid = oStarDictPlugins->NetDictPlugins.dict_cacheid(dictmask[iLib].index);
851 		NetDictResponse *resp = netdict_get_cache_resp(dict_cacheid, sWord);
852 		if (resp && resp->data) {
853 			pppWord[iLib] = (gchar **)g_malloc(sizeof(gchar *)*2);
854 			pppWord[iLib][0] = g_strdup(resp->word);
855 			pppWord[iLib][1] = NULL;
856 			ppppWordData[iLib] = (gchar ***)g_malloc(sizeof(gchar **)*(1));
857 			ppppWordData[iLib][0] = (gchar **)g_malloc(sizeof(gchar *)*2);
858 			ppppWordData[iLib][0][0] =  stardict_datadup(resp->data);
859 			ppppWordData[iLib][0][1] = NULL;
860 			bFound = true;
861 		} else {
862 			pppWord[iLib] = NULL;
863 		}
864 	} else if (dictmask[iLib].type == InstantDictType_VIRTUAL) {
865 		oStarDictPlugins->VirtualDictPlugins.lookup(dictmask[iLib].index, sWord, &(pppWord[iLib]), &(ppppWordData[iLib]));
866 		if (pppWord[iLib])
867 			bFound = true;
868 	}
869 }
870 
BuildResultData(std::vector<InstantDictIndex> & dictmask,const char * sWord,CurrentIndex * iIndex,const gchar * piIndexValidStr,int iLib,gchar *** pppWord,gchar **** ppppWordData,bool & bFound,gint Method)871 void AppCore::BuildResultData(std::vector<InstantDictIndex> &dictmask, const char* sWord, CurrentIndex *iIndex, const gchar *piIndexValidStr, int iLib, gchar ***pppWord, gchar ****ppppWordData, bool &bFound, gint Method)
872 {
873 	if (dictmask[iLib].type != InstantDictType_LOCAL)
874 		return;
875 
876 	int iRealLib = dictmask[iLib].index;
877 	gint i, j;
878 	gint count=0, syncount;
879 	bool bLookupWord, bLookupSynonymWord;
880 	gint nWord;
881 	glong iWordIdx;
882 	if (piIndexValidStr) {
883 		if (iIndex[iLib].idx != INVALID_INDEX) {
884 			bLookupWord = !strcmp(oLibs.poGetWord(iIndex[iLib].idx, iRealLib, 0), piIndexValidStr);
885 		} else {
886 			bLookupWord = false;
887 		}
888 		if (iIndex[iLib].synidx != UNSET_INDEX && iIndex[iLib].synidx != INVALID_INDEX) {
889 			bLookupSynonymWord = !strcmp(oLibs.poGetSynonymWord(iIndex[iLib].synidx, iRealLib, 0), piIndexValidStr);
890 		} else {
891 			bLookupSynonymWord = false;
892 		}
893 	} else {
894 		if (Method==0) {
895 			bLookupWord = oLibs.LookupWord(sWord, iIndex[iLib].idx, iIndex[iLib].idx_suggest, iRealLib, 0);
896 			bLookupSynonymWord = oLibs.LookupSynonymWord(sWord, iIndex[iLib].synidx, iIndex[iLib].synidx_suggest, iRealLib, 0);
897 		} else if (Method==1) {
898 			bLookupWord = oLibs.LookupSimilarWord(sWord, iIndex[iLib].idx, iIndex[iLib].idx_suggest, iRealLib, 0);
899 			bLookupSynonymWord = oLibs.LookupSynonymSimilarWord(sWord, iIndex[iLib].synidx, iIndex[iLib].synidx_suggest, iRealLib, 0);
900 		} else {
901 			bLookupWord = oLibs.SimpleLookupWord(sWord, iIndex[iLib].idx, iIndex[iLib].idx_suggest, iRealLib, 0);
902 			bLookupSynonymWord = oLibs.SimpleLookupSynonymWord(sWord, iIndex[iLib].synidx, iIndex[iLib].synidx_suggest, iRealLib, 0);
903 		}
904 	}
905 	if (bLookupWord || bLookupSynonymWord) {
906 		glong orig_idx, orig_synidx;
907 		orig_idx = oLibs.CltIndexToOrig(iIndex[iLib].idx, iRealLib, 0);
908 		orig_synidx = oLibs.CltSynIndexToOrig(iIndex[iLib].synidx, iRealLib, 0);
909 		nWord=0;
910 		if (bLookupWord)
911 			nWord++;
912 		if (bLookupSynonymWord) {
913 			syncount = oLibs.GetOrigWordCount(orig_synidx, iRealLib, false);
914 			nWord+=syncount;
915 		}
916 		pppWord[iLib] = (gchar **)g_malloc(sizeof(gchar *)*(nWord+1));
917 		ppppWordData[iLib] = (gchar ***)g_malloc(sizeof(gchar **)*(nWord));
918 		if (bLookupWord) {
919 			pppWord[iLib][0] = g_strdup(oLibs.poGetOrigWord(orig_idx, iRealLib));
920 			count = oLibs.GetOrigWordCount(orig_idx, iRealLib, true);
921 			ppppWordData[iLib][0] = (gchar **)g_malloc(sizeof(gchar *)*(count+1));
922 			for (i=0;i<count;i++) {
923 				ppppWordData[iLib][0][i] = stardict_datadup(oLibs.poGetOrigWordData(orig_idx+i, iRealLib));
924 			}
925 			ppppWordData[iLib][0][count] = NULL;
926 			i=1;
927 		} else {
928 			i=0;
929 		}
930 		for (j=0;i<nWord;i++,j++) {
931 			iWordIdx = oLibs.poGetOrigSynonymWordIdx(orig_synidx+j, iRealLib);
932 			if (bLookupWord) {
933 				if (iWordIdx>=orig_idx && (iWordIdx<orig_idx+count)) {
934 					nWord--;
935 					i--;
936 					continue;
937 				}
938 			}
939 			pppWord[iLib][i] = g_strdup(oLibs.poGetOrigWord(iWordIdx, iRealLib));
940 			ppppWordData[iLib][i] = (gchar **)g_malloc(sizeof(gchar *)*2);
941 			ppppWordData[iLib][i][0] = stardict_datadup(oLibs.poGetOrigWordData(iWordIdx, iRealLib));
942 			ppppWordData[iLib][i][1] = NULL;
943 		}
944 		pppWord[iLib][nWord] = NULL;
945 		bFound = true;
946 	} else {
947 		pppWord[iLib] = NULL;
948 	}
949 }
950 
FreeResultData(size_t dictmask_size,gchar *** pppWord,gchar **** ppppWordData)951 void AppCore::FreeResultData(size_t dictmask_size, gchar ***pppWord, gchar ****ppppWordData)
952 {
953 	if (!pppWord)
954 		return;
955 	int j, k;
956 	size_t i;
957 	for (i=0; i<dictmask_size; i++) {
958 		if (pppWord[i]) {
959 			j=0;
960 			while (pppWord[i][j]) {
961 				k=0;
962 				while (ppppWordData[i][j][k]) {
963 					g_free(ppppWordData[i][j][k]);
964 					k++;
965 				}
966 				g_free(pppWord[i][j]);
967 				g_free(ppppWordData[i][j]);
968 				j++;
969 			}
970 			g_free(pppWord[i]);
971 			g_free(ppppWordData[i]);
972 		}
973 	}
974 	g_free(pppWord);
975 	g_free(ppppWordData);
976 }
977 
978 /* The input can be:
979  * (sWord, NULL, NULL). Look up the sWord.
980  * (sWord, piIndex, NULL). Look up the sWord, and set piIndex to the new indexes that found.
981  * (sWord, piIndex, "word"), show sWord by piIndex's information, while the index point to "word".
982  */
SimpleLookupToTextWin(const char * sWord,CurrentIndex * piIndex,const gchar * piIndexValidStr,bool bTryMoreIfNotFound,bool bShowNotfound,bool isShowFirst)983 bool AppCore::SimpleLookupToTextWin(const char* sWord, CurrentIndex *piIndex, const gchar *piIndexValidStr, bool bTryMoreIfNotFound, bool bShowNotfound, bool isShowFirst)
984 {
985 	bool bFound = false;
986 	gchar ***pppWord = (gchar ***)g_malloc(sizeof(gchar **) * query_dictmask.size());
987 	gchar ****ppppWordData = (gchar ****)g_malloc(sizeof(gchar ***) * query_dictmask.size());
988 	CurrentIndex *iIndex;
989 	if (!piIndex)
990 		iIndex = (CurrentIndex *)g_malloc(sizeof(CurrentIndex) * query_dictmask.size());
991 	else
992 		iIndex = piIndex;
993 
994 	for (size_t iLib=0; iLib<query_dictmask.size(); iLib++)
995 		BuildResultData(query_dictmask, sWord, iIndex, piIndexValidStr, iLib, pppWord, ppppWordData, bFound, 0);
996 	if (!bFound && !piIndexValidStr) {
997 		for (size_t iLib=0; iLib<query_dictmask.size(); iLib++)
998 			BuildResultData(query_dictmask, sWord, iIndex, NULL, iLib, pppWord, ppppWordData, bFound, 1);
999 	}
1000 	for (size_t iLib=0; iLib<query_dictmask.size(); iLib++)
1001 		BuildVirtualDictData(query_dictmask, piIndexValidStr?piIndexValidStr:sWord, iLib, pppWord, ppppWordData, bFound);
1002 	if (bFound) {
1003 		ShowDataToTextWin(pppWord, ppppWordData, sWord, isShowFirst);
1004 	} else {
1005 		if (bTryMoreIfNotFound) {
1006 			gchar *word = g_strdup(sWord);
1007 			gchar *hword;
1008 			hword = GetHeadWord(word);
1009 			if (*hword) {
1010 				if (!strcmp(hword,sWord)) {
1011 					if (bShowNotfound)
1012 						ShowNotFoundToTextWin(sWord,_("<Not Found!>"), TEXT_WIN_NOT_FOUND);
1013 				} else {
1014 					for (size_t iLib=0;iLib<query_dictmask.size();iLib++)
1015 						BuildResultData(query_dictmask, hword, iIndex, NULL, iLib, pppWord, ppppWordData, bFound, 0);
1016 					if (!bFound) {
1017 						for (size_t iLib=0; iLib<query_dictmask.size(); iLib++)
1018 							BuildResultData(query_dictmask, hword, iIndex, NULL, iLib, pppWord, ppppWordData, bFound, 1);
1019 					}
1020 					for (size_t iLib=0; iLib<query_dictmask.size(); iLib++)
1021 						BuildVirtualDictData(query_dictmask, hword, iLib, pppWord, ppppWordData, bFound);
1022 					if (bFound) {
1023 						ShowDataToTextWin(pppWord, ppppWordData, sWord, isShowFirst);
1024 					} else {
1025 						if (bShowNotfound)
1026 							ShowNotFoundToTextWin(sWord,_("<Not Found!>"), TEXT_WIN_NOT_FOUND);
1027 					}
1028 				}
1029 			} else {
1030 				if (bShowNotfound)
1031 					ShowNotFoundToTextWin(sWord,_("<Not Found!>"), TEXT_WIN_NOT_FOUND);
1032 			}
1033 			g_free(word);
1034 		} else {
1035 			if (bShowNotfound)
1036 				ShowNotFoundToTextWin(sWord,_("<Not Found!>"), TEXT_WIN_NOT_FOUND);
1037 		}
1038 	}
1039 
1040 	if (!piIndex)
1041 		g_free(iIndex);
1042 
1043 	FreeResultData(query_dictmask.size(), pppWord, ppppWordData);
1044 
1045 	return bFound;
1046 }
1047 
1048 struct FullTextSearchDialog {
1049 	GtkWidget *progress_bar;
1050 };
1051 
updateSearchDialog(gpointer data,gdouble fraction)1052 static void updateSearchDialog(gpointer data, gdouble fraction)
1053 {
1054 	FullTextSearchDialog *Dialog = (FullTextSearchDialog *)data;
1055 	gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(Dialog->progress_bar), fraction);
1056 	while (gtk_events_pending())
1057 		gtk_main_iteration();
1058 }
1059 
on_fulltext_search_cancel_clicked(GtkButton * button,bool * cancel)1060 static void on_fulltext_search_cancel_clicked(GtkButton *button, bool *cancel)
1061 {
1062 	*cancel = true;
1063 }
1064 
on_fulltext_search_window_delete_event(GtkWidget * window,GdkEvent * event,bool * cancel)1065 static gboolean on_fulltext_search_window_delete_event(GtkWidget * window, GdkEvent *event , bool *cancel)
1066 {
1067 	*cancel = true;
1068 	return true;
1069 }
1070 
1071 class LookupDataDialog {
1072 public:
1073 	LookupDataDialog(const char *sWord);
1074 	void show();
1075 private:
1076 	std::string word;
1077 	GtkListStore *now_tree_model;
1078 	static void on_fulltext_search_dict_enable_toggled (GtkCellRendererToggle *cell, gchar *path_str, LookupDataDialog *oLookupDataDialog);
1079 };
1080 
LookupDataDialog(const char * sWord)1081 LookupDataDialog::LookupDataDialog(const char *sWord)
1082 {
1083 	word = sWord;
1084 }
1085 
on_fulltext_search_dict_enable_toggled(GtkCellRendererToggle * cell,gchar * path_str,LookupDataDialog * oLookupDataDialog)1086 void LookupDataDialog::on_fulltext_search_dict_enable_toggled (GtkCellRendererToggle *cell, gchar *path_str, LookupDataDialog *oLookupDataDialog)
1087 {
1088 	GtkTreeModel *model = GTK_TREE_MODEL(oLookupDataDialog->now_tree_model);
1089 	GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
1090 	GtkTreeIter iter;
1091 	gtk_tree_model_get_iter (model, &iter, path);
1092 	gboolean enable;
1093 	gtk_tree_model_get (model, &iter, 0, &enable, -1);
1094 	enable = !enable;
1095 	gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, enable, -1);
1096 	gtk_tree_path_free (path);
1097 }
1098 
show()1099 void LookupDataDialog::show()
1100 {
1101 	GtkWidget *dialog = gtk_dialog_new_with_buttons(_("Full-text Search"), GTK_WINDOW(gpAppFrame->window), GTK_DIALOG_MODAL, NULL, NULL, NULL);
1102 	GtkWidget *button = gtk_dialog_add_button(GTK_DIALOG (dialog), GTK_STOCK_OK, GTK_RESPONSE_ACCEPT);
1103 	gtk_dialog_add_button(GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
1104 	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
1105 	gtk_widget_grab_focus(button);
1106 #if GTK_MAJOR_VERSION >= 3
1107 	GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
1108 #else
1109 	GtkWidget *vbox = gtk_vbox_new(false, 5);
1110 #endif
1111 	gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),vbox,true,true,0);
1112 	GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
1113 	gtk_box_pack_start(GTK_BOX(vbox),sw,true,true,0);
1114 	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
1115 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1116 	gtk_widget_set_size_request (sw, 300, 200);
1117 	now_tree_model = gtk_list_store_new(3, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_LONG);
1118 	for (std::vector<InstantDictIndex>::iterator i = gpAppFrame->query_dictmask.begin(); i != gpAppFrame->query_dictmask.end(); ++i) {
1119 		if (i->type == InstantDictType_LOCAL) {
1120 			GtkTreeIter new_iter;
1121 			gtk_list_store_append(now_tree_model, &new_iter);
1122 			gtk_list_store_set(now_tree_model, &new_iter, 0, TRUE, 1, gpAppFrame->oLibs.dict_name(i->index).c_str(), 2, i->index, -1);
1123 		}
1124 	}
1125 	GtkWidget *now_treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL(now_tree_model));
1126 	g_object_unref (G_OBJECT (now_tree_model));
1127 	gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (now_treeview), TRUE);
1128 	GtkCellRenderer *renderer;
1129 	GtkTreeViewColumn *column;
1130 	renderer = gtk_cell_renderer_toggle_new ();
1131 	g_signal_connect (renderer, "toggled", G_CALLBACK (on_fulltext_search_dict_enable_toggled), this);
1132 	column = gtk_tree_view_column_new_with_attributes (_("Search"), renderer, "active", 0, NULL);
1133 	gtk_tree_view_append_column (GTK_TREE_VIEW(now_treeview), column);
1134 	gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), FALSE);
1135 	renderer = gtk_cell_renderer_text_new ();
1136 	g_object_set (G_OBJECT (renderer), "xalign", 0.0, NULL);
1137 	column = gtk_tree_view_column_new_with_attributes (_("Dictionary Name"), renderer, "text", 1, NULL);
1138 	gtk_tree_view_append_column (GTK_TREE_VIEW(now_treeview), column);
1139 	gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), FALSE);
1140 	gtk_container_add (GTK_CONTAINER (sw), now_treeview);
1141 	gtk_widget_show_all(vbox);
1142 	gint response = gtk_dialog_run(GTK_DIALOG(dialog));
1143 	if (response == GTK_RESPONSE_ACCEPT) {
1144 		std::vector<InstantDictIndex> dictmask;
1145 		GtkTreeIter iter;
1146 		GtkTreeModel *model = GTK_TREE_MODEL(now_tree_model);
1147 		gboolean have_next = gtk_tree_model_get_iter_first(model, &iter);
1148 		while (have_next) {
1149 			gboolean enable;
1150 			gtk_tree_model_get (model, &iter, 0, &enable, -1);
1151 			if (enable) {
1152 				glong index;
1153 				gtk_tree_model_get (model, &iter, 2, &index, -1);
1154 				InstantDictIndex dictindex;
1155 				dictindex.type = InstantDictType_LOCAL;
1156 				dictindex.index = index;
1157 				dictmask.push_back(dictindex);
1158 			}
1159 			have_next = gtk_tree_model_iter_next(model, &iter);
1160 		}
1161 		gtk_widget_destroy(dialog);
1162 		gpAppFrame->oMidWin.oIndexWin.oListWin.Clear();
1163 		gpAppFrame->oMidWin.oIndexWin.oListWin.SetModel(false);
1164 		gpAppFrame->oMidWin.oIndexWin.oListWin.list_word_type = LIST_WIN_DATA_LIST;
1165 		bool enable_netdict = conf->get_bool_at("network/enable_netdict");
1166 		if (enable_netdict) {
1167 			std::string lookupword = "|";
1168 			lookupword += word;
1169 			STARDICT::Cmd *c = new STARDICT::Cmd(STARDICT::CMD_LOOKUP, lookupword.c_str());
1170 			if (!gpAppFrame->oStarDictClient.try_cache(c)) {
1171 				gpAppFrame->waiting_mainwin_lookupcmd_seq = c->seq;
1172 				gpAppFrame->oStarDictClient.send_commands(1, c);
1173 			}
1174 		}
1175 		gpAppFrame->LookupDataWithDictMask(word.c_str(), dictmask);
1176 	} else {
1177 		gtk_widget_destroy(dialog);
1178 	}
1179 }
1180 
LookupDataToMainWin(const gchar * sWord)1181 void AppCore::LookupDataToMainWin(const gchar *sWord)
1182 {
1183 	if (query_dictmask.empty()) {
1184 		oMidWin.oIndexWin.oListWin.Clear();
1185 		oMidWin.oIndexWin.oListWin.SetModel(false);
1186 		oMidWin.oIndexWin.oListWin.list_word_type = LIST_WIN_DATA_LIST;
1187 		bool enable_netdict = conf->get_bool_at("network/enable_netdict");
1188 		if (enable_netdict) {
1189 			std::string lookupword = "|";
1190 			lookupword += sWord;
1191 			STARDICT::Cmd *c = new STARDICT::Cmd(STARDICT::CMD_LOOKUP, lookupword.c_str());
1192 			if (!oStarDictClient.try_cache(c)) {
1193 				waiting_mainwin_lookupcmd_seq = c->seq;
1194 				oStarDictClient.send_commands(1, c);
1195 			}
1196 		} else {
1197 			ShowNotFoundToTextWin(sWord, _("There are no dictionary articles containing this word. :-("), TEXT_WIN_FUZZY_NOT_FOUND);
1198 		}
1199 	} else {
1200 		LookupDataDialog *dialog = new LookupDataDialog(sWord);
1201 		dialog->show();
1202 		delete dialog;
1203 	}
1204 }
1205 
LookupDataWithDictMask(const gchar * sWord,std::vector<InstantDictIndex> & dictmask)1206 void AppCore::LookupDataWithDictMask(const gchar *sWord, std::vector<InstantDictIndex> &dictmask)
1207 {
1208 	if (!sWord || !*sWord)
1209 		return;
1210 	change_cursor busy(gtk_widget_get_window(window),
1211 			   get_impl(oAppSkin.watch_cursor),
1212 			   get_impl(oAppSkin.normal_cursor));
1213 
1214 	bool cancel = false;
1215 	FullTextSearchDialog Dialog;
1216 	GtkWidget *search_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1217 	gtk_window_set_title (GTK_WINDOW(search_window), _("Full-text search..."));
1218 	gtk_window_set_transient_for(GTK_WINDOW(search_window), GTK_WINDOW(window));
1219 	gtk_window_set_position(GTK_WINDOW(search_window), GTK_WIN_POS_CENTER_ON_PARENT);
1220 #if GTK_MAJOR_VERSION >= 3
1221 	GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
1222 #else
1223 	GtkWidget *vbox = gtk_vbox_new(false, 6);
1224 #endif
1225 	gtk_container_add(GTK_CONTAINER(search_window),vbox);
1226 	Dialog.progress_bar = gtk_progress_bar_new();
1227 	gtk_box_pack_start(GTK_BOX(vbox),Dialog.progress_bar,false,false,0);
1228 	GtkWidget *button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1229 	gtk_box_pack_start(GTK_BOX(vbox),button,false,false,0);
1230 	g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(on_fulltext_search_cancel_clicked), &cancel);
1231 	g_signal_connect (G_OBJECT (search_window), "delete_event", G_CALLBACK (on_fulltext_search_window_delete_event), &cancel);
1232 	gtk_widget_show_all(search_window);
1233 
1234 	//clock_t t=clock();
1235 	std::vector< std::vector<gchar *> > reslist(dictmask.size());
1236 	if (oLibs.LookupData(sWord, &reslist[0], updateSearchDialog, &Dialog, &cancel, dictmask)) {
1237 		for (size_t i=0; i<dictmask.size(); i++) {
1238 			if (!reslist[i].empty()) {
1239 				SimpleLookupToTextWin(reslist[i][0], iCurrentIndex, NULL); // so iCurrentIndex is refreshed.
1240 				break;
1241 			}
1242 		}
1243 		oMidWin.oIndexWin.oListWin.SetTreeModel(&reslist[0], dictmask);
1244 		oMidWin.oIndexWin.oListWin.ReScroll();
1245 	} else {
1246 		ShowNotFoundToTextWin(sWord, _("There are no dictionary articles containing this word. :-("), TEXT_WIN_FUZZY_NOT_FOUND);
1247 	}
1248 	//t=clock()-t;
1249 	//g_message("Time: %.3lf sec\n", double(t)/CLOCKS_PER_SEC);
1250 	gtk_widget_destroy(search_window);
1251 }
1252 
LookupWithFuzzyToMainWin(const gchar * sWord)1253 void AppCore::LookupWithFuzzyToMainWin(const gchar *sWord)
1254 {
1255 	if (sWord[0] == '\0')
1256 		return;
1257 	change_cursor busy(gtk_widget_get_window(window),
1258 			   get_impl(oAppSkin.watch_cursor),
1259 			   get_impl(oAppSkin.normal_cursor));
1260 
1261 	gchar *fuzzy_reslist[MAX_FUZZY_MATCH_ITEM];
1262 	bool Found=
1263 		oLibs.LookupWithFuzzy(sWord, fuzzy_reslist, MAX_FUZZY_MATCH_ITEM, query_dictmask);
1264 
1265 	// show
1266 	oMidWin.oIndexWin.oListWin.Clear();
1267 	oMidWin.oIndexWin.oListWin.SetModel(true);
1268 	oMidWin.oIndexWin.oListWin.fuzzyWord = sWord;
1269 	oMidWin.oIndexWin.oListWin.list_word_type = LIST_WIN_FUZZY_LIST;
1270 
1271 	if (Found) {
1272 		//SimpleLookupToTextWin(oFuzzystruct[0].pMatchWord,NULL);
1273 		SimpleLookupToTextWin(fuzzy_reslist[0], iCurrentIndex, NULL); // so iCurrentIndex is refreshed.
1274 
1275 		for (int i=0; i<MAX_FUZZY_MATCH_ITEM && fuzzy_reslist[i]; i++) {
1276 			oMidWin.oIndexWin.oListWin.InsertLast(fuzzy_reslist[i]);
1277 			g_free(fuzzy_reslist[i]);
1278 			//g_print("fuzzy %s,%d\n",oFuzzystruct[i].pMatchWord,oFuzzystruct[i].iMatchWordDistance);
1279 		}
1280 		oMidWin.oIndexWin.oListWin.ReScroll();
1281 	} else {
1282 		ShowNotFoundToTextWin(sWord,_("There are too many spelling errors :-("), TEXT_WIN_FUZZY_NOT_FOUND);
1283 	}
1284 }
1285 
LookupWithFuzzyToFloatWin(const gchar * sWord)1286 void AppCore::LookupWithFuzzyToFloatWin(const gchar *sWord)
1287 {
1288 	if (sWord[0] == '\0')
1289 		return;
1290 
1291 	oFloatWin.StartLookup(sWord);
1292 	composite_lookup_float_win.new_lookup();
1293 	gchar *fuzzy_reslist[MAX_FLOAT_WINDOW_FUZZY_MATCH_ITEM];
1294 	bool Found = oLibs.LookupWithFuzzy(sWord, fuzzy_reslist, MAX_FLOAT_WINDOW_FUZZY_MATCH_ITEM, scan_dictmask);
1295 	if (Found) {
1296 		int i, count=0;
1297 		for (i=0; i<MAX_FLOAT_WINDOW_FUZZY_MATCH_ITEM; i++) {
1298 			if (fuzzy_reslist[i])
1299 				count++;
1300 			else
1301 				break;
1302 		}
1303 		gchar ****ppppWord = (gchar ****)g_malloc(sizeof(gchar ***) * count);
1304 		gchar *****pppppWordData = (gchar *****)g_malloc(sizeof(gchar ****) * count);
1305 		const gchar **ppOriginWord = (const gchar **)g_malloc(sizeof(gchar *) * count);
1306 		CurrentIndex *iIndex = (CurrentIndex *)g_malloc(sizeof(CurrentIndex) * scan_dictmask.size());
1307 
1308 		gchar ***pppWord;
1309 		gchar ****ppppWordData;
1310 		for (i=0;i<count;i++) {
1311 			bool bFound = false;
1312 			pppWord = (gchar ***)g_malloc(sizeof(gchar **) * scan_dictmask.size());
1313 			ppppWordData = (gchar ****)g_malloc(sizeof(gchar ***) * scan_dictmask.size());
1314 
1315 			ppOriginWord[i] = fuzzy_reslist[i];
1316 			for (size_t iLib=0; iLib<scan_dictmask.size(); iLib++)
1317 				BuildResultData(scan_dictmask, fuzzy_reslist[i], iIndex, NULL, iLib, pppWord, ppppWordData, bFound, 2);
1318 			for (size_t iLib=0; iLib<scan_dictmask.size(); iLib++)
1319 				BuildVirtualDictData(scan_dictmask, fuzzy_reslist[i], iLib, pppWord, ppppWordData, bFound);
1320 			if (bFound) {// it is certainly be true.
1321 				ppppWord[i]=pppWord;
1322 				pppppWordData[i]=ppppWordData;
1323 			} else {
1324 				FreeResultData(scan_dictmask.size(), pppWord, ppppWordData);
1325 				ppppWord[i]=NULL;
1326 			}
1327 		}
1328 		oFloatWin.AppendTextFuzzy(ppppWord, pppppWordData, ppOriginWord, count, sWord);
1329 		for (i=0; i<count; i++) {
1330 			if (ppppWord[i])
1331 				FreeResultData(scan_dictmask.size(), ppppWord[i], pppppWordData[i]);
1332 		}
1333 		g_free(ppppWord);
1334 		g_free(pppppWordData);
1335 		g_free(ppOriginWord);
1336 		g_free(iIndex);
1337 
1338 		for (i=0;i<count;i++)
1339 			g_free(fuzzy_reslist[i]);
1340 	}
1341 	composite_lookup_float_win.done_lookup();
1342 	if(composite_lookup_float_win.is_got_all_responses())
1343 		oFloatWin.EndLookup();
1344 }
1345 
LookupWithRuleToMainWin(const gchar * word)1346 void AppCore::LookupWithRuleToMainWin(const gchar *word)
1347 {
1348 	change_cursor busy(gtk_widget_get_window(window),
1349 			   get_impl(oAppSkin.watch_cursor),
1350 			   get_impl(oAppSkin.normal_cursor));
1351 
1352 	gchar **ppMatchWord = (gchar **)g_malloc(sizeof(gchar *) * (MAX_MATCH_ITEM_PER_LIB*2) * query_dictmask.size()); //Need to be MAX_MATCH_ITEM_PER_LIB*2 as oLibs.LookupWithRule will call LookupWithRule() and LookupWithRuleSynonym().
1353 	gint iMatchCount=oLibs.LookupWithRule(word, ppMatchWord, query_dictmask);
1354 	oMidWin.oIndexWin.oListWin.Clear();
1355 	oMidWin.oIndexWin.oListWin.SetModel(true);
1356 	oMidWin.oIndexWin.oListWin.list_word_type = LIST_WIN_PATTERN_LIST;
1357 
1358 	if (iMatchCount) {
1359 		for (gint i=0; i<iMatchCount; i++)
1360 			oMidWin.oIndexWin.oListWin.InsertLast(ppMatchWord[i]);
1361 		//memset(iCurrentIndex,'\0',sizeof(iCurrentIndex));    // iCurrentIndex is ineffective now.
1362 
1363 		// show the first word.
1364 		//SimpleLookupToTextWin(ppMatchWord[0],NULL);
1365 		SimpleLookupToTextWin(ppMatchWord[0], iCurrentIndex, NULL); // so iCurrentIndex is refreshed.
1366 		oMidWin.oIndexWin.oListWin.ReScroll();
1367 		for(gint i=0; i<iMatchCount; i++)
1368 			g_free(ppMatchWord[i]);
1369 	} else {
1370 		ShowNotFoundToTextWin(word,_("Found no words matching this pattern!"), TEXT_WIN_PATTERN_NOT_FOUND);
1371 	}
1372 	g_free(ppMatchWord);
1373 }
1374 
LookupWithRegexToMainWin(const gchar * word)1375 void AppCore::LookupWithRegexToMainWin(const gchar *word)
1376 {
1377 	change_cursor busy(gtk_widget_get_window(window),
1378 			   get_impl(oAppSkin.watch_cursor),
1379 			   get_impl(oAppSkin.normal_cursor));
1380 
1381 	gchar **ppMatchWord = (gchar **)g_malloc(sizeof(gchar *) * (MAX_MATCH_ITEM_PER_LIB*2) * query_dictmask.size()); //Need to be MAX_MATCH_ITEM_PER_LIB*2 as oLibs.LookupWithRegex will call LookupWithRegex() and LookupWithRegexSynonym().
1382 	gint iMatchCount=oLibs.LookupWithRegex(word, ppMatchWord, query_dictmask);
1383 	oMidWin.oIndexWin.oListWin.Clear();
1384 	oMidWin.oIndexWin.oListWin.SetModel(true);
1385 	oMidWin.oIndexWin.oListWin.list_word_type = LIST_WIN_PATTERN_LIST;
1386 
1387 	if (iMatchCount) {
1388 		for (gint i=0; i<iMatchCount; i++)
1389 			oMidWin.oIndexWin.oListWin.InsertLast(ppMatchWord[i]);
1390 		SimpleLookupToTextWin(ppMatchWord[0], iCurrentIndex, NULL); // so iCurrentIndex is refreshed.
1391 		oMidWin.oIndexWin.oListWin.ReScroll();
1392 		for(gint i=0; i<iMatchCount; i++)
1393 			g_free(ppMatchWord[i]);
1394 	} else {
1395 		ShowNotFoundToTextWin(word,_("Found no words matching this regular expression!"), TEXT_WIN_PATTERN_NOT_FOUND);
1396 	}
1397 	g_free(ppMatchWord);
1398 }
1399 
LookupNetDict(const char * sWord,bool ismainwin)1400 void AppCore::LookupNetDict(const char *sWord, bool ismainwin)
1401 {
1402 	std::vector<InstantDictIndex> *dictmask;
1403 	if (ismainwin) {
1404 		dictmask = &query_dictmask;
1405 	} else {
1406 		dictmask = &scan_dictmask;
1407 	}
1408 	for (size_t iLib=0; iLib<dictmask->size(); iLib++) {
1409 		if ((*dictmask)[iLib].type == InstantDictType_NET) {
1410 			const char *dict_cacheid = oStarDictPlugins->NetDictPlugins.dict_cacheid((*dictmask)[iLib].index);
1411 			NetDictResponse *resp = netdict_get_cache_resp(dict_cacheid, sWord);
1412 			if(!ismainwin)
1413 				composite_lookup_float_win.send_net_dict_request(dict_cacheid, sWord);
1414 			if (!resp) {
1415 				oStarDictPlugins->NetDictPlugins.lookup((*dictmask)[iLib].index, sWord, ismainwin);
1416 			} else {
1417 				show_netdict_resp(dict_cacheid, resp, ismainwin);
1418 			}
1419 		}
1420 	}
1421 }
1422 
ShowDataToTextWin(gchar *** pppWord,gchar **** ppppWordData,const gchar * sOriginWord,bool isShowFirst)1423 void AppCore::ShowDataToTextWin(gchar ***pppWord, gchar ****ppppWordData,
1424 				const gchar *sOriginWord, bool isShowFirst)
1425 {
1426 	oMidWin.oTextWin.Show(sOriginWord, pppWord, ppppWordData);
1427 	if (isShowFirst)
1428 		oMidWin.oTextWin.query_result = TEXT_WIN_SHOW_FIRST;
1429 	else
1430 		oMidWin.oTextWin.query_result = TEXT_WIN_FOUND;
1431 	oMidWin.oTextWin.queryWord = sOriginWord;
1432 
1433 	oMidWin.oIndexWin.oResultWin.Clear();
1434 	int bookindex = 0;
1435 	for (size_t i=0; i < query_dictmask.size(); i++) {
1436 		if (pppWord[i]) {
1437 			gchar *mark = g_strdup_printf("%d", bookindex);
1438 			bookindex++;
1439 			if (query_dictmask[i].type == InstantDictType_LOCAL)
1440 				oMidWin.oIndexWin.oResultWin.InsertLast(oLibs.dict_name(query_dictmask[i].index).c_str(), mark);
1441 			else if (query_dictmask[i].type == InstantDictType_VIRTUAL)
1442 				oMidWin.oIndexWin.oResultWin.InsertLast(oStarDictPlugins->VirtualDictPlugins.dict_name(query_dictmask[i].index), mark);
1443 			else if (query_dictmask[i].type == InstantDictType_NET)
1444 				oMidWin.oIndexWin.oResultWin.InsertLast(oStarDictPlugins->NetDictPlugins.dict_name(query_dictmask[i].index), mark);
1445 			g_free(mark);
1446 		}
1447 	}
1448 
1449 	oMidWin.oTextWin.readwordtype = oReadWord.canRead(sOriginWord);
1450 	if (oMidWin.oTextWin.readwordtype != READWORD_CANNOT) {
1451 		oMidWin.oTextWin.pronounceWord = sOriginWord;
1452 	}
1453 	else {
1454 		for (size_t i=0;i< query_dictmask.size(); i++) {
1455 			if (pppWord[i] && strcmp(pppWord[i][0], sOriginWord)) {
1456 				oMidWin.oTextWin.readwordtype = oReadWord.canRead(pppWord[i][0]);
1457 				if (oMidWin.oTextWin.readwordtype != READWORD_CANNOT) {
1458 					oMidWin.oTextWin.pronounceWord = pppWord[i][0];
1459 				}
1460 				break;
1461 			}
1462 		}
1463 	}
1464 	gtk_widget_set_sensitive(GTK_WIDGET(oMidWin.oToolWin.PronounceWordMenuButton), (oMidWin.oTextWin.readwordtype != READWORD_CANNOT));
1465 }
1466 
ShowTreeDictDataToTextWin(guint32 offset,guint32 size,gint iTreeDict)1467 void AppCore::ShowTreeDictDataToTextWin(guint32 offset, guint32 size, gint iTreeDict)
1468 {
1469 	oMidWin.oTextWin.ShowTreeDictData(oTreeDicts.poGetWordData(offset, size, iTreeDict));
1470 	oMidWin.oTextWin.query_result = TEXT_WIN_TREEDICT;
1471 
1472 	oMidWin.oIndexWin.oResultWin.Clear();
1473 }
1474 
ShowNotFoundToTextWin(const char * sWord,const char * sReason,TextWinQueryResult query_result)1475 void AppCore::ShowNotFoundToTextWin(const char* sWord,const char* sReason, TextWinQueryResult query_result)
1476 {
1477 	bool have_netdict = false;
1478 	for (size_t iLib=0; iLib<query_dictmask.size(); iLib++) {
1479 		if (query_dictmask[iLib].type == InstantDictType_NET) {
1480 			have_netdict = true;
1481 			break;
1482 		}
1483 	}
1484 	bool enable_netdict = conf->get_bool_at("network/enable_netdict");
1485 	if (!enable_netdict && !have_netdict) {
1486 		oMidWin.oTextWin.Show(sReason);
1487 	}
1488 	oMidWin.oTextWin.query_result = query_result;
1489 	oMidWin.oTextWin.queryWord = sWord;
1490 
1491 	oMidWin.oIndexWin.oResultWin.Clear();
1492 
1493 	oMidWin.oTextWin.readwordtype = oReadWord.canRead(sWord);
1494 	if (oMidWin.oTextWin.readwordtype != READWORD_CANNOT)
1495 		oMidWin.oTextWin.pronounceWord = sWord;
1496 	gtk_widget_set_sensitive(GTK_WIDGET(oMidWin.oToolWin.PronounceWordMenuButton), oMidWin.oTextWin.readwordtype != READWORD_CANNOT);
1497 }
1498 
TopWinEnterWord()1499 void AppCore::TopWinEnterWord()
1500 {
1501 	const gchar *text = oTopWin.get_text();
1502 	if (text[0]=='\0')
1503 		return;
1504 	oTopWin.select_region_in_text(0, -1);
1505 	oTopWin.InsertHisList(text);
1506 	oTopWin.InsertBackList();
1507 	std::string res;
1508 	switch (analyse_query(text, res)) {
1509 	case qtFUZZY:
1510 		LookupWithFuzzyToMainWin(res.c_str());
1511 		break;
1512 	case qtPATTERN:
1513 		LookupWithRuleToMainWin(res.c_str());
1514 		break;
1515 	case qtREGEX:
1516 		LookupWithRegexToMainWin(res.c_str());
1517 		break;
1518 	case qtFULLTEXT:
1519 		LookupDataToMainWin(res.c_str());
1520 		return;
1521 	default:
1522 		if (!conf->get_bool_at("main_window/search_while_typing")) {
1523 			if (oMidWin.oTextWin.queryWord != res) {
1524 				bool showfirst = conf->get_bool_at("main_window/showfirst_when_notfound");
1525 				bool find = SimpleLookupToTextWin(res.c_str(), iCurrentIndex, NULL, true, !showfirst);
1526 				if (!find && showfirst) {
1527 					const gchar *sug_word = oLibs.GetSuggestWord(res.c_str(), iCurrentIndex, query_dictmask, 0);
1528 					if (sug_word) {
1529 						gchar *suit_word = g_strdup(sug_word);
1530 						SimpleLookupToTextWin(suit_word, iCurrentIndex, NULL, false, true, true);
1531 						g_free(suit_word);
1532 					} else {
1533 						ShowNotFoundToTextWin(res.c_str(), _("<Not Found!>"), TEXT_WIN_NOT_FOUND);
1534 					}
1535 				}
1536 				ListWords(iCurrentIndex);
1537 				break;
1538 			}
1539 		}
1540 		switch (oMidWin.oTextWin.query_result) {
1541 		case TEXT_WIN_NOT_FOUND:
1542 		case TEXT_WIN_SHOW_FIRST:
1543 		case TEXT_WIN_NET_NOT_FOUND:
1544 		case TEXT_WIN_NET_SHOW_FIRST:
1545 			LookupWithFuzzyToMainWin(res.c_str());
1546 			if (conf->get_bool_at("network/enable_netdict")) {
1547 				std::string word = "/";
1548 				word += res;
1549 				STARDICT::Cmd *c = new STARDICT::Cmd(STARDICT::CMD_LOOKUP, word.c_str());
1550 				if (!oStarDictClient.try_cache(c)) {
1551 					waiting_mainwin_lookupcmd_seq = c->seq;
1552 					oStarDictClient.send_commands(1, c);
1553 				}
1554 			}
1555 			return;
1556 		case TEXT_WIN_INFO:
1557 		case TEXT_WIN_TREEDICT:
1558 		{
1559 			GtkTreeSelection *selection =
1560 				gtk_tree_view_get_selection(oMidWin.oIndexWin.oListWin.treeview_);
1561 			GtkTreeModel *model;
1562 			GtkTreeIter iter;
1563 			gboolean selected = gtk_tree_selection_get_selected(selection,&model,&iter);
1564 			bool not_first_row=false;
1565 			if (selected) {
1566 				gchar *path_str = gtk_tree_model_get_string_from_iter(model,&iter);
1567 				if (!strcmp(path_str,"0"))
1568 					not_first_row = false;
1569 				else
1570 					not_first_row = true;
1571 				g_free(path_str);
1572 			}
1573 			if (!selected || not_first_row) {
1574 				// now select the first row.
1575 				GtkTreePath* path = gtk_tree_path_new_first();
1576 				gtk_tree_model_get_iter(model,&iter,path);
1577 				gtk_tree_selection_select_iter(selection,&iter);
1578 				gtk_tree_view_scroll_to_cell(oMidWin.oIndexWin.oListWin.treeview_,
1579 							     path, NULL, FALSE, 0, 0);
1580 				gtk_tree_path_free(path);
1581 				return;
1582 			} else {
1583 				SimpleLookupToTextWin(res.c_str(), iCurrentIndex, res.c_str(), false); //text 's index is already cached.
1584 			}
1585 			break;
1586 		}
1587 		case TEXT_WIN_FOUND:
1588 		case TEXT_WIN_NET_FOUND:
1589 			if (oMidWin.oTextWin.queryWord != res) {
1590 				//user have selected some other word in the list,now select the first word again.
1591 				GtkTreePath* path = gtk_tree_path_new_first();
1592 				GtkTreeModel *model =
1593 					gtk_tree_view_get_model(oMidWin.oIndexWin.oListWin.treeview_);
1594 				GtkTreeIter iter;
1595 				gtk_tree_model_get_iter(model,&iter,path);
1596 				GtkTreeSelection *selection =
1597 					gtk_tree_view_get_selection(oMidWin.oIndexWin.oListWin.treeview_);
1598 				gtk_tree_selection_select_iter(selection,&iter);
1599 				gtk_tree_view_scroll_to_cell(
1600 					oMidWin.oIndexWin.oListWin.treeview_, path, NULL, FALSE, 0, 0);
1601 				gtk_tree_path_free(path);
1602 			} else {
1603 				if (gtk_widget_get_sensitive(GTK_WIDGET(oMidWin.oToolWin.PronounceWordMenuButton)))
1604 					oReadWord.read(oMidWin.oTextWin.pronounceWord.c_str(), oMidWin.oTextWin.readwordtype);
1605 			}
1606 			return;
1607 		default:
1608 			/*nothing*/break;
1609 		}//switch (oMidWin.oTextWin.query_result) {
1610 	}
1611 	if (conf->get_bool_at("network/enable_netdict")) {
1612 		STARDICT::Cmd *c = new STARDICT::Cmd(STARDICT::CMD_LOOKUP, text);
1613 		if (!oStarDictClient.try_cache(c)) {
1614 			waiting_mainwin_lookupcmd_seq = c->seq;
1615 			oStarDictClient.send_commands(1, c);
1616 		}
1617 	}
1618 	LookupNetDict(text, true);
1619 }
1620 
TopWinWordChange(const gchar * sWord)1621 void AppCore::TopWinWordChange(const gchar* sWord)
1622 {
1623 	std::string res;
1624 	switch (analyse_query(sWord, res)) {
1625 	case qtPATTERN:
1626 		oMidWin.oTextWin.Show(_("Press Enter to list the words that match the pattern."));
1627 		break;
1628 	case qtREGEX:
1629 		oMidWin.oTextWin.Show(_("Press Enter to list the words that match this regular expression."));
1630 		break;
1631 	case qtFUZZY:
1632 		if (strlen(sWord)==1)
1633 			oMidWin.oTextWin.Show(_("Fuzzy query..."));
1634 		break;
1635 	case qtFULLTEXT:
1636 		if (strlen(sWord)==1)
1637 			oMidWin.oTextWin.Show(_("Full-text search..."));
1638 		break;
1639 	default:
1640 		stop_word_change_timer();
1641 		delayed_word_ = res;
1642 		int word_change_timeout = conf->get_int_at("main_window/word_change_timeout");
1643 		if(word_change_timeout > 0) {
1644 			word_change_timeout_id = g_timeout_add(word_change_timeout, on_word_change_timeout, this);
1645 		} else {
1646 			//Allow word_change_timeout to be 0, so do an immediate search.
1647 			on_word_change_timeout(this);
1648 		}
1649 	}
1650 }
1651 
on_word_change_timeout(gpointer data)1652 gboolean AppCore::on_word_change_timeout(gpointer data)
1653 {
1654 	AppCore *app = static_cast<AppCore *>(data);
1655 	bool showfirst = conf->get_bool_at("main_window/showfirst_when_notfound");
1656 	bool find = app->SimpleLookupToTextWin(app->delayed_word_.c_str(),
1657 					       app->iCurrentIndex, NULL, true,
1658 					       !showfirst);
1659 	if (!find && showfirst) {
1660 		const gchar *sug_word = app->oLibs.GetSuggestWord(app->delayed_word_.c_str(), app->iCurrentIndex, app->query_dictmask, 0);
1661 		if (sug_word) {
1662 			gchar *suit_word = g_strdup(sug_word);
1663 			app->SimpleLookupToTextWin(suit_word, app->iCurrentIndex, NULL, false, true, true);
1664 			g_free(suit_word);
1665 		} else {
1666 			app->ShowNotFoundToTextWin(app->delayed_word_.c_str(), _("<Not Found!>"), TEXT_WIN_NOT_FOUND);
1667 		}
1668 	}
1669 	app->ListWords(app->iCurrentIndex);
1670 
1671 	bool enable_netdict = conf->get_bool_at("network/enable_netdict");
1672 	if (enable_netdict) {
1673 		STARDICT::Cmd *c = new STARDICT::Cmd(STARDICT::CMD_LOOKUP, app->delayed_word_.c_str());
1674 		if (!app->oStarDictClient.try_cache(c)) {
1675 			app->waiting_mainwin_lookupcmd_seq = c->seq;
1676 			app->oStarDictClient.send_commands(1, c);
1677 		}
1678 	}
1679 	app->LookupNetDict(app->delayed_word_.c_str(), true);
1680 
1681 	app->word_change_timeout_id = 0;//next line destroy timer
1682 	return FALSE;
1683 }
1684 
ListWords(CurrentIndex * iIndex)1685 void AppCore::ListWords(CurrentIndex* iIndex)
1686 {
1687 	CurrentIndex *iCurrent = (CurrentIndex*)g_memdup(iIndex, sizeof(CurrentIndex)*query_dictmask.size());
1688 
1689 	oMidWin.oIndexWin.oListWin.Clear();
1690 	oMidWin.oIndexWin.oListWin.SetModel(true);
1691 	oMidWin.oIndexWin.oListWin.list_word_type = LIST_WIN_NORMAL_LIST;
1692 
1693 	int iWordCount=0;
1694 	const gchar * poCurrentWord=oLibs.poGetCurrentWord(iCurrent, query_dictmask, 0);
1695 	if (poCurrentWord) {
1696 		oMidWin.oIndexWin.oListWin.InsertLast(poCurrentWord);
1697 		iWordCount++;
1698 
1699 		while (iWordCount<LIST_WIN_ROW_NUM &&
1700 					 (poCurrentWord=oLibs.poGetNextWord(NULL,iCurrent, query_dictmask, 0))) {
1701 			oMidWin.oIndexWin.oListWin.InsertLast(poCurrentWord);
1702 			iWordCount++;
1703 		}
1704 		oMidWin.oIndexWin.oListWin.ReScroll();
1705 	}
1706 	g_free(iCurrent);
1707 }
1708 
ListPreWords(const char * sWord)1709 void AppCore::ListPreWords(const char*sWord)
1710 {
1711 	oMidWin.oIndexWin.oListWin.Clear();
1712 	CurrentIndex *iPreIndex = (CurrentIndex *)g_malloc(sizeof(CurrentIndex) * query_dictmask.size());
1713 	const gchar *preword = oLibs.poGetPreWord(sWord, iPreIndex, query_dictmask, 0);
1714 	if (preword) {
1715 		int iWordCount=1;
1716 		oMidWin.oIndexWin.oListWin.Prepend(preword);
1717 		while (iWordCount<15 && (preword=oLibs.poGetPreWord(NULL,iPreIndex, query_dictmask, 0))) {
1718 			oMidWin.oIndexWin.oListWin.Prepend(preword);
1719 			iWordCount++;
1720 		}
1721 		oMidWin.oIndexWin.oListWin.ReScroll();
1722 	}
1723 	g_free(iPreIndex);
1724 }
1725 
ListNextWords(const char * sWord)1726 void AppCore::ListNextWords(const char*sWord)
1727 {
1728 	oMidWin.oIndexWin.oListWin.Clear();
1729 	CurrentIndex *iNextIndex = (CurrentIndex *)g_malloc(sizeof(CurrentIndex) * query_dictmask.size());
1730 	const gchar *nextword = oLibs.poGetNextWord(sWord, iNextIndex, query_dictmask, 0);
1731 	if (nextword) {
1732 		int iWordCount=1;
1733 		oMidWin.oIndexWin.oListWin.InsertLast(nextword);
1734 		while (iWordCount<30 && (nextword = oLibs.poGetNextWord(NULL, iNextIndex, query_dictmask, 0))) {
1735 			oMidWin.oIndexWin.oListWin.InsertLast(nextword);
1736 			iWordCount++;
1737 		}
1738 		oMidWin.oIndexWin.oListWin.ReScroll();
1739 	}
1740 	g_free(iNextIndex);
1741 }
1742 
Query(const gchar * word)1743 void AppCore::Query(const gchar *word)
1744 {
1745 	oTopWin.InsertHisList(oTopWin.get_text());
1746 	oTopWin.InsertBackList();
1747 	oTopWin.SetText(word);
1748 	std::string res;
1749 	switch (analyse_query(word, res)) {
1750 	case qtSIMPLE:
1751 		break;
1752 	default:
1753 		TopWinEnterWord();
1754 		break;
1755 	}
1756 
1757 	oTopWin.TextSelectAll();
1758 	oTopWin.grab_focus();
1759 	oTopWin.InsertHisList(word);
1760 	oTopWin.InsertBackList(word);
1761 }
1762 
ListClick(const gchar * word)1763 void AppCore::ListClick(const gchar *word)
1764 {
1765 	oTopWin.InsertHisList(oTopWin.get_text());
1766 	oTopWin.InsertBackList();
1767 	oTopWin.SetText(word);
1768 	oTopWin.InsertHisList(word);
1769 	oTopWin.InsertBackList(word);
1770 	oTopWin.grab_focus();
1771 }
1772 
on_stardict_client_error(const char * error_msg)1773 void AppCore::on_stardict_client_error(const char *error_msg)
1774 {
1775 	GtkWindow *parent;
1776 	if (dict_manage_dlg && dict_manage_dlg->window && gtk_widget_get_visible(GTK_WIDGET(dict_manage_dlg->window))) {
1777 		parent = GTK_WINDOW(dict_manage_dlg->window);
1778 	} else if (prefs_dlg && prefs_dlg->window) {
1779 		parent = GTK_WINDOW(prefs_dlg->window);
1780 	} else {
1781 		parent = GTK_WINDOW(window);
1782 	}
1783     GtkWidget *message_dlg =
1784         gtk_message_dialog_new(
1785                 parent,
1786                 (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
1787                 GTK_MESSAGE_INFO,  GTK_BUTTONS_OK,
1788                 "%s", error_msg);
1789     gtk_dialog_set_default_response(GTK_DIALOG(message_dlg), GTK_RESPONSE_OK);
1790     gtk_window_set_resizable(GTK_WINDOW(message_dlg), FALSE);
1791     g_signal_connect_swapped (message_dlg, "response", G_CALLBACK (gtk_widget_destroy), message_dlg);
1792     gtk_widget_show(message_dlg);
1793 }
1794 
on_stardict_client_register_end(const char * msg)1795 void AppCore::on_stardict_client_register_end(const char *msg)
1796 {
1797 	if (prefs_dlg) {
1798 		prefs_dlg->on_register_end(msg);
1799 	}
1800 }
1801 
on_stardict_client_getdictmask_end(const char * msg)1802 void AppCore::on_stardict_client_getdictmask_end(const char *msg)
1803 {
1804 	if (dict_manage_dlg)
1805 		dict_manage_dlg->network_getdictmask(msg);
1806 }
1807 
on_stardict_client_getadinfo_end(const char * msg)1808 void AppCore::on_stardict_client_getadinfo_end(const char *msg)
1809 {
1810 	if (dict_manage_dlg)
1811 		dict_manage_dlg->network_getadinfo(msg);
1812 }
1813 
on_stardict_client_dirinfo_end(const char * msg)1814 void AppCore::on_stardict_client_dirinfo_end(const char *msg)
1815 {
1816 	if (dict_manage_dlg)
1817 		dict_manage_dlg->network_dirinfo(msg);
1818 }
1819 
on_stardict_client_dictinfo_end(const char * msg)1820 void AppCore::on_stardict_client_dictinfo_end(const char *msg)
1821 {
1822 	if (dict_manage_dlg)
1823 		dict_manage_dlg->network_dictinfo(msg);
1824 }
1825 
on_stardict_client_maxdictcount_end(int count)1826 void AppCore::on_stardict_client_maxdictcount_end(int count)
1827 {
1828 	if (dict_manage_dlg)
1829 		dict_manage_dlg->network_maxdictcount(count);
1830 }
1831 
on_stardict_client_previous_end(std::list<char * > * wordlist_response)1832 void AppCore::on_stardict_client_previous_end(std::list<char *> *wordlist_response)
1833 {
1834 	if (!wordlist_response->empty()) {
1835 		oMidWin.oIndexWin.oListWin.MergeWordList(wordlist_response);
1836 		oMidWin.oIndexWin.oListWin.ReScroll();
1837 	}
1838 }
1839 
on_stardict_client_next_end(std::list<char * > * wordlist_response)1840 void AppCore::on_stardict_client_next_end(std::list<char *> *wordlist_response)
1841 {
1842 	if (!wordlist_response->empty()) {
1843 		oMidWin.oIndexWin.oListWin.MergeWordList(wordlist_response);
1844 		oMidWin.oIndexWin.oListWin.ReScroll();
1845 	}
1846 }
1847 
on_stardict_client_lookup_end(const struct STARDICT::LookupResponse * lookup_response,unsigned int seq)1848 void AppCore::on_stardict_client_lookup_end(const struct STARDICT::LookupResponse *lookup_response, unsigned int seq)
1849 {
1850     if (seq != 0 && waiting_mainwin_lookupcmd_seq != seq)
1851         return;
1852     oMidWin.oTextWin.Show(&(lookup_response->dict_response), lookup_response->listtype);
1853     if (lookup_response->listtype == STARDICT::LookupResponse::ListType_List || lookup_response->listtype == STARDICT::LookupResponse::ListType_Rule_List || lookup_response->listtype == STARDICT::LookupResponse::ListType_Regex_List) {
1854 	if (!lookup_response->wordlist->empty()) {
1855 		oMidWin.oIndexWin.oListWin.MergeWordList(lookup_response->wordlist);
1856 		oMidWin.oIndexWin.oListWin.ReScroll();
1857 	}
1858     } else if (lookup_response->listtype == STARDICT::LookupResponse::ListType_Fuzzy_List) {
1859 	if (!lookup_response->wordlist->empty()) {
1860 		oMidWin.oIndexWin.oListWin.MergeFuzzyList(lookup_response->wordlist);
1861 		oMidWin.oIndexWin.oListWin.ReScroll();
1862 	}
1863     } else if (lookup_response->listtype == STARDICT::LookupResponse::ListType_Tree) {
1864         if (!lookup_response->wordtree->empty()) {
1865             oMidWin.oIndexWin.oListWin.SetTreeModel(lookup_response->wordtree);
1866             oMidWin.oIndexWin.oListWin.ReScroll();
1867         }
1868     }
1869 }
1870 
on_stardict_client_floatwin_lookup_end(const struct STARDICT::LookupResponse * lookup_response,unsigned int seq)1871 void AppCore::on_stardict_client_floatwin_lookup_end(const struct STARDICT::LookupResponse *lookup_response, unsigned int seq)
1872 {
1873 	if(seq == 0 || composite_lookup_float_win.got_StarDict_net_responce(seq)) {
1874 		oFloatWin.AppendTextStarDictNet(&(lookup_response->dict_response));
1875 		if(composite_lookup_float_win.is_got_all_responses())
1876 			oFloatWin.EndLookup();
1877 	}
1878 }
1879 
on_http_client_error(HttpClient * http_client,const char * error_msg)1880 void AppCore::on_http_client_error(HttpClient *http_client, const char *error_msg)
1881 {
1882 	if (http_client->callback_func_) {
1883 		http_client->callback_func_(NULL, 0, http_client->userdata);
1884 	} else {
1885 		GtkWindow *parent;
1886 		if (dict_manage_dlg && dict_manage_dlg->window && gtk_widget_get_visible(GTK_WIDGET(dict_manage_dlg->window))) {
1887 			parent = GTK_WINDOW(dict_manage_dlg->window);
1888 		} else if (prefs_dlg && prefs_dlg->window) {
1889 			parent = GTK_WINDOW(prefs_dlg->window);
1890 		} else {
1891 			parent = GTK_WINDOW(window);
1892 		}
1893 		GtkWidget *message_dlg =
1894 			gtk_message_dialog_new(
1895 				parent,
1896 				(GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
1897 				GTK_MESSAGE_INFO,  GTK_BUTTONS_OK,
1898 				"%s", error_msg);
1899 		gtk_dialog_set_default_response(GTK_DIALOG(message_dlg), GTK_RESPONSE_OK);
1900 		gtk_window_set_resizable(GTK_WINDOW(message_dlg), FALSE);
1901 		g_signal_connect_swapped (message_dlg, "response", G_CALLBACK (gtk_widget_destroy), message_dlg);
1902 		gtk_widget_show(message_dlg);
1903 	}
1904 	oHttpManager.Remove(http_client);
1905 }
1906 
on_http_client_response(HttpClient * http_client)1907 void AppCore::on_http_client_response(HttpClient *http_client)
1908 {
1909 	if (http_client->callback_func_) {
1910 		http_client->callback_func_(http_client->buffer, http_client->buffer_len, http_client->userdata);
1911 		oHttpManager.Remove(http_client);
1912 		return;
1913 	}
1914 	oHttpManager.Remove(http_client);
1915 }
1916 
PopupPrefsDlg()1917 void AppCore::PopupPrefsDlg()
1918 {
1919 	if (!prefs_dlg) {
1920 		prefs_dlg = new PrefsDlg(GTK_WINDOW(window),
1921 					 get_impl(oAppSkin.icon),
1922 					 unlock_keys->possible_combs());
1923 		bool enbcol =
1924 			conf->get_bool_at("dictionary/enable_collation");
1925 		int colf =
1926 			conf->get_int_at("dictionary/collate_function");
1927 		bool exiting = prefs_dlg->ShowModal();
1928 		delete prefs_dlg;
1929 		prefs_dlg = NULL;
1930 		if (exiting)
1931 			return;
1932 		if (enbcol == conf->get_bool_at("dictionary/enable_collation") &&
1933 		    colf == conf->get_int_at("dictionary/collate_function"))
1934 			return;
1935 		progress_win pw(GTK_WINDOW(gpAppFrame->window));
1936 		reload_show_progress_t rsp(pw);
1937 		show_progress_t *old_progress = oLibs.get_show_progress();
1938 		oLibs.set_show_progress(&rsp);
1939 		reload_dicts();
1940 		oLibs.set_show_progress(old_progress);
1941 	}
1942 }
1943 
reload_dicts()1944 void AppCore::reload_dicts()
1945 {
1946 	std::list<DictItemId> load_list;
1947 	GetUsedDictList(load_list);
1948 	std::list<std::string> s_load_list;
1949 	DictItemId::convert(s_load_list, load_list);
1950 	oLibs.reload(s_load_list,
1951 		conf->get_bool_at("dictionary/enable_collation") ? CollationLevel_SINGLE : CollationLevel_NONE,
1952 		int_to_colate_func(conf->get_int_at("dictionary/collate_function")));
1953 	UpdateDictMask();
1954 
1955 	const gchar *sWord = oTopWin.get_text();
1956 
1957 	if (sWord && sWord[0])
1958 		TopWinWordChange(sWord);
1959 }
1960 
PopupDictManageDlg()1961 void AppCore::PopupDictManageDlg()
1962 {
1963 
1964 	if (!dict_manage_dlg)
1965 		dict_manage_dlg = new DictManageDlg(GTK_WINDOW(window), get_impl(oAppSkin.index_wazard), get_impl(oAppSkin.index_appendix));
1966 	bool dictmanage_config_changed;
1967 	if (dict_manage_dlg->Show(dictmanage_config_changed))
1968 		return;
1969 	if (dictmanage_config_changed) {
1970 		progress_win pw(GTK_WINDOW(gpAppFrame->window));
1971 		reload_show_progress_t rsp(pw);
1972 		show_progress_t *old_progress = oLibs.get_show_progress();
1973 		oLibs.set_show_progress(&rsp);
1974 		reload_dicts();
1975 		oLibs.set_show_progress(old_progress);
1976 	}
1977 }
1978 
PopupPluginManageDlg()1979 void AppCore::PopupPluginManageDlg()
1980 {
1981 	if (!plugin_manage_dlg) {
1982 		plugin_manage_dlg = new PluginManageDlg();
1983 		bool dict_changed;
1984 		bool order_changed;
1985 		bool exiting = plugin_manage_dlg->ShowModal(GTK_WINDOW(window), dict_changed, order_changed);
1986 		delete plugin_manage_dlg;
1987 		plugin_manage_dlg = NULL;
1988 		if (exiting)
1989 			return;
1990 		if (order_changed) {
1991 #ifdef _WIN32
1992 			std::list<std::string> plugin_order_list;
1993 			{
1994 				const std::list<std::string>& plugin_order_list_rel
1995 					= conf->get_strlist("/apps/stardict/manage_plugins/plugin_order_list");
1996 				abs_path_to_data_dir(plugin_order_list_rel, plugin_order_list);
1997 			}
1998 #else
1999 			const std::list<std::string>& plugin_order_list
2000 				= conf->get_strlist("/apps/stardict/manage_plugins/plugin_order_list");
2001 #endif
2002 			oStarDictPlugins->VirtualDictPlugins.reorder(plugin_order_list);
2003 			oStarDictPlugins->NetDictPlugins.reorder(plugin_order_list);
2004 			oMidWin.oToolWin.UpdatePronounceMenu();
2005 		}
2006 		if (dict_changed) {
2007 			UpdateDictMask();
2008 
2009 			const gchar *sWord = oTopWin.get_text();
2010 			if (sWord && sWord[0])
2011 				TopWinWordChange(sWord);
2012 		}
2013 	}
2014 }
2015 
stop_word_change_timer()2016 void AppCore::stop_word_change_timer()
2017 {
2018 	if (word_change_timeout_id) {
2019 		g_source_remove(word_change_timeout_id);
2020 		word_change_timeout_id = 0;
2021 	}
2022 }
2023 
End()2024 void AppCore::End()
2025 {
2026 	stop_word_change_timer();
2027 	oSelection.End();
2028 #ifdef _WIN32
2029 	oClipboard.End();
2030 	oMouseover.End();
2031 #endif
2032 #ifdef ENABLE_LOG_WINDOW
2033 	gLogWindow.End();
2034 #endif
2035 	oHotkey.End();
2036 	oFloatWin.End();
2037 
2038 	oDockLet.reset(0);
2039 
2040 	if (dict_manage_dlg)
2041 		dict_manage_dlg->Close();
2042 	if (prefs_dlg)
2043 		prefs_dlg->Close(); // After user open the preferences dialog, then choose quit in the notification icon, this dialog can be closed.
2044 	oTopWin.Destroy();
2045 	oMidWin.oIndexWin.oListWin.Destroy();
2046 	oBottomWin.Destroy();
2047 
2048 	gtk_widget_destroy(window);
2049 }
2050 
Init(const gchar * queryword)2051 void AppCore::Init(const gchar *queryword)
2052 {
2053 	conf->notify_add("/apps/stardict/preferences/main_window/hide_list",
2054 			 sigc::mem_fun(this, &AppCore::on_main_win_hide_list_changed));
2055 	conf->notify_add("/apps/stardict/preferences/dictionary/scan_selection",
2056 			 sigc::mem_fun(this, &AppCore::on_dict_scan_select_changed));
2057 	conf->notify_add("/apps/stardict/preferences/dictionary/scan_modifier_key",
2058 			 sigc::mem_fun(this, &AppCore::on_scan_modifier_key_changed));
2059 
2060 	g_debug(_("Loading skin..."));
2061 #ifdef _WIN32
2062 	oAppSkin.load(abs_path_to_data_dir(conf->get_string_at("main_window/skin")));
2063 #else
2064 	oAppSkin.load(conf->get_string_at("main_window/skin"));
2065 #endif
2066 	g_debug(_("Skin loaded."));
2067 
2068 	if (!CmdLineOptions::get_hide())
2069 		stardict_splash.show();
2070 
2071 	Create(queryword);
2072 
2073 #ifdef CONFIG_GNOME
2074   stardict_app_server =
2075     stardict_application_server_new(gdk_screen_get_default());
2076 #endif
2077 
2078 	stardict_splash.on_mainwin_finish();
2079 	oStarDictPlugins->MiscPlugins.on_mainwin_finish();
2080 	gtk_main();
2081 }
2082 
Quit()2083 void AppCore::Quit()
2084 {
2085 	if (!conf->get_bool_at("main_window/maximized")) {
2086 		gint width, height;
2087 		gtk_window_get_size(GTK_WINDOW(window), &width, &height);
2088 		conf->set_int_at("main_window/window_width", width);
2089 		conf->set_int_at("main_window/window_height", height);
2090 	}
2091 	gint pos = gtk_paned_get_position(GTK_PANED(oMidWin.hpaned));
2092 	conf->set_int_at("main_window/hpaned_pos", pos);
2093 
2094 	End();
2095 
2096 #ifdef CONFIG_GNOME
2097 	bonobo_object_unref (stardict_app_server);
2098 #endif
2099 	unlock_keys.reset(0);
2100 	conf.reset(0);
2101 	gtk_main_quit();
2102 }
2103 
on_main_win_hide_list_changed(const baseconfval * hideval)2104 void AppCore::on_main_win_hide_list_changed(const baseconfval* hideval)
2105 {
2106 	bool hide = static_cast<const confval<bool> *>(hideval)->val_;
2107 
2108 	if (hide) {
2109 		gtk_widget_hide(oMidWin.oToolWin.HideListButton);
2110 		gtk_widget_show(oMidWin.oToolWin.ShowListButton);
2111 		gtk_widget_hide(oMidWin.oLeftWin.vbox);
2112 		gtk_widget_hide(oMidWin.oIndexWin.notebook);
2113 	} else {
2114 		gtk_widget_hide(oMidWin.oToolWin.ShowListButton);
2115 		gtk_widget_show(oMidWin.oToolWin.HideListButton);
2116 		gtk_widget_show(oMidWin.oLeftWin.vbox);
2117 		gtk_widget_show(oMidWin.oIndexWin.notebook);
2118 	}
2119 }
2120 
on_dict_scan_select_changed(const baseconfval * scanval)2121 void AppCore::on_dict_scan_select_changed(const baseconfval* scanval)
2122 {
2123 	bool scan = static_cast<const confval<bool> *>(scanval)->val_;
2124 
2125 	if (scan != static_cast<bool>(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(oBottomWin.ScanSelectionCheckButton))))
2126 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(oBottomWin.ScanSelectionCheckButton), scan);
2127 
2128 	oDockLet->set_scan_mode(scan);
2129 	if (gtk_widget_get_visible(GTK_WIDGET(window)))
2130 		oDockLet->hide_state();
2131 	if (scan) {
2132 		bool lock=conf->get_bool_at("floating_window/lock");
2133 		if (lock && !oFloatWin.getQueryingWord().empty())
2134 			oFloatWin.Show();
2135 		oSelection.start();
2136 #ifdef _WIN32
2137 		if (conf->get_bool_at("dictionary/scan_clipboard")) {
2138 			oClipboard.start();
2139 		}
2140 		oMouseover.start();
2141 #endif
2142 	} else {
2143 		oFloatWin.Hide();
2144 		oSelection.stop();
2145 #ifdef _WIN32
2146 		if (conf->get_bool_at("dictionary/scan_clipboard")) {
2147 			oClipboard.stop();
2148 		}
2149 		oMouseover.stop();
2150 #endif
2151 	}
2152 }
2153 
on_scan_modifier_key_changed(const baseconfval * keyval)2154 void AppCore::on_scan_modifier_key_changed(const baseconfval* keyval)
2155 {
2156 	int key = static_cast<const confval<int> *>(keyval)->val_;
2157 	unlock_keys->set_comb(combnum2str(key));
2158 }
2159 
GetPureEnglishAlpha(gchar * str)2160 gchar* GetPureEnglishAlpha(gchar *str)
2161 {
2162 	while (*str && (!((*str >= 'a' && *str <='z')||(*str >= 'A' && *str <='Z'))))
2163 		str++;
2164 	gchar *p = str;
2165 	while (*p && ((*p >= 'a' && *p <='z')||(*p >= 'A' && *p <='Z')||(*p==' ')))
2166 		p++;
2167 	*p='\0';
2168 	return str;
2169 }
2170 
GetHeadWord(gchar * str)2171 gchar* GetHeadWord(gchar *str)
2172 {
2173 	while (g_ascii_isspace(*str))
2174 		str++;
2175 	glong len = g_utf8_strlen(str, -1);
2176 	if (len) {
2177 		gchar *last_str = g_utf8_offset_to_pointer(str, len-1);
2178 		gunichar last = g_utf8_get_char(last_str);
2179 		while ((g_unichar_isspace(last) || g_unichar_ispunct(last)) || g_unichar_isdigit(last)) {
2180 			*last_str = '\0';
2181 			last_str = g_utf8_find_prev_char(str, last_str);
2182 			if (!last_str)
2183 				break;
2184 			last = g_utf8_get_char(last_str);
2185 		}
2186 	}
2187 	return str;
2188 }
2189 
stardict_on_enter_notify(GtkWidget * widget,GdkEventCrossing * event,gpointer data)2190 gboolean stardict_on_enter_notify(GtkWidget *widget, GdkEventCrossing *event, gpointer data)
2191 {
2192 	play_sound_on_event("buttonactive");
2193 
2194 	return FALSE;
2195 }
2196 
2197 #ifdef CONFIG_GNOME
2198 static void
stardict_handle_automation_cmdline(const gchar * queryword)2199 stardict_handle_automation_cmdline (const gchar *queryword)
2200 {
2201 	CORBA_Environment env;
2202 	GNOME_Stardict_Application server;
2203 
2204 	CORBA_exception_init (&env);
2205 	CORBA_char id[] = "OAFIID:GNOME_Stardict_Application";
2206 
2207 	server = bonobo_activation_activate_from_id (id, 0, NULL, &env);
2208 	if (!server) {
2209 		gdk_notify_startup_complete ();
2210 		return;
2211 	}
2212 	//g_return_if_fail (server != NULL);
2213 
2214 	if (CmdLineOptions::get_quit()) {
2215 		GNOME_Stardict_Application_quit (server, &env);
2216 	}
2217 	else {
2218 		if (queryword) {
2219 			GNOME_Stardict_Application_queryWord (server, queryword, &env);
2220 		}
2221 		if (CmdLineOptions::get_hide()) {
2222 			GNOME_Stardict_Application_hide (server, &env);
2223 		} else {
2224 			GNOME_Stardict_Application_grabFocus (server, &env);
2225 			g_message(_("StarDict is already running. Using the running process."));
2226 		}
2227 	}
2228 
2229 
2230 	bonobo_object_release_unref (server, &env);
2231 	CORBA_exception_free (&env);
2232 
2233 
2234 	/* we never popup a window, so tell startup-notification that
2235 	 * we're done */
2236 	gdk_notify_startup_complete ();
2237 }
2238 
2239 /*
2240 static void client_die_cb (GnomeClient *client, gpointer client_data)
2241 {
2242 	gpAppFrame->Quit();
2243 }
2244 
2245 static gboolean save_yourself_cb (GnomeClient       *client,
2246                               gint               phase,
2247                               GnomeRestartStyle  save_style,
2248                               gint               shutdown,
2249                               GnomeInteractStyle interact_style,
2250                               gint               fast,
2251                               gpointer           client_data)
2252 {
2253     gchar *argv[] = {NULL, NULL, NULL};
2254 	gchar *word = NULL;
2255     gint argc = 1;
2256 
2257     argv[0] = (gchar *)client_data;
2258 
2259 	if (gpAppFrame->window) {
2260 		if (!gtk_widget_get_visible(GTK_WIDGET(gpAppFrame->window)))
2261 			argv[argc++] = (gchar *)"-h";
2262 	}
2263 
2264 	const gchar *text = gpAppFrame->oTopWin.get_text();
2265     	if (text[0]) {
2266 		word = g_strdup(text);
2267         	argv[argc++] = word;
2268 	}
2269 
2270     gnome_client_set_restart_command(client, argc, argv);
2271     gnome_client_set_clone_command(client, argc, argv);
2272 	if (word)
2273 		g_free(word);
2274 
2275     return true;
2276 }
2277 */
2278 #endif
2279 
2280 #if defined(_WIN32) && defined(_MSC_VER)
2281 /* Synchronize environment variables in CRTs.
2282 See section "Two copies of CRT" in doc/README_windows.txt for more details. */
synchronize_crt_enviroment(void)2283 void synchronize_crt_enviroment(void)
2284 {
2285 	const char* varname = "LANG";
2286 	size_t size;
2287 	if(getenv_s(&size, NULL, 0, varname)) {
2288 		g_warning("Unable to get the value of the %s environment variable", varname);
2289 		return;
2290 	}
2291 	if(size == 0)
2292 		return; // variable is not found
2293 	std::vector<char> buf(size);
2294 	if(getenv_s(&size, &buf[0], size, varname)) {
2295 		g_warning("Unable to get the value of the %s environment variable", varname);
2296 		return;
2297 	}
2298 	if(!g_setenv(varname, &buf[0], TRUE)) {
2299 		g_warning("Unable to set the %s environment variable.", varname);
2300 		return;
2301 	}
2302 }
2303 #endif
2304 
2305 #ifdef _WIN32
stardict_main(HINSTANCE hInstance,int argc,char ** argv)2306 DLLIMPORT int stardict_main(HINSTANCE hInstance, int argc, char **argv)
2307 #else
2308 int main(int argc,char **argv)
2309 #endif
2310 {
2311 #if defined(_WIN32)
2312 	stardictexe_hInstance = hInstance;
2313 #endif // #if defined(_WIN32)
2314 	CmdLineOptions::pre_parse_arguments(argc, argv);
2315 	const char* const dirs_config_file = CmdLineOptions::get_dirs_config_pre();
2316 	conf_dirs.reset(new AppDirs(dirs_config_file ? dirs_config_file : ""));
2317 	app_dirs = conf_dirs.get();
2318 	bindtextdomain (GETTEXT_PACKAGE, conf_dirs->get_locale_dir().c_str());
2319 	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
2320 	textdomain (GETTEXT_PACKAGE);
2321 
2322 #if defined(_WIN32) && defined(_MSC_VER)
2323 	synchronize_crt_enviroment();
2324 #endif
2325 #if defined(_WIN32) || defined(CONFIG_GTK) || defined(CONFIG_GNOME) || defined(CONFIG_MAEMO) || defined(CONFIG_DARWIN)
2326 	gtk_init(&argc, &argv);
2327 #endif
2328 	/* Register an interim logger.
2329 	On Windows, without the logger all output produced by g_option_context_parse will be lost.
2330 	For example, g_option_context_parse prints usage message when stardict is invoked with --help option.
2331 	The problem is g_option_context_parse uses g_print function to print messages,
2332 	but this function produce no output on windows console. See test_windows_console
2333 	function to check what works with windows console.
2334 	*/
2335 	logger.reset(new Logger(MessageLevel_MESSAGE, MessageLevel_NONE));
2336 #if defined(_WIN32) && defined(_DEBUG)
2337 	//test_windows_console();
2338 #endif
2339 #ifdef CONFIG_GPE
2340 	if (gpe_application_init (&argc, &argv) == FALSE)
2341 		exit (1);
2342 #endif
2343 	GOptionContext *context;
2344 	context = g_option_context_new(_("- Lookup words"));
2345 	g_option_context_add_main_entries(context, CmdLineOptions::get_options(), GETTEXT_PACKAGE);
2346 #ifndef CONFIG_GNOME
2347 	glib::Error err;
2348 	if (!g_option_context_parse(context, &argc, &argv, get_addr(err))) {
2349 		g_warning(_("Options parsing failed: %s\n"), err->message);
2350 		g_option_context_free(context);
2351 		return EXIT_FAILURE;
2352 	}
2353 	g_option_context_free(context);
2354 #else // #ifndef CONFIG_GNOME
2355 	//GnomeProgram *program;
2356 	gnome_program_init ("stardict", VERSION,
2357 			    LIBGNOME_MODULE, argc, argv,
2358 			    GNOME_PARAM_GOPTION_CONTEXT, context,
2359 			    GNOME_PARAM_HUMAN_READABLE_NAME,
2360 			    _("Dictionary"),
2361 			    GNOME_PARAM_APP_DATADIR, conf_dirs->get_system_data_dir().c_str(),
2362 			    NULL);
2363 	bonobo_init(&argc, argv);
2364 #endif // #ifndef CONFIG_GNOME
2365 
2366 	const char *query_word = NULL;
2367 	if(CmdLineOptions::get_query_words())
2368 		query_word = CmdLineOptions::get_query_words()[0];
2369 
2370 	logger->set_console_message_level(CmdLineOptions::get_console_message_level());
2371 	logger->set_log_message_level(CmdLineOptions::get_log_message_level());
2372 
2373 #ifndef CONFIG_GNOME
2374 #ifdef _WIN32
2375 	if (CmdLineOptions::get_newinstance() == FALSE) {
2376 		gchar *title=g_locale_from_utf8(_("StarDict"), -1, NULL, NULL, NULL);
2377 		HWND ll_winhandle = FindWindowA("gdkWindowToplevel", title);
2378 		g_free(title);
2379 		if (ll_winhandle > 0) {
2380 			if (IsIconic(ll_winhandle))
2381 				ShowWindow(ll_winhandle,SW_RESTORE);
2382 			else
2383 				SetForegroundWindow(ll_winhandle);
2384 			g_message("Stardict is already running.");
2385 			return EXIT_SUCCESS;
2386 		}
2387 	}
2388 #endif // #ifdef _WIN32
2389 #else // #ifndef CONFIG_GNOME
2390 	if (CmdLineOptions::get_newinstance() == FALSE) {
2391 		CORBA_Object factory;
2392 		CORBA_char id[] = "OAFIID:GNOME_Stardict_Factory";
2393 		factory = bonobo_activation_activate_from_id(id,
2394 			Bonobo_ACTIVATION_FLAG_EXISTING_ONLY,
2395 			NULL, NULL);
2396 
2397 		if (factory != NULL) {
2398 			/* there is an instance already running, so send
2399 			 * commands to it if needed
2400 			 */
2401 			stardict_handle_automation_cmdline (query_word);
2402 			/* and we're done */
2403 			return EXIT_SUCCESS;
2404 		}
2405 	}
2406 
2407 	/*
2408 	GnomeClient *client;
2409 	if ((client = gnome_master_client()) != NULL) {
2410 		g_signal_connect (client, "save_yourself", G_CALLBACK (save_yourself_cb), (gpointer) argv[0]);
2411 		g_signal_connect (client, "die", G_CALLBACK (client_die_cb), NULL);
2412 	}
2413 	*/
2414 #endif // #ifndef CONFIG_GNOME
2415 	g_debug(_("Loading StarDict configuration..."));
2416 	conf.reset(new AppConf);
2417 	g_debug(_("StarDict configuration loaded."));
2418 	AppCore oAppCore;
2419 	gpAppFrame = &oAppCore;
2420 	oAppCore.Init(query_word);
2421 
2422 	return EXIT_SUCCESS;
2423 }
2424