1 /*
2 
3   Copyright (c) 2004-2013 uim Project https://github.com/uim/uim
4 
5   All rights reserved.
6 
7   Redistribution and use in source and binary forms, with or without
8   modification, are permitted provided that the following conditions
9   are met:
10 
11   1. Redistributions of source code must retain the above copyright
12      notice, this list of conditions and the following disclaimer.
13   2. Redistributions in binary form must reproduce the above copyright
14      notice, this list of conditions and the following disclaimer in the
15      documentation and/or other materials provided with the distribution.
16   3. Neither the name of authors nor the names of its contributors
17      may be used to endorse or promote products derived from this software
18      without specific prior written permission.
19 
20   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
21   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
24   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30   SUCH DAMAGE.
31 
32 */
33 
34 #include <config.h>
35 
36 #include <stdlib.h>
37 # include <gtk/gtk.h>
38 #if GTK_CHECK_VERSION(2, 90, 0)
39 # include <gdk/gdkkeysyms-compat.h>
40 #else
41 # include <gdk/gdkkeysyms.h>
42 #endif
43 
44 #include "gettext.h"
45 
46 #include "word.h"
47 #include "anthy.h"
48 #include "word-list-view-gtk.h"
49 #include "word-list-win-gtk.h"
50 #include "word-win-gtk.h"
51 
52 static void word_list_window_class_init    (WordListWindowClass *window);
53 static void word_list_window_init          (WordListWindow *window);
54 static void word_list_window_dispose       (GObject        *object);
55 static void word_list_window_set_sensitive (WordListWindow *window);
56 
57 /* call back functions for ui manager */
58 static void add_widget_cb               (GtkUIManager   *merge,
59 					 GtkWidget      *widget,
60 					 GtkBox         *box);
61 
62 /* call back functions for actions */
63 static void file_exit_action_cb         (GtkAction      *action);
64 static void edit_add_word_action_cb     (GtkAction      *action,
65 					 WordListWindow *window);
66 static void edit_remove_word_action_cb  (GtkAction      *action,
67 					 WordListWindow *window);
68 static void edit_edit_word_action_cb    (GtkAction      *action,
69 					 WordListWindow *window);
70 static void popup_menu_action_cb        (GtkAction      *action,
71 					 WordListWindow *window);
72 static void help_about_action_cb        (GtkAction      *action,
73 					 WordListWindow *window);
74 static void activate_radio_action(GtkAction *action, GtkRadioAction *current,
75 				  gpointer data);
76 
77 /* call back functions for WordListView */
78 static gboolean word_list_button_press_cb  (GtkWidget      *widget,
79 					    GdkEventButton *event,
80 					    WordListWindow *window);
81 static gboolean word_list_row_activated_cb(GtkWidget *widget,
82 					   GtkTreePath *path,
83 					   GtkTreeViewColumn *column,
84 					   WordListWindow *window);
85 static gboolean word_list_key_press_cb     (GtkWidget      *widget,
86 					    GdkEventKey    *event,
87 					    WordListWindow *window);
88 static void word_list_selection_changed_cb (GtkTreeSelection *selection,
89 					    WordListWindow *window);
90 
91 /* call back functions for WordWindow */
92 static void wordwin_response_cb            (WordWindow     *dialog,
93 					    WordListWindow *window);
94 
95 static void dict_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
96 static void dict_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
97 
98 GtkWindowClass *parent_class = NULL;
99 GdkEventButton *current_button_event = NULL;
100 
101 /* Main menu*/
102 GtkActionEntry menu_action_entries[] = {
103     { "DictionaryMenu", NULL, N_("_Dictionary") },
104     { "SelectMenu", NULL, N_("_Select") },
105     { "EditMenu",   NULL, N_("_Edit")   },
106     { "OptionMenu", NULL, N_("_Option") },
107     { "HelpMenu",   NULL, N_("_Help")   },
108     { "Quit",       GTK_STOCK_QUIT,   N_("_Quit"),       "<control>Q",
109       N_("Quit uim-dict"),            G_CALLBACK(file_exit_action_cb) },
110     { "AddWord",    GTK_STOCK_ADD,    N_("A_dd..."),     "<control>A",
111       N_("Add a new word"),           G_CALLBACK(edit_add_word_action_cb) },
112     { "RemoveWord", GTK_STOCK_REMOVE, N_("_Remove..."),  "<control>D",
113       N_("Remove the selected word"), G_CALLBACK(edit_remove_word_action_cb) },
114     { "EditWord",   GTK_STOCK_DND,    N_("_Edit..."),    "<control>E",
115       N_("Edit the selected word"),   G_CALLBACK(edit_edit_word_action_cb) },
116     { "PopupMenu",  NULL,             N_("_Popup Menu"), NULL,
117       N_("Show popup menu"),          G_CALLBACK(popup_menu_action_cb) },
118     { "About",      NULL,             N_("_About"),      NULL,
119       N_("About uim-dict"),           G_CALLBACK(help_about_action_cb) },
120 };
121 static guint n_menu_action_entries = G_N_ELEMENTS(menu_action_entries);
122 
123 static GtkRadioActionEntry dictionary_entries[] = {
124   { "Anthy", NULL,
125     "_Anthy", NULL,
126     "Anthy private dictionary", DICT_ENUM_DICTIONARY_TYPE_ANTHY },
127   { "Canna", NULL,
128     "_Canna", NULL,
129     "Canna private dictionary", DICT_ENUM_DICTIONARY_TYPE_CANNA },
130 };
131 static guint n_dictionary_entries = G_N_ELEMENTS(dictionary_entries);
132 
133 #define ACTIVATE_ACTION(window, action_name)				       \
134 {									       \
135   GtkAction *action;							       \
136   action = gtk_action_group_get_action((window)->action_group, (action_name)); \
137   if (action) {								       \
138     gtk_action_activate(action);					       \
139   }									       \
140 }
141 
142 #define SET_ACTION_SENSITIVE(window, action_name, sensitive)		       \
143 {									       \
144   GtkAction *action;							       \
145   action = gtk_action_group_get_action((window)->action_group, (action_name)); \
146   if (action) {								       \
147     g_object_set(action,						       \
148 		 "sensitive", (sensitive),				       \
149 		 NULL);							       \
150   }									       \
151 }
152 
word_list_window_get_type(void)153 GType word_list_window_get_type(void) {
154   static GType type = 0;
155 
156   if (type == 0) {
157     static const GTypeInfo info = {
158       sizeof(WordListWindowClass),
159       NULL, /* base_init */
160       NULL, /* base_finalize */
161       (GClassInitFunc)word_list_window_class_init,
162       NULL, /* class_finalize */
163       NULL, /* class_data */
164       sizeof(WordWindow),
165       0, /* n_preallocs */
166       (GInstanceInitFunc)word_list_window_init /* instance_init */
167     };
168     type = g_type_register_static(GTK_TYPE_WINDOW,
169 				  "WordListWindow", &info, 0);
170   }
171   return type;
172 }
173 
174 GType
dict_enum_dictionary_type_get_type(void)175 dict_enum_dictionary_type_get_type(void)
176 {
177   static GType etype = 0;
178   if (etype == 0) {
179     static const GEnumValue values[] = {
180       { DICT_ENUM_DICTIONARY_TYPE_ANTHY, "DICT_ENUM_DICTIONARY_TYPE_ANTHY", "anthy" },
181       { DICT_ENUM_DICTIONARY_TYPE_CANNA, "DICT_ENUM_DICTIONARY_TYPE_CANNA", "canna" },
182       { DICT_ENUM_DICTIONARY_TYPE_SKK, "DICT_ENUM_DICTIONARY_TYPE_SKK", "skk" },
183       { DICT_ENUM_DICTIONARY_TYPE_PRIME, "DICT_ENUM_DICTIONARY_TYPE_PRIME", "prime" },
184       { DICT_ENUM_DICTIONARY_TYPE_UNKOWN, "DICT_ENUM_DICTIONARY_TYPE_UNKOWN", "unknown" },
185       { 0, NULL, NULL }
186     };
187     etype = g_enum_register_static("DictEnumDictionaryType", values);
188   }
189   return etype;
190 }
191 
192 static void
word_list_window_class_init(WordListWindowClass * klass)193 word_list_window_class_init (WordListWindowClass *klass)
194 {
195   GObjectClass *object_class;
196 
197   parent_class = g_type_class_peek_parent(klass);
198   object_class = (GObjectClass *) klass;
199 
200   object_class->dispose = word_list_window_dispose;
201 
202   object_class->get_property = dict_get_property;
203   object_class->set_property = dict_set_property;
204 
205   g_object_class_install_property(object_class,
206   				  PROP_DICTIONARY_TYPE,
207 				  g_param_spec_enum("dictionary-type",
208 				  		    _("dictionary type"),
209 						    _("dictionary type"),
210 						    DICT_TYPE_ENUM_DICTIONARY_TYPE,
211 						    DICT_ENUM_DICTIONARY_TYPE_ANTHY,
212 						    G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
213 }
214 
215 static gchar *
translate_func(const gchar * path,gpointer data)216 translate_func(const gchar *path, gpointer data)
217 {
218   return _(path);
219 }
220 
221 static void
warn_dict_open()222 warn_dict_open()
223 {
224   GtkWidget *dialog;
225   const gchar *message;
226 
227   message = N_("Couldn't open the dictionary.\n");
228   dialog = gtk_message_dialog_new(NULL,
229 		  		  GTK_DIALOG_MODAL,
230 				  GTK_MESSAGE_WARNING,
231 				  GTK_BUTTONS_OK,
232 				  "%s", _(message));
233   gtk_dialog_run(GTK_DIALOG(dialog));
234   gtk_widget_destroy(GTK_WIDGET(dialog));
235 }
236 
237 static void
word_list_window_init(WordListWindow * window)238 word_list_window_init (WordListWindow *window)
239 {
240   GtkWidget *word_list, *vbox, *statusbar;
241   GtkUIManager *ui;
242   GtkActionGroup *actions;
243 
244   gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
245   gtk_window_set_default_size(GTK_WINDOW(window), 600, 450);
246   gtk_window_set_title(GTK_WINDOW(window), _("Edit the dictionary"));
247 
248 #if GTK_CHECK_VERSION(3, 2, 0)
249   vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
250 #else
251   vbox = gtk_vbox_new(FALSE, 0);
252 #endif
253   gtk_container_add(GTK_CONTAINER(window), vbox);
254   gtk_widget_show(vbox);
255 
256   window->action_group = actions = gtk_action_group_new("Actions");
257 #if ENABLE_NLS
258   gtk_action_group_set_translate_func(window->action_group,
259 				      translate_func, NULL, NULL);
260 #endif
261   gtk_action_group_add_actions(actions, menu_action_entries,
262 			       n_menu_action_entries, window);
263 
264   gtk_action_group_add_radio_actions(actions, dictionary_entries,
265 				     n_dictionary_entries,
266 				     DICT_ENUM_DICTIONARY_TYPE_ANTHY,
267 				     G_CALLBACK(activate_radio_action),
268 				     window);
269 
270   window->ui_manager = ui = gtk_ui_manager_new();
271   gtk_ui_manager_insert_action_group(ui, actions, 0);
272   g_signal_connect(ui, "add_widget",
273 		   G_CALLBACK(add_widget_cb),
274 		   vbox);
275   gtk_window_add_accel_group(GTK_WINDOW(window),
276 			     gtk_ui_manager_get_accel_group(ui));
277 
278   gtk_ui_manager_add_ui_from_file(ui,
279 				  UIM_DATADIR "/helperdata/uim-dict-ui.xml",
280 				  NULL);
281   gtk_ui_manager_ensure_update(ui);
282 
283   window->word_list = word_list = word_list_view_new();
284   word_list_view_set_visible_cclass_code_column(WORD_LIST_VIEW(word_list), TRUE);
285   word_list_view_set_visible_freq_column(WORD_LIST_VIEW(word_list), TRUE);
286   gtk_widget_show(word_list);
287   gtk_box_pack_start(GTK_BOX(vbox), word_list, TRUE, TRUE, 0);
288 
289   g_signal_connect(G_OBJECT(gtk_bin_get_child(GTK_BIN(window->word_list))),
290 		   "button-press-event",
291 		   G_CALLBACK(word_list_button_press_cb), window);
292   g_signal_connect(G_OBJECT(gtk_bin_get_child(GTK_BIN(window->word_list))),
293 		   "row-activated",
294 		   G_CALLBACK(word_list_row_activated_cb), window);
295   g_signal_connect(G_OBJECT(gtk_bin_get_child(GTK_BIN(window->word_list))),
296 		   "key-press-event",
297 		   G_CALLBACK(word_list_key_press_cb), window);
298   g_signal_connect(G_OBJECT(WORD_LIST_VIEW(window->word_list)->selection),
299 		   "changed",
300 		   G_CALLBACK(word_list_selection_changed_cb), window);
301 
302   window->statusbar = statusbar = gtk_statusbar_new();
303   gtk_box_pack_start(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0);
304   gtk_widget_show(statusbar);
305 
306   word_list_window_set_sensitive(window);
307 }
308 
309 static void
word_list_window_dispose(GObject * object)310 word_list_window_dispose(GObject *object)
311 {
312   WordListWindow *window = WORD_LIST_WINDOW(object);
313 
314   if (window->action_group) {
315     g_object_unref(window->action_group);
316     window->action_group = NULL;
317   }
318 
319   if (window->ui_manager) {
320     g_object_unref(window->ui_manager);
321     window->ui_manager = NULL;
322   }
323 
324   if (G_OBJECT_CLASS(parent_class)->dispose)
325     G_OBJECT_CLASS(parent_class)->dispose(object);
326 }
327 
328 static void
dict_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)329 dict_get_property(GObject *object, guint prop_id, GValue *value,
330 		  GParamSpec *pspec)
331 {
332   switch (prop_id) {
333   case PROP_DICTIONARY_TYPE:
334     g_value_set_enum(value, dict_get_dictionary_type(GTK_WIDGET(object)));
335     break;
336   default:
337     break;
338   }
339 }
340 
341 static void
dict_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)342 dict_set_property(GObject *object, guint prop_id, const GValue *value,
343 		  GParamSpec *pspec)
344 {
345   WordListWindow *window = WORD_LIST_WINDOW(object);
346   uim_dict *dict = NULL;
347   gchar message[128];
348 
349   switch (prop_id) {
350   case PROP_DICTIONARY_TYPE:
351     window->dictionary_type = g_value_get_enum(value);
352 
353     ACTIVATE_ACTION(window, dictionary_entries[window->dictionary_type].name);
354 
355     switch (window->dictionary_type) {
356     case DICT_ENUM_DICTIONARY_TYPE_ANTHY:
357       dict = uim_dict_open(N_("Anthy private dictionary"));
358       break;
359     case DICT_ENUM_DICTIONARY_TYPE_CANNA:
360       word_list_view_set_visible_freq_column(WORD_LIST_VIEW(window->word_list), FALSE);
361       dict = uim_dict_open(N_("Canna private dictionary"));
362       break;
363     default:
364       break;
365     }
366     if (!dict) {
367       warn_dict_open();
368       break;
369     }
370     word_list_view_set_dict(WORD_LIST_VIEW(window->word_list), dict);
371 
372     g_snprintf(message, sizeof(message), _("%s"), _(dict->identifier));
373     gtk_statusbar_push(GTK_STATUSBAR(window->statusbar), 0, _(dict->identifier));
374     break;
375   default:
376     break;
377   }
378 }
379 
380 DictEnumDictionaryType
dict_get_dictionary_type(GtkWidget * window)381 dict_get_dictionary_type(GtkWidget *window)
382 {
383   WordListWindow *w = (WordListWindow *)window;
384 
385   return w->dictionary_type;
386 }
387 
word_list_window_new(int type)388 GtkWidget *word_list_window_new(int type)
389 {
390   return GTK_WIDGET(g_object_new(WORD_LIST_WINDOW_TYPE,
391 				 "dictionary-type", type, NULL));
392 }
393 
394 static void
word_list_window_set_sensitive(WordListWindow * window)395 word_list_window_set_sensitive(WordListWindow *window)
396 {
397   gboolean selected;
398   WordListView *word_list;
399   GtkTreeSelection *selection;
400 
401   word_list = WORD_LIST_VIEW(window->word_list);
402   selection = word_list->selection;
403 
404   selected = gtk_tree_selection_get_selected(selection, NULL, NULL);
405 
406   if (selected) {
407     SET_ACTION_SENSITIVE(window, "EditWord",   TRUE);
408     SET_ACTION_SENSITIVE(window, "RemoveWord", TRUE);
409   } else {
410     SET_ACTION_SENSITIVE(window, "EditWord",   FALSE);
411     SET_ACTION_SENSITIVE(window, "RemoveWord", FALSE);
412   }
413 }
414 
415 
416 /*
417  * call back functions for ui manager
418  */
419 static void
add_widget_cb(GtkUIManager * merge,GtkWidget * widget,GtkBox * box)420 add_widget_cb (GtkUIManager *merge, GtkWidget *widget, GtkBox *box)
421 {
422   gtk_box_pack_start (box, widget, FALSE, FALSE, 0);
423 }
424 
425 
426 /*
427  *  call back functions for actions
428  */
429 static void
file_exit_action_cb(GtkAction * action)430 file_exit_action_cb(GtkAction *action)
431 {
432   gtk_main_quit();
433 }
434 
435 static void
edit_add_word_action_cb(GtkAction * action,WordListWindow * window)436 edit_add_word_action_cb(GtkAction *action, WordListWindow *window)
437 {
438   GtkWidget *w;
439 
440   w = word_window_new(WORD_WINDOW_MODE_ADD,
441 		      WORD_LIST_VIEW(window->word_list)->dict);
442   gtk_grab_add(w);
443   gtk_window_set_transient_for(GTK_WINDOW(w), GTK_WINDOW(window));
444   gtk_window_set_position(GTK_WINDOW(w), GTK_WIN_POS_CENTER_ON_PARENT);
445   g_signal_connect(G_OBJECT(w), "word-added",
446 		   G_CALLBACK(wordwin_response_cb), window);
447   gtk_widget_show(w);
448 }
449 
450 static void
remove_confirm_dialog_response_cb(GtkDialog * dialog,gint arg,gboolean * ok)451 remove_confirm_dialog_response_cb(GtkDialog *dialog, gint arg,
452 				  gboolean *ok)
453 {
454   g_return_if_fail(ok);
455 
456   *ok = FALSE;
457 
458   switch (arg)
459   {
460   case GTK_RESPONSE_OK:
461     *ok = TRUE;
462     break;
463   default:
464     break;
465   }
466 }
467 
468 static void
edit_remove_word_action_cb(GtkAction * action,WordListWindow * window)469 edit_remove_word_action_cb(GtkAction *action, WordListWindow *window)
470 {
471   GtkWidget *dialog;
472   GList *node, *list;
473   gboolean ok = FALSE;
474   const gchar *message = _("Are you sure to remove seleted words?");
475 
476   list = word_list_view_get_selected_data_list(WORD_LIST_VIEW(window->word_list));
477   if (!list) return;
478 
479   if (!g_list_next(list))
480     message = _("Are you sure to remove the selected word?");
481 
482   dialog = gtk_message_dialog_new(NULL,
483 				  GTK_DIALOG_MODAL,
484 				  GTK_MESSAGE_QUESTION,
485 				  GTK_BUTTONS_OK_CANCEL,
486 				  "%s", message);
487   gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(window));
488   gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ON_PARENT);
489   g_signal_connect(G_OBJECT(dialog), "response",
490 		   G_CALLBACK(remove_confirm_dialog_response_cb), &ok);
491   gtk_dialog_run(GTK_DIALOG(dialog));
492   gtk_widget_destroy(dialog);
493   dialog = NULL;
494 
495   if (!ok) return;
496 
497   for (node = list; node; node = g_list_next(node)) {
498     uim_word *w = node->data;
499     int ret;
500 
501     ret = uim_dict_remove_word(WORD_LIST_VIEW(window->word_list)->dict, w);
502 
503     if (ret) {
504       word_list_view_refresh(WORD_LIST_VIEW(window->word_list));
505       dialog = gtk_message_dialog_new(NULL,
506 				      GTK_DIALOG_MODAL,
507 				      GTK_MESSAGE_INFO,
508 				      GTK_BUTTONS_CLOSE,
509 				      "%s", _("Word deletion succeeded."));
510     } else {
511       dialog = gtk_message_dialog_new(NULL,
512 				      GTK_DIALOG_MODAL,
513 				      GTK_MESSAGE_ERROR,
514 				      GTK_BUTTONS_CLOSE,
515 				      "%s", _("Word deletion failed."));
516     }
517     gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(window));
518     gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ON_PARENT);
519     gtk_dialog_run(GTK_DIALOG(dialog));
520     gtk_widget_destroy(dialog);
521   }
522   g_list_free(list);
523 }
524 
525 static void
edit_edit_word_action_cb(GtkAction * action,WordListWindow * window)526 edit_edit_word_action_cb(GtkAction *action, WordListWindow *window)
527 {
528   GList *list;
529 
530   list = word_list_view_get_selected_data_list(WORD_LIST_VIEW(window->word_list));
531 
532   /* FIXME! it can edit only one word yet. */
533   if (list) {
534     GtkWidget *widget;
535 
536     widget = word_window_new(WORD_WINDOW_MODE_EDIT,
537 			     WORD_LIST_VIEW(window->word_list)->dict);
538     gtk_grab_add(widget);
539     gtk_window_set_transient_for(GTK_WINDOW(widget), GTK_WINDOW(window));
540     gtk_window_set_position(GTK_WINDOW(widget), GTK_WIN_POS_CENTER_ON_PARENT);
541     word_window_set_word(WORD_WINDOW(widget), list->data);
542     g_signal_connect(G_OBJECT(widget), "word-added",
543     		     G_CALLBACK(wordwin_response_cb), window);
544 
545     gtk_widget_show(widget);
546   }
547   g_list_free(list);
548 }
549 
550 static void
popup_menu_action_cb(GtkAction * action,WordListWindow * window)551 popup_menu_action_cb(GtkAction *action, WordListWindow *window)
552 {
553   GtkWidget *popup_menu;
554 
555   popup_menu = gtk_ui_manager_get_widget(window->ui_manager,
556 					 "/WordListPopup");
557   g_return_if_fail(popup_menu);
558 
559   if (current_button_event) {
560     gtk_menu_popup(GTK_MENU(popup_menu),
561 		   NULL, NULL,
562 		   NULL, NULL,
563 		   current_button_event->button,
564 		   current_button_event->time);
565   } else {
566     gtk_menu_popup(GTK_MENU(popup_menu), NULL, NULL,
567 		   NULL, NULL, 0, GDK_CURRENT_TIME);
568   }
569 }
570 
571 #if GTK_CHECK_VERSION(2, 6, 0) && !GTK_CHECK_VERSION(2, 18, 0)
572 static void
activate_url(GtkAboutDialog * about,const gchar * link,gpointer data)573 activate_url(GtkAboutDialog *about, const gchar *link, gpointer data)
574 {
575   /* g_print("show url %s\n", link); */
576 }
577 #endif
578 
579 static void
help_about_action_cb(GtkAction * action,WordListWindow * window)580 help_about_action_cb(GtkAction *action, WordListWindow *window)
581 {
582   const gchar *name = N_("uim-dict");
583 #if GTK_CHECK_VERSION(2, 6, 0)
584   GdkPixbuf *pixbuf, *transparent;
585   const gchar *filename = UIM_PIXMAPSDIR "/uim-dict.png";
586   const gchar *authors[] = {
587     "Masahito Omote <omote@utyuuzin.net>",
588     "Takuro Ashie",
589     "Etsushi Kato",
590     NULL
591   };
592   const gchar *copyright = N_(
593     "Copyright (C) 2003-2004 Masahito Omote\n"
594     "Copyright (C) 2004-2013 uim Project\n"
595     "All rights reserved.");
596 
597   transparent = NULL;
598   pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
599   if (pixbuf) {
600     transparent = gdk_pixbuf_add_alpha(pixbuf, TRUE, 0xff, 0xff, 0xff);
601     g_object_unref(pixbuf);
602   }
603 
604 #if !GTK_CHECK_VERSION(2, 18, 0)
605   gtk_about_dialog_set_url_hook (activate_url, NULL, NULL);
606 #endif
607   gtk_show_about_dialog (GTK_WINDOW(window),
608 			 "name", name,
609 			 "version", VERSION,
610 			 "copyright", copyright,
611 			 "website", "https://github.com/uim/uim",
612 			 "authors", authors,
613 			 "logo", transparent,
614 			 NULL);
615   g_object_unref(transparent);
616 #else
617   GtkWidget *about_dialog, *label1;
618   const gchar *copyright = N_(
619     "Copyright 2003-2004 Masahito Omote &lt;omote@utyuuzin.net&gt;\n"
620     "Copyright 2004-2013 uim Project https://github.com/uim/uim\n"
621     "All rights reserved.");
622   gchar *about_name =
623     g_strdup_printf("<span size=\"20000\">%s %s </span>\n\n<span size=\"14000\">%s </span>\n", _(name), VERSION, _(copyright));
624 
625   about_dialog = gtk_dialog_new_with_buttons(_("About uim-dict"), NULL,
626 					     GTK_DIALOG_MODAL,
627 					     GTK_STOCK_OK,
628 					     GTK_RESPONSE_ACCEPT, NULL);
629   gtk_container_set_border_width(GTK_CONTAINER(about_dialog), 8);
630 
631   label1 = gtk_label_new(NULL);
632   gtk_widget_show(label1);
633   gtk_label_set_markup(GTK_LABEL(label1), about_name);
634   g_free(about_name);
635   gtk_box_pack_start(
636       GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(about_dialog))),
637       label1, FALSE, FALSE, 0);
638 
639   gtk_window_set_transient_for(GTK_WINDOW(about_dialog),
640 			       GTK_WINDOW(window));
641   gtk_window_set_position(GTK_WINDOW(about_dialog),
642 			  GTK_WIN_POS_CENTER_ON_PARENT);
643   gtk_dialog_run(GTK_DIALOG(about_dialog));
644 
645   gtk_widget_destroy(about_dialog);
646 #endif
647 }
648 
649 static void
activate_radio_action(GtkAction * action,GtkRadioAction * current,gpointer data)650 activate_radio_action(GtkAction *action, GtkRadioAction *current,
651 		      gpointer data)
652 {
653   WordListWindow *window;
654   gboolean active;
655   guint value;
656 
657   window = WORD_LIST_WINDOW(data);
658   active = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(current));
659   value = gtk_radio_action_get_current_value(GTK_RADIO_ACTION(current));
660 
661   if (active) {
662     if (value != window->dictionary_type) {
663       GtkWidget *newwin;
664 
665       newwin = word_list_window_new(value);
666 
667       /* quit */
668       if (WORD_LIST_VIEW(WORD_LIST_WINDOW(newwin)->word_list)->dict == NULL) {
669         gtk_main_quit();
670       }
671 
672       g_signal_handlers_disconnect_by_func(G_OBJECT(window),
673 					   (gpointer)(uintptr_t)dict_window_destroy_cb,
674 					   NULL);
675       gtk_widget_destroy(GTK_WIDGET(window));
676 
677       g_signal_connect(G_OBJECT(newwin), "destroy",
678 		       G_CALLBACK(dict_window_destroy_cb), NULL);
679       gtk_widget_show(newwin);
680     }
681   }
682 }
683 
684 /*
685  * call back functions for WordListView
686  */
687 static gboolean
word_list_button_press_cb(GtkWidget * widget,GdkEventButton * event,WordListWindow * window)688 word_list_button_press_cb(GtkWidget *widget, GdkEventButton *event,
689 			  WordListWindow *window)
690 {
691   if (event->button == 2 && event->type == GDK_BUTTON_PRESS) {
692     ACTIVATE_ACTION(window, "EditWord");
693   } else if (event->button == 3) {
694     current_button_event = event;
695     ACTIVATE_ACTION(window, "PopupMenu");
696     current_button_event = NULL;
697   }
698 
699   return FALSE;
700 }
701 
702 static gboolean
word_list_row_activated_cb(GtkWidget * widget,GtkTreePath * path,GtkTreeViewColumn * column,WordListWindow * window)703 word_list_row_activated_cb(GtkWidget *widget, GtkTreePath *path,
704 			   GtkTreeViewColumn *column, WordListWindow *window)
705 {
706     ACTIVATE_ACTION(window, "EditWord");
707 
708     return FALSE;
709 }
710 
711 static gboolean
word_list_key_press_cb(GtkWidget * widget,GdkEventKey * event,WordListWindow * window)712 word_list_key_press_cb(GtkWidget *widget, GdkEventKey *event,
713 		       WordListWindow *window)
714 {
715   switch (event->keyval) {
716   case GDK_Delete:
717   case GDK_BackSpace:
718     ACTIVATE_ACTION(window, "RemoveWord");
719     break;
720   default:
721     break;
722   }
723 
724   return FALSE;
725 }
726 
727 static void
word_list_selection_changed_cb(GtkTreeSelection * selection,WordListWindow * window)728 word_list_selection_changed_cb(GtkTreeSelection *selection,
729 			       WordListWindow *window)
730 {
731   word_list_window_set_sensitive(window);
732 }
733 
734 
735 /*
736  * call back functions for WordWindow
737  */
738 static void
wordwin_response_cb(WordWindow * dialog,WordListWindow * window)739 wordwin_response_cb(WordWindow *dialog, WordListWindow *window)
740 {
741   word_list_view_refresh(WORD_LIST_VIEW(window->word_list));
742 }
743