Imported version 0.5-1
[mstardict] / src / mstardict.cpp
1 /*
2  *  MStarDict - International dictionary for Maemo.
3  *  Copyright (C) 2010 Roman Moravcik
4  *
5  *  base on code of stardict:
6  *  Copyright (C) 2003-2007 Hu Zheng <huzheng_001@163.com>
7  *
8  *  based on code of sdcv:
9  *  Copyright (C) 2005-2006 Evgeniy <dushistov@mail.ru>
10  *
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation; either version 2 of the License, or
14  *  (at your option) any later version.
15  *
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with this program; if not, write to the Free Software
23  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #  include "config.h"
28 #endif
29
30 #include <cerrno>
31 #include <cstring>
32 #include <cstdlib>
33 #include <cstdio>
34 #include <clocale>
35
36 #include <glib.h>
37 #include <glib/gi18n.h>
38 #include <glib/gstdio.h>
39
40 #include <gtk/gtk.h>
41 #include <hildon/hildon.h>
42
43 #include <getopt.h>
44 #include <string>
45 #include <vector>
46 #include <memory>
47 #include <list>
48
49 #include "conf.hpp"
50 #include "dictmngr.hpp"
51 #include "libwrapper.hpp"
52 #include "prefsdlg.hpp"
53 #include "transwin.hpp"
54 #include "tts.hpp"
55 #include "mstardict.hpp"
56
57 MStarDict *pMStarDict;
58
59 enum {
60     DEF_COLUMN,
61     N_COLUMNS
62 };
63
64 MStarDict::MStarDict()
65 {
66     window = NULL;
67     label_widget = NULL;
68     results_widget = NULL;
69     results_view = NULL;
70     results_view_scroll = NULL;
71
72     /* create list of ressults */
73     results_list = gtk_list_store_new(N_COLUMNS,
74                                       G_TYPE_STRING);   /* DEF_COLUMN */
75
76     /* initialize configuration */
77     oConf = new Conf();
78
79     /* initialize stardict plugins */
80     std::list < std::string > plugin_order_list;
81     std::list < std::string > plugin_disable_list;
82     oPlugins = new StarDictPlugins("/usr/lib/mstardict/plugins",
83                                    plugin_order_list,
84                                    plugin_disable_list);
85
86     /* initialize dict manager */
87     oDict = new DictMngr(this);
88
89     /* initialize prefs dialog */
90     oPrefs = new PrefsDlg(this);
91
92     /* initialize translation window */
93     oTransWin = new TransWin(this);
94
95     /* initialize tts */
96     oTts = new Tts(this);
97
98     /* initialize stardict library */
99     oLibs = new Library(this);
100 }
101
102 MStarDict::~MStarDict()
103 {
104     /* destroy list of results */
105     g_object_unref(results_list);
106
107     /* deinitialize stardict library */
108     delete oLibs;
109
110     /* deinitialize tts */
111     delete oTts;
112
113     /* deinitialize translation window */
114     delete oTransWin;
115
116     /* deinitialize prefs dialog */
117     delete oPrefs;
118
119     /* deinitialize dict manager */
120     delete oDict;
121
122     /* deinitialize stardict plugins */
123     delete oPlugins;
124
125     /* deinitialize configuration */
126     delete oConf;
127 }
128
129 gboolean
130 MStarDict::onResultsViewSelectionChanged(GtkTreeSelection *selection,
131                                          MStarDict *mStarDict)
132 {
133     GtkTreeModel *model;
134     GtkTreeIter iter;
135     const gchar *sWord;
136     bool bFound = false;
137
138     if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
139         GList *results = NULL;
140
141         /* unselect selected rows */
142         gtk_tree_selection_unselect_all(selection);
143
144         gtk_tree_model_get(model, &iter, DEF_COLUMN, &sWord, -1);
145
146         for (size_t iLib = 0; iLib < mStarDict->oLibs->query_dictmask.size(); iLib++) {
147             bFound =
148                 mStarDict->oLibs->BuildResultData(mStarDict->oLibs->query_dictmask, sWord,
149                                                   mStarDict->oLibs->iCurrentIndex, iLib,
150                                                   &results);
151         }
152
153         /* create translation window */
154         mStarDict->oTransWin->CreateTransWindow(results);
155
156         /* free result data */
157         mStarDict->oLibs->FreeResultData(results);
158     }
159
160     /* grab focus to search entry */
161     mStarDict->GrabFocus();
162
163     return true;
164 }
165
166 gboolean
167 MStarDict::onSearchEntryChanged(GtkEditable* editable,
168                                 MStarDict* mStarDict)
169 {
170     const gchar *sWord;
171     bool bFound = false;
172     std::string query;
173
174     if (mStarDict->oLibs->query_dictmask.empty())
175         return true;
176
177     sWord = gtk_entry_get_text(GTK_ENTRY(editable));
178     if (strcmp(sWord, "") == 0) {
179         mStarDict->ShowNoResults(true);
180     } else {
181         mStarDict->ShowProgressIndicator(true);
182         mStarDict->ResultsUnselectAll(GTK_SELECTION_NONE);
183
184         switch (analyse_query(sWord, query)) {
185         case qtFUZZY:
186             bFound = mStarDict->oLibs->LookupWithFuzzy(query.c_str());
187             break;
188
189         case qtPATTERN:
190             bFound = mStarDict->oLibs->LookupWithRule(query.c_str());
191             break;
192
193         case qtREGEX:
194             bFound = mStarDict->oLibs->LookupWithRegex(query.c_str());
195             break;
196
197         case qtSIMPLE:
198             bFound = mStarDict->oLibs->SimpleLookup(query.c_str(), mStarDict->oLibs->iCurrentIndex);
199             if (!bFound) {
200                 const gchar *sugWord = mStarDict->oLibs->GetSuggestWord(query.c_str(),
201                                                                         mStarDict->
202                                                                         oLibs->iCurrentIndex,
203                                                                         mStarDict->
204                                                                         oLibs->query_dictmask, 0);
205                 if (sugWord) {
206                     gchar *sSugWord = g_strdup(sugWord);
207                     bFound =
208                         mStarDict->oLibs->SimpleLookup(sSugWord, mStarDict->oLibs->iCurrentIndex);
209                     g_free(sSugWord);
210                 }
211             }
212             mStarDict->oLibs->ListWords(mStarDict->oLibs->iCurrentIndex);
213             break;
214
215         default:
216             break;
217         }
218
219         if (bFound)
220             mStarDict->ShowNoResults(false);
221         else
222             mStarDict->ShowNoResults(true);
223
224         mStarDict->ResultsUnselectAll(GTK_SELECTION_SINGLE);
225         mStarDict->ShowProgressIndicator(false);
226     }
227
228     return true;
229 }
230
231 gboolean
232 MStarDict::onSearchClearClicked(GtkButton* button,
233                                 MStarDict* mStarDict)
234 {
235     gtk_entry_set_text(GTK_ENTRY(mStarDict->search_entry), "");
236     mStarDict->GrabFocus();
237     return true;
238 }
239
240 gboolean
241 MStarDict::onDictionariesMenuItemClicked(GtkButton *button,
242                                          MStarDict *mStarDict)
243 {
244     mStarDict->oDict->CreateDictMngrDialog();
245
246     /* trigger re-search */
247     mStarDict->onSearchEntryChanged(GTK_EDITABLE(mStarDict->search_entry), mStarDict);
248     mStarDict->GrabFocus();
249     return true;
250 }
251
252 gboolean
253 MStarDict::onPreferenciesMenuItemClicked(GtkButton *button,
254                                          MStarDict *mStarDict)
255 {
256     mStarDict->oPrefs->CreatePrefsDialog();
257     return true;
258 }
259
260 gboolean
261 MStarDict::onQuitMenuItemClicked(GtkButton *button,
262                                  MStarDict *mStarDict)
263 {
264     gtk_main_quit();
265     return true;
266 }
267
268 gboolean
269 MStarDict::onLookupProgressDialogResponse(GtkDialog *dialog,
270                                           gint response_id,
271                                           bool *cancel)
272 {
273     *cancel = true;
274     return true;
275 }
276
277 gboolean
278 MStarDict::onMainWindowKeyPressEvent(GtkWidget *window,
279                                      GdkEventKey *event,
280                                      MStarDict *mStarDict)
281 {
282     if (event->type == GDK_KEY_PRESS && event->keyval == GDK_KP_Enter) {
283         mStarDict->SearchWord();
284     } else if (event->type == GDK_KEY_PRESS && event->keyval >= 0x21 && event->keyval <= 0x7E) {
285         mStarDict->GrabFocus();
286     }
287     return false;
288 }
289
290 GtkWidget *
291 MStarDict::CreateLookupProgressDialog(bool *cancel)
292 {
293     GtkWidget *dialog, *progress;
294
295     /* create dialog */
296     dialog = gtk_dialog_new();
297     gtk_window_set_title(GTK_WINDOW(dialog), _("Searching"));
298     gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(window));
299     gtk_dialog_add_button(GTK_DIALOG(dialog), _("Cancel"), GTK_RESPONSE_OK);
300
301     g_signal_connect(dialog, "response", G_CALLBACK(onLookupProgressDialogResponse), cancel);
302
303     /* add progress bar */
304     progress = gtk_progress_bar_new();
305     gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), progress);
306     g_object_set_data(G_OBJECT(dialog), "progress_bar", progress);
307
308     /* show dialog */
309     gtk_widget_show_all(dialog);
310
311     while (gtk_events_pending())
312         gtk_main_iteration();
313
314     return dialog;
315 }
316
317 void
318 MStarDict::DestroyLookupProgressDialog(GtkWidget *dialog)
319 {
320     gtk_widget_destroy(GTK_WIDGET(dialog));
321 }
322
323 void
324 MStarDict::CreateMainWindow()
325 {
326     HildonProgram *program = NULL;
327     GtkWidget *alignment, *main_vbox, *search;
328     GtkCellRenderer *renderer;
329     GtkTreeSelection *selection;
330
331     /* hildon program */
332     program = hildon_program_get_instance();
333     g_set_application_name(_("MStardict"));
334
335     /* main window */
336     window = hildon_stackable_window_new();
337     hildon_program_add_window(program, HILDON_WINDOW(window));
338
339     /* aligment */
340     alignment = gtk_alignment_new(0.5, 0.5, 1.0, 1.0);
341     gtk_alignment_set_padding(GTK_ALIGNMENT(alignment),
342                               HILDON_MARGIN_HALF, 0, HILDON_MARGIN_DEFAULT, HILDON_MARGIN_DEFAULT);
343     gtk_container_add(GTK_CONTAINER(window), alignment);
344
345     /* main vbox */
346     main_vbox = gtk_vbox_new(FALSE, 0);
347     gtk_container_add(GTK_CONTAINER(alignment), main_vbox);
348
349     /* no_search_result label */
350     label_widget = gtk_label_new(_("No search result"));
351     hildon_helper_set_logical_color(label_widget, GTK_RC_FG,
352                                     GTK_STATE_NORMAL, "SecondaryTextColor");
353     hildon_helper_set_logical_font(label_widget, "LargeSystemFont");
354     gtk_box_pack_start(GTK_BOX(main_vbox), label_widget, TRUE, TRUE, 0);
355
356     /* alignment for pannable area */
357     results_widget = gtk_alignment_new(0.5, 0.5, 1.0, 1.0);
358     gtk_alignment_set_padding(GTK_ALIGNMENT(results_widget),
359                               0, 0, HILDON_MARGIN_DEFAULT, HILDON_MARGIN_DEFAULT);
360     gtk_box_pack_start(GTK_BOX(main_vbox), results_widget, TRUE, TRUE, 0);
361
362     /* pannable for tree view */
363     results_view_scroll = hildon_pannable_area_new();
364     gtk_container_add(GTK_CONTAINER(results_widget), results_view_scroll);
365
366     /* result tree view */
367     results_view = hildon_gtk_tree_view_new(HILDON_UI_MODE_EDIT);
368     gtk_tree_view_set_model(GTK_TREE_VIEW(results_view), GTK_TREE_MODEL(results_list));
369     gtk_container_add(GTK_CONTAINER(results_view_scroll), results_view);
370
371     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(results_view));
372     g_signal_connect(selection, "changed", G_CALLBACK(onResultsViewSelectionChanged), this);
373
374     /* def column */
375     renderer = gtk_cell_renderer_text_new();
376     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW
377                                                 (results_view), -1, "Def",
378                                                 renderer, "text", DEF_COLUMN, NULL);
379     g_object_set(G_OBJECT(renderer),
380                  "xpad", 10,
381                  "ellipsize", PANGO_ELLIPSIZE_END,
382                  "ellipsize-set", TRUE,
383                  NULL);
384
385     /* create search bar */
386     search = CreateSearchBar();
387     gtk_box_pack_end(GTK_BOX(main_vbox), search, FALSE, TRUE, 0);
388
389     /* window signals */
390     g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
391     g_signal_connect(G_OBJECT(window), "key_press_event", G_CALLBACK(onMainWindowKeyPressEvent), this);
392
393     /* show all widget instead of alignment */
394     gtk_widget_show_all(GTK_WIDGET(window));
395
396     /* grab focus to search entry */
397     GrabFocus();
398 }
399
400 GtkWidget *
401 MStarDict::GetMainWindow()
402 {
403     return window;
404 }
405
406 GtkWidget *
407 MStarDict::CreateSearchBar()
408 {
409     GtkWidget *hbox, *entry, *button;
410     GtkEntryCompletion *completion;
411
412     /* search hbox */
413     hbox = gtk_hbox_new(FALSE, HILDON_MARGIN_DEFAULT);
414
415     /* search entry */
416     entry = hildon_entry_new(HILDON_SIZE_FINGER_HEIGHT);
417     hildon_gtk_entry_set_input_mode(GTK_ENTRY(entry), HILDON_GTK_INPUT_MODE_FULL);
418     gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
419
420     completion = gtk_entry_completion_new();
421     gtk_entry_completion_set_inline_completion(completion, TRUE);
422     gtk_entry_completion_set_popup_completion(completion, FALSE);
423     gtk_entry_set_completion(GTK_ENTRY(entry), completion);
424
425     /* clear button */
426     button = GTK_WIDGET(gtk_tool_button_new(gtk_image_new_from_icon_name("general_delete",
427                                                                          (GtkIconSize)HILDON_ICON_PIXEL_SIZE_FINGER),
428                                             "Clear"));
429     gtk_box_pack_end(GTK_BOX (hbox), button, FALSE, TRUE, 0);
430
431     /* search signals */
432     g_signal_connect(entry, "changed", G_CALLBACK(onSearchEntryChanged), this);
433     g_signal_connect(button, "clicked", G_CALLBACK(onSearchClearClicked), this);
434
435     search_entry = entry;
436     return hbox;
437 }
438
439
440 void
441 MStarDict::CreateMainMenu()
442 {
443     HildonAppMenu *menu;
444     GtkWidget *item;
445
446     menu = HILDON_APP_MENU(hildon_app_menu_new());
447     hildon_window_set_app_menu(HILDON_WINDOW(window), menu);
448
449     /* dictionaries menu item */
450     item = hildon_gtk_button_new(HILDON_SIZE_AUTO);
451     gtk_button_set_label(GTK_BUTTON(item), _("Dictionaries"));
452     hildon_app_menu_append(menu, GTK_BUTTON(item));
453     g_signal_connect(item, "clicked", G_CALLBACK(onDictionariesMenuItemClicked), this);
454
455     /* preferencies menu item */
456     item = hildon_gtk_button_new(HILDON_SIZE_AUTO);
457     gtk_button_set_label(GTK_BUTTON(item), _("Preferencies"));
458     hildon_app_menu_append(menu, GTK_BUTTON(item));
459     g_signal_connect(item, "clicked", G_CALLBACK(onPreferenciesMenuItemClicked), this);
460
461     /* quit menu item */
462     item = hildon_gtk_button_new(HILDON_SIZE_AUTO);
463     gtk_button_set_label(GTK_BUTTON(item), _("Quit"));
464     hildon_app_menu_append(menu, GTK_BUTTON(item));
465     g_signal_connect(item, "clicked", G_CALLBACK(onQuitMenuItemClicked), this);
466
467     /* show main menu */
468     gtk_widget_show_all(GTK_WIDGET(menu));
469 }
470
471 void
472 MStarDict::SearchWord()
473 {
474     const gchar *sWord;
475     bool bFound = false;
476     std::string query;
477
478     if (oLibs->query_dictmask.empty())
479         return;
480
481     sWord = gtk_entry_get_text(GTK_ENTRY(search_entry));
482     if (strcmp(sWord, "") == 0) {
483         ShowNoResults(true);
484     } else {
485         /* unselect rows */
486         ResultsUnselectAll(GTK_SELECTION_NONE);
487
488         switch (analyse_query(sWord, query)) {
489         case qtDATA:
490             bFound = oLibs->LookupData(query.c_str());
491
492             if (bFound)
493                 ShowNoResults(false);
494             else
495                 ShowNoResults(true);
496             break;
497         default:
498             /* nothing */ ;
499         }
500
501         /* unselect selected rows */
502         ResultsUnselectAll(GTK_SELECTION_SINGLE);
503     }
504 }
505
506 void
507 MStarDict::ResultsListClear()
508 {
509     gtk_list_store_clear(results_list);
510 }
511
512 void
513 MStarDict::ResultsListInsertLast(const gchar *word)
514 {
515     GtkTreeIter iter;
516     gtk_list_store_append(results_list, &iter);
517     gtk_list_store_set(results_list, &iter, DEF_COLUMN, word, -1);
518 }
519
520 void
521 MStarDict::ResultsReScroll()
522 {
523     hildon_pannable_area_scroll_to(HILDON_PANNABLE_AREA(results_view_scroll), -1, 0);
524 }
525
526 void
527 MStarDict::ResultsUnselectAll(GtkSelectionMode mode)
528 {
529     GtkTreeSelection *selection;
530
531     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(results_view));
532     gtk_tree_selection_set_mode(selection, mode);
533     gtk_tree_selection_unselect_all(selection);
534 }
535
536 void
537 MStarDict::ShowNoResults(bool bNoResults)
538 {
539     if (bNoResults) {
540         gtk_label_set_text(GTK_LABEL(label_widget), _("No search result"));
541         gtk_widget_show(label_widget);
542         gtk_widget_hide(results_widget);
543     } else {
544         gtk_widget_hide(label_widget);
545         gtk_widget_show(results_widget);
546     }
547 }
548
549 void
550 MStarDict::ShowNoDictionary(bool bNoDictionary)
551 {
552     if (bNoDictionary) {
553         gtk_label_set_text(GTK_LABEL(label_widget), _("No loaded dictionary"));
554         gtk_widget_show(label_widget);
555         gtk_widget_hide(results_widget);
556     } else {
557         gtk_widget_hide(label_widget);
558         gtk_widget_show(results_widget);
559     }
560 }
561
562 void
563 MStarDict::ShowProgressIndicator(bool bShow)
564 {
565     if (bShow)
566         hildon_gtk_window_set_progress_indicator(GTK_WINDOW(window), 1);
567     else
568         hildon_gtk_window_set_progress_indicator(GTK_WINDOW(window), 0);
569 }
570
571 void
572 MStarDict::GrabFocus()
573 {
574     gtk_widget_grab_focus(GTK_WIDGET(search_entry));
575 }
576
577 int
578 main(int argc,
579      char **argv)
580 {
581     /* initialize hildon */
582     hildon_gtk_init(&argc, &argv);
583
584     /* initialize localization */
585     setlocale(LC_ALL, "");
586     bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
587     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
588     textdomain(GETTEXT_PACKAGE);
589
590     /* create main window */
591     MStarDict mStarDict;
592     pMStarDict = &mStarDict;
593     mStarDict.CreateMainWindow();
594     mStarDict.CreateMainMenu();
595     mStarDict.ShowNoResults(true);
596
597     /* load dictionaries */
598     mStarDict.oDict->LoadDictionaries();
599
600     gtk_main();
601     return 0;
602 }