Tizen 2.1 base
[framework/uifw/ise-engine-anthy.git] / src / scim_anthy_setup.cpp
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  *  Copyright (C) 2004 Hiroyuki Ikezoe
4  *  Copyright (C) 2004-2005 Takuro Ashie
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2, or (at your option)
9  *  any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  */
20
21 /*
22  * Based on scim-hangul.
23  * Copyright (c) 2004 James Su <suzhe@turbolinux.com.cn>
24  */
25
26 #ifdef HAVE_CONFIG_H
27   #include <config.h>
28 #endif
29
30 #include <string.h>
31 #include <gtk/gtk.h>
32 #include <gdk/gdkkeysyms.h>
33
34 #define Uses_SCIM_CONFIG_BASE
35 #define Uses_SCIM_EVENT
36 #define SCIM_ANTHY_USE_GTK
37 #include <scim.h>
38 #include <gtk/scimkeyselection.h>
39 #include "scim_anthy_intl.h"
40 #include "scim_anthy_style_file.h"
41 #include "scim_anthy_prefs.h"
42 #include "scim_anthy_default_tables.h"
43 #include "scim_anthy_setup.h"
44 #include "scim_anthy_setup_romaji.h"
45 #include "scim_anthy_setup_kana.h"
46 #include "scim_anthy_utils.h"
47 #include "scim_anthy_color_button.h"
48
49 using namespace scim;
50 using namespace scim_anthy;
51
52 #define scim_module_init anthy_imengine_setup_LTX_scim_module_init
53 #define scim_module_exit anthy_imengine_setup_LTX_scim_module_exit
54
55 #define scim_setup_module_create_ui       anthy_imengine_setup_LTX_scim_setup_module_create_ui
56 #define scim_setup_module_get_category    anthy_imengine_setup_LTX_scim_setup_module_get_category
57 #define scim_setup_module_get_name        anthy_imengine_setup_LTX_scim_setup_module_get_name
58 #define scim_setup_module_get_description anthy_imengine_setup_LTX_scim_setup_module_get_description
59 #define scim_setup_module_load_config     anthy_imengine_setup_LTX_scim_setup_module_load_config
60 #define scim_setup_module_save_config     anthy_imengine_setup_LTX_scim_setup_module_save_config
61 #define scim_setup_module_query_changed   anthy_imengine_setup_LTX_scim_setup_module_query_changed
62
63 #define DATA_POINTER_KEY "scim-anthy::ConfigPointer"
64 #define INDEX_KEY        "scim-anthy::Index"
65
66 namespace scim_anthy {
67
68 static GtkWidget * create_setup_window (void);
69 static void        load_style_files    (const char *dirname);
70 static void        load_config         (const ConfigPointer &config);
71 static void        save_config         (const ConfigPointer &config);
72 static bool        query_changed       (void);
73
74 //static StyleFiles __style_list;
75 //static StyleFile  __user_style_file;
76 StyleFiles __style_list;
77 StyleFile  __user_style_file;
78 const String __user_config_dir_name =
79     scim_get_home_dir () +
80     String (SCIM_PATH_DELIM_STRING
81             ".scim"
82             SCIM_PATH_DELIM_STRING
83             "Anthy");
84 const String __user_style_dir_name =
85     __user_config_dir_name +
86     String (SCIM_PATH_DELIM_STRING
87             "style");
88 const String __user_style_file_name =
89     __user_config_dir_name +
90     String (SCIM_PATH_DELIM_STRING
91             "config.sty");
92
93 }
94
95 // Module Interface.
96 extern "C" {
97     void scim_module_init (void)
98     {
99         bindtextdomain (GETTEXT_PACKAGE, SCIM_ANTHY_LOCALEDIR);
100         bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
101     }
102
103     void scim_module_exit (void)
104     {
105     }
106
107     GtkWidget * scim_setup_module_create_ui (void)
108     {
109         return create_setup_window ();
110     }
111
112     String scim_setup_module_get_category (void)
113     {
114         return String ("IMEngine");
115     }
116
117     String scim_setup_module_get_name (void)
118     {
119         return String (_("Anthy"));
120     }
121
122     String scim_setup_module_get_description (void)
123     {
124         return String (_("An Anthy IMEngine Module."));
125     }
126
127     void scim_setup_module_load_config (const ConfigPointer &config)
128     {
129         load_config (config);
130     }
131
132     void scim_setup_module_save_config (const ConfigPointer &config)
133     {
134         save_config (config);
135     }
136
137     bool scim_setup_module_query_changed ()
138     {
139         return query_changed ();
140     }
141 } // extern "C"
142
143
144
145 namespace scim_anthy {
146
147 // Internal data structure
148 struct KeyboardConfigPage
149 {
150     const char       *label;
151     StringConfigData *data;
152 };
153
154 struct ComboConfigCandidate
155 {
156     const char *label;
157     const char *data;
158 };
159
160 enum {
161     COLUMN_LABEL = 0,
162     COLUMN_VALUE = 1,
163     COLUMN_DESC  = 2,
164     COLUMN_DATA  = 3,
165     N_COLUMNS    = 4,
166 };
167
168 // Internal data declaration.
169 bool __config_changed = false;
170 bool __style_changed  = false;
171 static GtkWidget   * __widget_key_categories_menu   = NULL;
172 static GtkWidget   * __widget_key_filter            = NULL;
173 static GtkWidget   * __widget_key_filter_button     = NULL;
174 static GtkWidget   * __widget_key_theme_menu        = NULL;
175 static GtkWidget   * __widget_key_list_view         = NULL;
176 static GtkWidget   * __widget_choose_keys_button    = NULL;
177 static GtkTooltips * __widget_tooltips              = NULL;
178
179 static String __config_key_theme      = SCIM_ANTHY_CONFIG_KEY_THEME_DEFAULT;
180 static String __config_key_theme_file = SCIM_ANTHY_CONFIG_KEY_THEME_FILE_DEFAULT;
181
182 static struct KeyboardConfigPage __key_conf_pages[] =
183 {
184     {N_("Mode keys"),          config_keyboards_mode},
185     {N_("Edit keys"),          config_keyboards_edit},
186     {N_("Caret keys"),         config_keyboards_caret},
187     {N_("Segments keys"),      config_keyboards_segments},
188     {N_("Candidates keys"),    config_keyboards_candidates},
189     {N_("Direct select keys"), config_keyboards_direct_select},
190     {N_("Convert keys"),       config_keyboards_converting},
191     {N_("Dictionary keys"),    config_keyboards_dict},
192 };
193 static unsigned int __key_conf_pages_num = sizeof (__key_conf_pages) / sizeof (KeyboardConfigPage);
194
195 const int KEY_CATEGORY_INDEX_SEARCH_BY_KEY = __key_conf_pages_num;
196 const int KEY_CATEGORY_INDEX_ALL           = __key_conf_pages_num + 1;
197
198 const int KEY_THEME_INDEX_USER_DEFINED = 0;
199 const int KEY_THEME_INDEX_DEFAULT      = 1;
200
201 static ComboConfigCandidate input_modes[] =
202 {
203     {N_("Hiragana"),            "Hiragana"},
204     {N_("Katakana"),            "Katakana"},
205     {N_("Half width katakana"), "HalfKatakana"},
206     {N_("Latin"),               "Latin"},
207     {N_("Wide latin"),          "WideLatin"},
208     {NULL, NULL},
209 };
210
211 static ComboConfigCandidate typing_methods[] =
212 {
213     {N_("Romaji typing method"),      "Romaji"},
214     {N_("Kana typing method"),        "Kana"},
215     {N_("Thumb shift typing method"), "NICOLA"},
216     {NULL, NULL},
217 };
218
219 static ComboConfigCandidate conversion_modes[] =
220 {
221     {N_("Multi segment"),                        "MultiSeg"},
222     {N_("Single segment"),                       "SingleSeg"},
223     {N_("Convert as you type (Multi segment)"),  "CAYT_MultiSeg"},
224     {N_("Convert as you type (Single segment)"), "CAYT_SingleSeg"},
225     {NULL, NULL},
226 };
227
228 static ComboConfigCandidate period_styles[] =
229 {
230     {"\xE3\x80\x81\xE3\x80\x82", "Japanese"},
231     {"\xEF\xBC\x8C\xE3\x80\x82", "WideLatin_Japanese"},
232     {"\xEF\xBC\x8C\xEF\xBC\x8E", "WideLatin"},
233     {",.",                       "Latin"},
234     {NULL, NULL},
235 };
236
237 static ComboConfigCandidate symbol_styles[] =
238 {
239     {"\xE3\x80\x8C\xE3\x80\x8D\xE3\x83\xBB", "Japanese"},
240     {"\xE3\x80\x8C\xE3\x80\x8D\xEF\xBC\x8F", "CornerBracket_WideSlash"},
241     {"\xEF\xBC\xBB\xEF\xBC\xBD\xE3\x83\xBB", "WideBracket_MiddleDot"},
242     {"\xEF\xBC\xBB\xEF\xBC\xBD\xEF\xBC\x8F", "WideBracket_WideSlash"},
243     {NULL, NULL},
244 };
245
246 static ComboConfigCandidate space_types[] =
247 {
248     {N_("Follow input mode"), "FollowMode"},
249     {N_("Wide"),              "Wide"},
250     {N_("Half"),              "Half"},
251     {NULL, NULL},
252 };
253
254 static ComboConfigCandidate ten_key_types[] =
255 {
256     {N_("Follow input mode"), "FollowMode"},
257     {N_("Wide"),              "Wide"},
258     {N_("Half"),              "Half"},
259     {NULL, NULL},
260 };
261
262 static ComboConfigCandidate behavior_on_period[] =
263 {
264     {N_("Do nothing"),       "None"},
265     {N_("Start conversion"), "Convert"},
266     {N_("Commit"),           "Commit"},
267     {NULL, NULL},
268 };
269
270 static ComboConfigCandidate behavior_on_focus_out[] =
271 {
272     {N_("Commit"), "Commit"},
273     {N_("Clear"),  "Clear"},
274     {NULL, NULL},
275 };
276
277 static ComboConfigCandidate dict_encoding[] =
278 {
279     {N_("UTF-8"),     "UTF-8"},
280     {N_("EUC-JP"),    "EUC-JP"},
281     {N_("EUC-JP-MS"), "EUC-JP-MS"},
282     {NULL, NULL},
283 };
284
285 static ComboConfigCandidate preedit_style[] =
286 {
287     {N_("No decoration"), "None"},
288     {N_("Underline"),     "Underline"},
289     {N_("Reverse"),       "Reverse"},
290     {N_("Highlight"),     "Highlight"},
291     {N_("String color"),  "FGColor"},
292     {N_("BG color"),      "BGColor"},
293     {N_("Both color"),    "Color"},
294     {NULL, NULL},
295 };
296
297
298 static void     setup_key_theme_menu              (GtkOptionMenu *omenu);
299 static void     setup_widget_value                (void);
300
301 static void     on_default_editable_changed       (GtkEditable      *editable,
302                                                    gpointer          user_data);
303 static void     on_default_toggle_button_toggled  (GtkToggleButton  *togglebutton,
304                                                    gpointer          user_data);
305 static void     on_default_spin_button_changed    (GtkSpinButton    *spinbutton,
306                                                    gpointer          user_data);
307 static void     on_default_key_selection_clicked  (GtkButton        *button,
308                                                    gpointer          user_data);
309 static void     on_default_combo_changed          (GtkEditable      *editable,
310                                                    gpointer          user_data);
311 static void     on_default_option_menu_changed    (GtkOptionMenu    *omenu,
312                                                    gpointer          user_data);
313 static void     on_preedit_style_menu_changed     (GtkOptionMenu    *omenu,
314                                                    gpointer          user_data);
315 static void     on_key_filter_selection_clicked   (GtkButton        *button,
316                                                    gpointer          user_data);
317 static void     on_dict_menu_label_toggled        (GtkToggleButton  *togglebutton,
318                                                    gpointer          user_data);
319 static void     on_key_category_menu_changed      (GtkOptionMenu    *omenu,
320                                                    gpointer          user_data);
321 static gboolean on_key_list_view_key_press        (GtkWidget        *widget,
322                                                    GdkEventKey      *event,
323                                                    gpointer          user_data);
324 static gboolean on_key_list_view_button_press     (GtkWidget        *widget,
325                                                    GdkEventButton   *event,
326                                                    gpointer          user_data);
327 static void     on_key_theme_menu_changed         (GtkOptionMenu    *omenu,
328                                                    gpointer          user_data);
329 static void     on_key_list_selection_changed     (GtkTreeSelection *selection,
330                                                    gpointer          data);
331 static void     on_choose_keys_button_clicked     (GtkWidget        *button,
332                                                    gpointer          data);
333 static void     on_dict_launch_button_clicked     (GtkButton        *button,
334                                                    gpointer          user_data);
335 static void     on_color_button_changed           (ScimAnthyColorButton  *button,
336                                                    gpointer               user_data);
337
338
339 static StringConfigData *
340 find_key_config_entry (const char *config_key)
341 {
342     for (unsigned int j = 0; j < __key_conf_pages_num; j++) {
343         for (unsigned int i = 0; __key_conf_pages[j].data[i].key; i++) {
344             StringConfigData *entry = &__key_conf_pages[j].data[i];
345             if (entry->key && !strcmp (entry->key, config_key))
346                 return entry;
347         }
348     }
349
350     return NULL;
351 }
352
353 GtkWidget *
354 create_check_button (const char *config_key)
355 {
356     BoolConfigData *entry = find_bool_config_entry (config_key);
357     if (!entry)
358         return NULL;
359
360     entry->widget = gtk_check_button_new_with_mnemonic (_(entry->label));
361     gtk_container_set_border_width (GTK_CONTAINER (entry->widget), 4);
362     g_signal_connect (G_OBJECT (entry->widget), "toggled",
363                       G_CALLBACK (on_default_toggle_button_toggled),
364                       entry);
365     gtk_widget_show (GTK_WIDGET (entry->widget));
366
367     if (!__widget_tooltips)
368         __widget_tooltips = gtk_tooltips_new();
369     if (entry->tooltip)
370         gtk_tooltips_set_tip (__widget_tooltips, GTK_WIDGET (entry->widget),
371                               _(entry->tooltip), NULL);
372
373     return GTK_WIDGET (entry->widget);
374 }
375
376 GtkWidget *
377 create_spin_button (const char *config_key, GtkTable *table, int idx)
378 {
379     IntConfigData *entry = find_int_config_entry (config_key);
380     if (!entry)
381         return NULL;
382
383     GtkWidget *label = gtk_label_new_with_mnemonic (_(entry->label));
384     gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
385     gtk_misc_set_padding (GTK_MISC (label), 4, 0);
386     gtk_table_attach (GTK_TABLE (table), label, 0, 1, idx, idx + 1,
387                       (GtkAttachOptions) (GTK_FILL),
388                       (GtkAttachOptions) (GTK_FILL),
389                       4, 4);
390     gtk_widget_show (GTK_WIDGET (label));
391
392     GtkWidget *hbox = gtk_hbox_new (FALSE, 0);
393     gtk_table_attach (GTK_TABLE (table), GTK_WIDGET (hbox),
394                       1, 2, idx, idx + 1,
395                       (GtkAttachOptions) GTK_FILL,
396                       (GtkAttachOptions) GTK_FILL,
397                       4, 4);
398     gtk_widget_show (hbox);
399
400     entry->widget = gtk_spin_button_new_with_range (entry->min, entry->max,
401                                                     entry->step);
402     gtk_label_set_mnemonic_widget (GTK_LABEL (label),
403                                    GTK_WIDGET (entry->widget));
404     gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (entry->widget),
405                         FALSE, FALSE, 0);
406     g_signal_connect (G_OBJECT (entry->widget), "value-changed",
407                       G_CALLBACK (on_default_spin_button_changed),
408                       entry);
409     gtk_widget_show (GTK_WIDGET (entry->widget));
410
411     if (entry->unit) {
412         label = gtk_label_new_with_mnemonic (_(entry->unit));
413         gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
414         gtk_misc_set_padding (GTK_MISC (label), 4, 0);
415         gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (label),
416                             FALSE, FALSE, 0);
417         gtk_widget_show (GTK_WIDGET (label));
418     }
419
420     if (!__widget_tooltips)
421         __widget_tooltips = gtk_tooltips_new();
422     if (entry->tooltip)
423         gtk_tooltips_set_tip (__widget_tooltips, GTK_WIDGET (entry->widget),
424                               _(entry->tooltip), NULL);
425
426     return GTK_WIDGET (entry->widget);
427 }
428
429 GtkWidget *
430 create_entry (const char *config_key, GtkTable *table, int idx)
431 {
432     StringConfigData *entry = find_string_config_entry (config_key);
433     if (!entry)
434         return NULL;
435
436     GtkWidget *label = gtk_label_new (NULL);
437     gtk_label_set_text_with_mnemonic (GTK_LABEL (label), _(entry->label));
438     gtk_widget_show (label);
439     gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
440     gtk_misc_set_padding (GTK_MISC (label), 4, 0);
441     gtk_table_attach (GTK_TABLE (table), label, 0, 1, idx, idx + 1,
442                       (GtkAttachOptions) (GTK_FILL),
443                       (GtkAttachOptions) (GTK_FILL), 4, 4);
444     (entry)->widget = gtk_entry_new ();
445     gtk_label_set_mnemonic_widget (GTK_LABEL (label),
446                                    GTK_WIDGET (entry->widget));
447     g_signal_connect ((gpointer) (entry)->widget, "changed",
448                       G_CALLBACK (on_default_editable_changed),
449                       entry);
450     gtk_widget_show (GTK_WIDGET (entry->widget));
451     gtk_table_attach (GTK_TABLE (table), GTK_WIDGET (entry->widget),
452                       1, 2, idx, idx + 1,
453                       (GtkAttachOptions) (GTK_FILL|GTK_EXPAND),
454                       (GtkAttachOptions) (GTK_FILL), 4, 4);
455
456     if (!__widget_tooltips)
457         __widget_tooltips = gtk_tooltips_new();
458     if (entry->tooltip)
459         gtk_tooltips_set_tip (__widget_tooltips, GTK_WIDGET (entry->widget),
460                               _(entry->tooltip), NULL);
461
462     return GTK_WIDGET (entry->widget);
463 }
464
465 GtkWidget *
466 create_combo (const char *config_key, gpointer candidates_p,
467               GtkTable *table, gint idx)
468 {
469     StringConfigData *entry = find_string_config_entry (config_key);
470     if (!entry)
471         return NULL;
472
473     GtkWidget *label;
474
475     label = gtk_label_new_with_mnemonic (_(entry->label));
476     gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
477     gtk_misc_set_padding (GTK_MISC (label), 4, 0);
478     gtk_table_attach (GTK_TABLE (table), label, 0, 1, idx, idx + 1,
479                       (GtkAttachOptions) (GTK_FILL),
480                       (GtkAttachOptions) (GTK_FILL), 4, 4);
481     gtk_widget_show (label);
482
483     entry->widget = gtk_combo_new ();
484     gtk_label_set_mnemonic_widget (GTK_LABEL (label),
485                                    GTK_COMBO (entry->widget)->entry);
486     gtk_combo_set_value_in_list (GTK_COMBO (entry->widget), TRUE, FALSE);
487     gtk_combo_set_case_sensitive (GTK_COMBO (entry->widget), TRUE);
488     gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (entry->widget)->entry),
489                             FALSE);
490     gtk_widget_show (GTK_WIDGET (entry->widget));
491     gtk_table_attach (GTK_TABLE (table), GTK_WIDGET (entry->widget),
492                       1, 2, idx, idx + 1,
493                       (GtkAttachOptions) (GTK_FILL|GTK_EXPAND),
494                       (GtkAttachOptions) (GTK_FILL), 4, 4);
495     g_object_set_data (G_OBJECT (GTK_COMBO (entry->widget)->entry),
496                        DATA_POINTER_KEY,
497                        (gpointer) candidates_p);
498
499     g_signal_connect ((gpointer) GTK_COMBO (entry->widget)->entry, "changed",
500                       G_CALLBACK (on_default_combo_changed),
501                       entry);
502
503     if (!__widget_tooltips)
504         __widget_tooltips = gtk_tooltips_new();
505     if (entry->tooltip)
506         gtk_tooltips_set_tip (__widget_tooltips,
507                               GTK_WIDGET (GTK_COMBO (entry->widget)->entry),
508                               _(entry->tooltip), NULL);
509
510     return GTK_WIDGET (entry->widget);
511 }
512
513 GtkWidget *
514 create_option_menu (const char *config_key, gpointer candidates_p,
515                     GtkTable *table, gint idx)
516 {
517     StringConfigData *entry = find_string_config_entry (config_key);
518     ComboConfigCandidate *data = static_cast<ComboConfigCandidate*> (candidates_p);
519     if (!entry)
520         return NULL;
521
522     GtkWidget *label;
523     label = gtk_label_new_with_mnemonic (_(entry->label));
524     gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
525     gtk_misc_set_padding (GTK_MISC (label), 4, 0);
526     gtk_table_attach (GTK_TABLE (table), label, 0, 1, idx, idx + 1,
527                       (GtkAttachOptions) (GTK_FILL),
528                       (GtkAttachOptions) (GTK_FILL), 4, 4);
529     gtk_widget_show (label);
530
531     entry->widget = gtk_option_menu_new ();
532     gtk_label_set_mnemonic_widget (GTK_LABEL (label),
533                                    GTK_WIDGET (entry->widget));
534     gtk_widget_show (GTK_WIDGET (entry->widget));
535     gtk_table_attach (GTK_TABLE (table), GTK_WIDGET (entry->widget),
536                       1, 2, idx, idx + 1,
537                       (GtkAttachOptions) (GTK_FILL),
538                       (GtkAttachOptions) (GTK_FILL), 4, 4);
539     g_object_set_data (G_OBJECT (entry->widget),
540                        DATA_POINTER_KEY,
541                        (gpointer) candidates_p);
542
543     GtkWidget *menu = gtk_menu_new ();
544     gtk_option_menu_set_menu (GTK_OPTION_MENU (entry->widget), menu);
545     gtk_widget_show (menu);
546
547     for (unsigned int i = 0; data[i].label; i++) {
548         GtkWidget *menuitem = gtk_menu_item_new_with_label (_(data[i].label));
549         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
550         gtk_widget_show (menuitem);
551     }
552
553     gtk_option_menu_set_history (GTK_OPTION_MENU (entry->widget), 0);
554
555     g_signal_connect ((gpointer) GTK_OPTION_MENU (entry->widget), "changed",
556                       G_CALLBACK (on_default_option_menu_changed),
557                       entry);
558
559     if (!__widget_tooltips)
560         __widget_tooltips = gtk_tooltips_new();
561     if (entry->tooltip)
562         gtk_tooltips_set_tip (__widget_tooltips, GTK_WIDGET (entry->widget),
563                               _(entry->tooltip), NULL);
564
565     return GTK_WIDGET (entry->widget);
566 }
567
568 GtkWidget *
569 create_key_select_button (const char *config_key, GtkTable *table, int idx)
570 {
571     StringConfigData *entry = find_string_config_entry (config_key);
572     if (!entry)
573         return NULL;
574
575     GtkWidget *button = gtk_button_new_with_label ("...");
576     gtk_widget_show (button);
577     gtk_table_attach (GTK_TABLE (table), button, 2, 3, idx, idx + 1,
578                       GTK_FILL, GTK_FILL, 4, 4);
579     g_signal_connect ((gpointer) button, "clicked",
580                       G_CALLBACK (on_default_key_selection_clicked),
581                       entry);
582
583     return button;
584 }
585
586 GtkWidget *
587 create_color_button (const char *config_key)
588 {
589     ColorConfigData *entry = find_color_config_entry (config_key);
590     if (!entry)
591         return NULL;
592
593     GtkWidget *hbox = gtk_hbox_new (FALSE, 0);
594     gtk_container_set_border_width (GTK_CONTAINER (hbox), 4);
595     gtk_widget_show (hbox);
596
597     GtkWidget *label = NULL;
598     if (entry->label) {
599         label = gtk_label_new_with_mnemonic (_(entry->label));
600         gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 2);
601         gtk_widget_show (label);
602     }
603
604     entry->widget = scim_anthy_color_button_new ();
605     gtk_widget_set_size_request (GTK_WIDGET (entry->widget), 32, 24);
606     g_signal_connect (G_OBJECT (entry->widget), "color-changed",
607                       G_CALLBACK (on_color_button_changed),
608                       entry);
609     gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (entry->widget),
610                         FALSE, FALSE, 2);
611     gtk_widget_show (GTK_WIDGET (entry->widget));
612
613     if (label)
614         gtk_label_set_mnemonic_widget (GTK_LABEL (label),
615                                        GTK_WIDGET (entry->widget));
616
617     if (!__widget_tooltips)
618         __widget_tooltips = gtk_tooltips_new();
619     if (entry->tooltip)
620         gtk_tooltips_set_tip (__widget_tooltips, GTK_WIDGET (entry->widget),
621                               _(entry->tooltip), NULL);
622
623     return hbox;
624 }
625
626 static void
627 append_key_bindings (GtkTreeView *treeview, gint idx, const gchar *filter)
628 {
629     GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model (treeview));
630     KeyEventList keys1, keys2;
631     
632     if (filter && *filter)
633         scim_string_to_key_list (keys1, filter);
634
635     if (idx < 0 || idx >= (gint) __key_conf_pages_num)
636         return;
637
638     for (unsigned int i = 0; __key_conf_pages[idx].data[i].key; i++) {
639         if (filter && *filter) {
640             scim_string_to_key_list (
641                 keys2,
642                 __key_conf_pages[idx].data[i].value.c_str());
643             KeyEventList::const_iterator kit;
644             bool found = true;
645             for (kit = keys1.begin (); kit != keys1.end (); kit++) {
646                 if (!util_match_key_event (keys2, *kit)) {
647                     found = false;
648                     break;
649                 }
650             }
651             if (!found)
652                 continue;
653         }
654
655         GtkTreeIter iter;
656         gtk_list_store_append (store, &iter);
657         gtk_list_store_set (
658             store, &iter,
659             COLUMN_LABEL, _(__key_conf_pages[idx].data[i].label),
660             COLUMN_VALUE, __key_conf_pages[idx].data[i].value.c_str (),
661             COLUMN_DESC,  _(__key_conf_pages[idx].data[i].tooltip),
662             COLUMN_DATA, &__key_conf_pages[idx].data[i],
663             -1);
664     }
665 }
666
667 static void
668 key_list_view_popup_key_selection (GtkTreeView *treeview)
669 {
670     GtkTreeModel *model = gtk_tree_view_get_model (treeview);
671     GtkTreePath *treepath = NULL;
672     GtkTreeIter iter;
673
674     gtk_tree_view_get_cursor (treeview, &treepath, NULL);
675     if (!treepath) return;
676     gtk_tree_model_get_iter (model, &iter, treepath);
677     gtk_tree_path_free (treepath);
678
679     StringConfigData *data;
680     gtk_tree_model_get (model, &iter,
681                         COLUMN_DATA, &data,
682                         -1);
683     if (data) {
684         GtkWidget *dialog = scim_key_selection_dialog_new (_(data->title));
685         gint result;
686
687         scim_key_selection_dialog_set_keys
688             (SCIM_KEY_SELECTION_DIALOG (dialog),
689              data->value.c_str());
690
691         result = gtk_dialog_run (GTK_DIALOG (dialog));
692
693         if (result == GTK_RESPONSE_OK) {
694             const gchar *keys = scim_key_selection_dialog_get_keys
695                 (SCIM_KEY_SELECTION_DIALOG (dialog));
696
697             if (!keys) keys = "";
698
699             if (strcmp (keys, data->value.c_str())) {
700                 data->value = keys;
701                 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
702                                     COLUMN_VALUE, data->value.c_str(),
703                                     -1);
704                 gtk_option_menu_set_history (
705                     GTK_OPTION_MENU (__widget_key_theme_menu),
706                     KEY_THEME_INDEX_USER_DEFINED);
707                 data->changed = true;
708                 __config_changed = true;
709             }
710         }
711
712         gtk_widget_destroy (dialog);
713     }
714 }
715
716 static GtkWidget *
717 create_common_page (void)
718 {
719     GtkWidget *vbox, *table, *widget;
720
721     vbox = gtk_vbox_new (FALSE, 0);
722     gtk_widget_show (vbox);
723
724     table = gtk_table_new (7, 2, FALSE);
725     gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
726     gtk_widget_show (table);
727
728     /* input mode */
729     widget = create_combo (SCIM_ANTHY_CONFIG_INPUT_MODE,
730                            (gpointer) &input_modes,
731                            GTK_TABLE (table), 0);
732
733     /* typing method */
734     widget = create_combo (SCIM_ANTHY_CONFIG_TYPING_METHOD,
735                            (gpointer) &typing_methods,
736                            GTK_TABLE (table), 1);
737
738     /* conversion mode */
739     widget = create_combo (SCIM_ANTHY_CONFIG_CONVERSION_MODE,
740                            (gpointer) &conversion_modes,
741                            GTK_TABLE (table), 2);
742
743     /* behavior on focus out */
744     widget = create_combo (SCIM_ANTHY_CONFIG_BEHAVIOR_ON_FOCUS_OUT,
745                            (gpointer) &behavior_on_focus_out,
746                            GTK_TABLE (table), 3);
747
748     return vbox;
749 }
750
751 static GtkWidget *
752 create_symbols_page (void)
753 {
754     GtkWidget *vbox, *table, *widget;
755
756     vbox = gtk_vbox_new (FALSE, 0);
757     gtk_widget_show (vbox);
758
759     table = gtk_table_new (7, 2, FALSE);
760     gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
761     gtk_widget_show (table);
762
763     /* period style */
764     widget = create_combo (SCIM_ANTHY_CONFIG_PERIOD_STYLE,
765                            (gpointer) &period_styles,
766                            GTK_TABLE (table), 3);
767
768     /* symbol style */
769     widget = create_combo (SCIM_ANTHY_CONFIG_SYMBOL_STYLE,
770                            (gpointer) &symbol_styles,
771                            GTK_TABLE (table), 4);
772
773     /* space_style */
774     widget = create_combo (SCIM_ANTHY_CONFIG_SPACE_TYPE,
775                            (gpointer) &space_types,
776                            GTK_TABLE (table), 5);
777
778     /* ten key_style */
779     widget = create_combo (SCIM_ANTHY_CONFIG_TEN_KEY_TYPE,
780                            (gpointer) &ten_key_types,
781                            GTK_TABLE (table), 6);
782
783     /* behavior on period */
784     widget = create_combo (SCIM_ANTHY_CONFIG_BEHAVIOR_ON_PERIOD,
785                            (gpointer) &behavior_on_period,
786                            GTK_TABLE (table), 7);
787
788     return vbox;
789 }
790
791 static GtkWidget *
792 create_keyboard_page (void)
793 {
794     GtkWidget *vbox, *hbox;
795
796     vbox = gtk_vbox_new (FALSE, 0);
797     gtk_widget_show (vbox);
798
799     hbox = gtk_hbox_new (FALSE, 0);
800     gtk_container_set_border_width (GTK_CONTAINER (hbox), 4);
801     gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
802     gtk_widget_show(hbox);
803
804     // category menu
805     GtkWidget *label = gtk_label_new_with_mnemonic (_("_Group:"));
806     gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 2);
807     gtk_widget_show (label);
808
809     GtkWidget *omenu = gtk_option_menu_new ();
810     __widget_key_categories_menu = omenu;
811     gtk_box_pack_start (GTK_BOX (hbox), omenu, FALSE, FALSE, 2);
812     gtk_widget_show (omenu);
813
814     gtk_label_set_mnemonic_widget (GTK_LABEL (label), omenu);
815
816     GtkWidget *menu = gtk_menu_new ();
817
818     GtkWidget *menuitem;
819
820     for (unsigned int i = 0; i < __key_conf_pages_num; i++) {
821         menuitem = gtk_menu_item_new_with_label (_(__key_conf_pages[i].label));
822         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
823         gtk_widget_show (menuitem);
824     }
825
826     menuitem = gtk_menu_item_new_with_label (_("Search by key"));
827     gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
828     gtk_widget_show (menuitem);
829
830     menuitem = gtk_menu_item_new_with_label (_("all"));
831     gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
832     gtk_widget_show (menuitem);
833
834     gtk_option_menu_set_menu (GTK_OPTION_MENU (omenu), menu);
835     gtk_widget_show (menu);
836
837     GtkWidget *entry = gtk_entry_new ();
838     __widget_key_filter = entry;
839     gtk_entry_set_editable (GTK_ENTRY (entry), FALSE);
840     gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 2);
841     gtk_widget_show(entry);
842
843     GtkWidget *button = gtk_button_new_with_label ("...");
844     __widget_key_filter_button = button;
845     g_signal_connect (G_OBJECT (button), "clicked",
846                       G_CALLBACK (on_key_filter_selection_clicked), entry);
847     gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 2);
848     gtk_widget_show (button);
849
850     // key bindings view
851     GtkWidget *scrwin = gtk_scrolled_window_new (NULL, NULL);
852     gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrwin),
853                                          GTK_SHADOW_IN);
854     gtk_container_set_border_width (GTK_CONTAINER (scrwin), 4);
855     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scrwin),
856                                    GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
857     gtk_box_pack_start (GTK_BOX (vbox), scrwin, TRUE, TRUE, 2);
858     gtk_widget_show (scrwin);
859
860     GtkListStore *store = gtk_list_store_new (N_COLUMNS,
861                                               G_TYPE_STRING,
862                                               G_TYPE_STRING,
863                                               G_TYPE_STRING,
864                                               G_TYPE_POINTER);
865     GtkWidget *treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
866     __widget_key_list_view = treeview;
867     gtk_container_add (GTK_CONTAINER (scrwin), treeview);
868     gtk_widget_show (treeview);
869
870     GtkCellRenderer *cell;
871     GtkTreeViewColumn *column;
872     cell = gtk_cell_renderer_text_new ();
873     column = gtk_tree_view_column_new_with_attributes (_("Feature"), cell,
874                                                        "text", COLUMN_LABEL,
875                                                        NULL);
876     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
877     gtk_tree_view_column_set_fixed_width (column, 120);
878     gtk_tree_view_column_set_resizable(column, TRUE);
879     gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
880
881     cell = gtk_cell_renderer_text_new ();
882     column = gtk_tree_view_column_new_with_attributes (_("Key bindings"), cell,
883                                                        "text", COLUMN_VALUE,
884                                                        NULL);
885     gtk_tree_view_column_set_fixed_width (column, 200);
886     gtk_tree_view_column_set_resizable(column, TRUE);
887     gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
888
889     cell = gtk_cell_renderer_text_new ();
890     column = gtk_tree_view_column_new_with_attributes (_("Description"), cell,
891                                                        "text", COLUMN_DESC,
892                                                        NULL);
893     gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
894
895     GtkTreeSelection *selection;
896     selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
897
898     // connect signals
899     g_signal_connect (G_OBJECT (omenu), "changed",
900                       G_CALLBACK (on_key_category_menu_changed), treeview);
901     g_signal_connect (G_OBJECT (treeview), "key-press-event",
902                       G_CALLBACK (on_key_list_view_key_press), treeview);
903     g_signal_connect (G_OBJECT (treeview), "button-press-event",
904                       G_CALLBACK (on_key_list_view_button_press), treeview);
905     g_signal_connect (G_OBJECT (selection), "changed",
906                       G_CALLBACK (on_key_list_selection_changed), treeview);
907
908     hbox = gtk_hbox_new (FALSE, 0);
909     gtk_container_set_border_width (GTK_CONTAINER (hbox), 4);
910     gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
911     gtk_widget_show(hbox);
912
913     // for key bind theme
914     label = gtk_label_new_with_mnemonic (_("Key bindings _theme:"));
915     gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 2);
916     gtk_widget_show (label);
917
918     omenu = gtk_option_menu_new ();
919     __widget_key_theme_menu = omenu;
920     g_signal_connect (G_OBJECT (omenu), "changed",
921                       G_CALLBACK (on_key_theme_menu_changed), NULL);
922     gtk_box_pack_start (GTK_BOX (hbox), omenu, FALSE, FALSE, 2);
923     gtk_widget_show (omenu);
924
925     gtk_label_set_mnemonic_widget (GTK_LABEL(label), omenu);
926
927     // edit button
928     button = gtk_button_new_with_mnemonic (_("_Choose keys..."));
929     __widget_choose_keys_button = button;
930     g_signal_connect (G_OBJECT (button), "clicked",
931                       G_CALLBACK (on_choose_keys_button_clicked), treeview);
932     gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 2);
933     gtk_widget_set_sensitive (button, false);
934     gtk_widget_show (button);
935
936     // clean
937     g_object_unref (G_OBJECT (store));
938
939     return vbox;
940 }
941
942 static GtkWidget *
943 create_learning_page ()
944 {
945     GtkWidget *vbox, *vbox2, *hbox, *alignment, *table;
946     GtkWidget *widget, *label;
947
948     vbox = gtk_vbox_new (FALSE, 0);
949     gtk_widget_show (vbox);
950
951     hbox = gtk_hbox_new (FALSE, 0);
952     gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 4);
953     gtk_widget_show (hbox);
954
955     label = gtk_label_new (_("<b>Enable/Disable learning</b>"));
956     gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
957     gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 4);
958     gtk_widget_show (label);
959
960     alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
961     gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 24, 0);
962     gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0);
963     gtk_widget_show (alignment);
964
965     vbox2 = gtk_vbox_new (FALSE, 0);
966     gtk_container_add (GTK_CONTAINER (alignment), vbox2);
967     gtk_widget_show (vbox2);
968
969     /* maual commit */
970     widget = create_check_button (SCIM_ANTHY_CONFIG_LEARN_ON_MANUAL_COMMIT);
971     gtk_box_pack_start (GTK_BOX (vbox2), widget, FALSE, FALSE, 4);
972
973     /* auto commit */
974     widget = create_check_button (SCIM_ANTHY_CONFIG_LEARN_ON_AUTO_COMMIT);
975     gtk_box_pack_start (GTK_BOX (vbox2), widget, FALSE, FALSE, 4);
976
977     /* key preference */
978     hbox = gtk_hbox_new (FALSE, 0);
979     gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 4);
980     gtk_widget_show (hbox);
981
982     label = gtk_label_new (_("<b>Key preferences to commit "
983                              "with reversing learning preference</b>"));
984     gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
985     gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 4);
986     gtk_widget_show (label);
987
988     alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
989     gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 24, 0);
990     gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0);
991     gtk_widget_show (alignment);
992
993     table = gtk_table_new (3, 3, FALSE);
994     gtk_container_add (GTK_CONTAINER (alignment), table);
995     gtk_widget_show (table);
996
997     StringConfigData *entries[3];
998     entries [0] = find_string_config_entry (
999         SCIM_ANTHY_CONFIG_COMMIT_REVERSE_LEARN_KEY);
1000     entries [1] = find_string_config_entry (
1001         SCIM_ANTHY_CONFIG_COMMIT_FIRST_SEGMENT_REVERSE_LEARN_KEY);
1002     entries [2] = find_string_config_entry (
1003         SCIM_ANTHY_CONFIG_COMMIT_SELECTED_SEGMENT_REVERSE_LEARN_KEY);
1004
1005     for (unsigned int i = 0;
1006          i < sizeof (entries) / sizeof (StringConfigData*);
1007          i++)
1008     {
1009         StringConfigData *entry = entries[i];
1010         widget = create_entry (entry->key, GTK_TABLE (table), i);
1011         gtk_entry_set_editable (GTK_ENTRY (widget), FALSE);
1012         create_key_select_button (entry->key, GTK_TABLE (table), i);
1013     }
1014
1015     return vbox;
1016 }
1017
1018 static GtkWidget *
1019 create_prediction_page ()
1020 {
1021     GtkWidget *vbox, *widget;
1022
1023     vbox = gtk_vbox_new (FALSE, 0);
1024     gtk_widget_show (vbox);
1025
1026     /* predict while inputting */
1027     widget = create_check_button (SCIM_ANTHY_CONFIG_PREDICT_ON_INPUT);
1028     gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 4);
1029
1030     /* use direct select keys */
1031     widget = create_check_button (SCIM_ANTHY_CONFIG_USE_DIRECT_KEY_ON_PREDICT);
1032     gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 4);
1033
1034     return vbox;
1035 }
1036
1037 static GtkWidget *
1038 create_dict_page (void)
1039 {
1040     GtkWidget *table, *button;
1041     StringConfigData *entry;
1042
1043     table = gtk_table_new (3, 3, FALSE);
1044     gtk_widget_show (table);
1045
1046     // encoding of dictionary
1047     create_combo (SCIM_ANTHY_CONFIG_DICT_ENCODING,
1048                   (gpointer) &dict_encoding,
1049                   GTK_TABLE (table), 0);
1050
1051     // dict admin command
1052     create_entry (SCIM_ANTHY_CONFIG_DICT_ADMIN_COMMAND,
1053                   GTK_TABLE (table), 1);
1054     entry = find_string_config_entry (SCIM_ANTHY_CONFIG_DICT_ADMIN_COMMAND);
1055
1056     button = gtk_button_new_with_mnemonic (_("_Launch"));
1057     gtk_table_attach (GTK_TABLE (table), GTK_WIDGET (button),
1058                       2, 3, 1, 2,
1059                       (GtkAttachOptions) 0,
1060                       (GtkAttachOptions) 0, 4, 4);
1061     g_signal_connect (G_OBJECT (button), "clicked",
1062                       G_CALLBACK (on_dict_launch_button_clicked), entry);
1063     gtk_widget_show (button);
1064
1065     // add word command
1066     create_entry (SCIM_ANTHY_CONFIG_ADD_WORD_COMMAND,
1067                   GTK_TABLE (table), 2);
1068     entry = find_string_config_entry (SCIM_ANTHY_CONFIG_ADD_WORD_COMMAND);
1069
1070     button = gtk_button_new_with_mnemonic (_("_Launch"));
1071     gtk_table_attach (GTK_TABLE (table), GTK_WIDGET (button),
1072                       2, 3, 2, 3,
1073                       (GtkAttachOptions) 0,
1074                       (GtkAttachOptions) 0, 4, 4);
1075     g_signal_connect (G_OBJECT (button), "clicked",
1076                       G_CALLBACK (on_dict_launch_button_clicked), entry);
1077     gtk_widget_show (button);
1078
1079     return table;
1080 }
1081
1082 static GtkWidget *
1083 create_candidates_window_page (void)
1084 {
1085     GtkWidget *vbox, *widget, *table;
1086
1087     vbox = gtk_vbox_new (FALSE, 0);
1088     gtk_widget_show (vbox);
1089
1090     /* show candidates label */
1091     widget = create_check_button (SCIM_ANTHY_CONFIG_SHOW_CANDIDATES_LABEL);
1092     gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 2);
1093
1094     /* close candidate window on select */
1095     widget = create_check_button (SCIM_ANTHY_CONFIG_CLOSE_CAND_WIN_ON_SELECT);
1096     gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 2);
1097
1098     table = gtk_table_new (2, 2, FALSE);
1099     gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
1100     gtk_widget_show (table);
1101
1102     /* number of triggers until show candidates window */
1103     create_spin_button (SCIM_ANTHY_CONFIG_CAND_WIN_PAGE_SIZE,
1104                         GTK_TABLE (table), 0);
1105
1106     /* number of triggers until show candidates window */
1107     create_spin_button (SCIM_ANTHY_CONFIG_N_TRIGGERS_TO_SHOW_CAND_WIN,
1108                         GTK_TABLE (table), 1);
1109
1110     return vbox;
1111 }
1112
1113 static GtkWidget *
1114 create_toolbar_page (void)
1115 {
1116     GtkWidget *vbox, *hbox, *label, *widget;
1117
1118     vbox = gtk_vbox_new (FALSE, 0);
1119     gtk_widget_show (vbox);
1120
1121     /* show/hide toolbar label */
1122     widget = create_check_button (SCIM_ANTHY_CONFIG_SHOW_INPUT_MODE_LABEL);
1123     gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 2);
1124
1125     widget = create_check_button (SCIM_ANTHY_CONFIG_SHOW_TYPING_METHOD_LABEL);
1126     gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 2);
1127
1128     widget = create_check_button (SCIM_ANTHY_CONFIG_SHOW_CONVERSION_MODE_LABEL);
1129     gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 2);
1130
1131     widget = create_check_button (SCIM_ANTHY_CONFIG_SHOW_PERIOD_STYLE_LABEL);
1132     gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 2);
1133
1134     widget = create_check_button (SCIM_ANTHY_CONFIG_SHOW_SYMBOL_STYLE_LABEL);
1135     gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 2);
1136
1137     /* dictionary menu */
1138     widget = create_check_button (SCIM_ANTHY_CONFIG_SHOW_DICT_LABEL);
1139     g_signal_connect ((gpointer) widget, "toggled",
1140                       G_CALLBACK (on_dict_menu_label_toggled),
1141                       NULL);
1142     gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 2);
1143
1144     hbox = gtk_hbox_new (FALSE, 0);
1145     gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2);
1146     gtk_widget_show (hbox);
1147     label = gtk_label_new ("    ");
1148     gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1149
1150     gtk_widget_show (label);
1151     widget = create_check_button (SCIM_ANTHY_CONFIG_SHOW_DICT_ADMIN_LABEL);
1152     gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
1153
1154     gtk_widget_show (label);
1155     widget = create_check_button (SCIM_ANTHY_CONFIG_SHOW_ADD_WORD_LABEL);
1156     gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
1157
1158     // set initial state
1159     on_dict_menu_label_toggled (GTK_TOGGLE_BUTTON (widget), NULL);
1160
1161     return vbox;
1162 }
1163
1164 static GtkWidget *
1165 create_appearance_page (void)
1166 {
1167     GtkWidget *vbox, *table, *omenu, *widget, *hbox; 
1168
1169     vbox = gtk_vbox_new (FALSE, 0);
1170     gtk_widget_show (vbox);
1171
1172     table = gtk_table_new (2, 3, FALSE);
1173     gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
1174     gtk_widget_show (table);
1175
1176     /* preedit style */
1177     omenu = create_option_menu (SCIM_ANTHY_CONFIG_PREEDIT_STYLE,
1178                                 &preedit_style, GTK_TABLE (table), 0);
1179
1180     /* preedit color */
1181     hbox = gtk_hbox_new (FALSE, 0);
1182     gtk_widget_show (hbox);
1183     widget = create_color_button (SCIM_ANTHY_CONFIG_PREEDIT_FG_COLOR);
1184     gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
1185     gtk_table_attach (GTK_TABLE (table), hbox, 2, 3, 0, 1,
1186                       (GtkAttachOptions) (GTK_FILL),
1187                       (GtkAttachOptions) (GTK_FILL), 4, 4);
1188     gtk_widget_set_sensitive (hbox, FALSE);
1189
1190     g_signal_connect ((gpointer) GTK_OPTION_MENU (omenu), "changed",
1191                       G_CALLBACK (on_preedit_style_menu_changed), hbox);
1192
1193     /* conversion style */
1194     omenu = create_option_menu (SCIM_ANTHY_CONFIG_CONVERSION_STYLE,
1195                                 &preedit_style, GTK_TABLE (table), 1);
1196
1197     /* conversion color */
1198     hbox = gtk_hbox_new (FALSE, 0);
1199     gtk_widget_show (hbox);
1200     widget = create_color_button (SCIM_ANTHY_CONFIG_CONVERSION_FG_COLOR);
1201     gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
1202     gtk_table_attach (GTK_TABLE (table), hbox, 2, 3, 1, 2,
1203                       (GtkAttachOptions) (GTK_FILL),
1204                       (GtkAttachOptions) (GTK_FILL), 4, 4);
1205     gtk_widget_set_sensitive (hbox, FALSE);
1206
1207     g_signal_connect ((gpointer) GTK_OPTION_MENU (omenu), "changed",
1208                       G_CALLBACK (on_preedit_style_menu_changed), hbox);
1209
1210     /* selected segment style */
1211     omenu = create_option_menu (SCIM_ANTHY_CONFIG_SELECTED_SEGMENT_STYLE,
1212                                 &preedit_style, GTK_TABLE (table), 2);
1213
1214     /* selected segment color */
1215     hbox = gtk_hbox_new (FALSE, 0);
1216     gtk_widget_show (hbox);
1217     widget = create_color_button (SCIM_ANTHY_CONFIG_SELECTED_SEGMENT_FG_COLOR);
1218     gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
1219     gtk_table_attach (GTK_TABLE (table), hbox, 2, 3, 2, 3,
1220                       (GtkAttachOptions) (GTK_FILL),
1221                       (GtkAttachOptions) (GTK_FILL), 4, 4);
1222     gtk_widget_set_sensitive (hbox, FALSE);
1223
1224     g_signal_connect ((gpointer) GTK_OPTION_MENU (omenu), "changed",
1225                       G_CALLBACK (on_preedit_style_menu_changed), hbox);
1226
1227     return vbox;
1228 }
1229
1230 static GtkWidget *
1231 create_about_page ()
1232 {
1233     GtkWidget *vbox, *label;
1234     gchar str[256];
1235
1236     vbox = gtk_vbox_new (FALSE, 0);
1237     gtk_widget_show (vbox);
1238
1239     g_snprintf (
1240         str, 256,
1241         _("<span size=\"20000\">"
1242           "%s-%s"
1243           "</span>\n\n"
1244
1245           "<span size=\"16000\" style=\"italic\">"
1246           "A Japanese input method module\nfor SCIM using Anthy"
1247           "</span>\n\n\n\n"
1248
1249           "<span size=\"12000\">"
1250           "Copyright 2005-2006, Takuro Ashie &lt;ashie@homa.ne.jp&gt;"
1251           "</span>"),
1252         PACKAGE, PACKAGE_VERSION);
1253
1254     label = gtk_label_new (NULL);
1255     gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);
1256     gtk_label_set_markup (GTK_LABEL (label), str);
1257     gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
1258     gtk_widget_show (label);
1259
1260     return vbox;
1261 }
1262
1263 static GtkWidget *
1264 create_setup_window (void)
1265 {
1266     static GtkWidget *window = NULL;
1267
1268     if (!window) {
1269         GtkWidget *notebook = gtk_notebook_new();
1270         gtk_notebook_popup_enable(GTK_NOTEBOOK(notebook));
1271         gtk_widget_show (notebook);
1272         window = notebook;
1273         gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE);
1274
1275         // Create the common page.
1276         GtkWidget *page = create_common_page ();
1277         GtkWidget *label = gtk_label_new (_("Common"));
1278         gtk_widget_show (label);
1279         gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
1280
1281         // Create the symbols page.
1282         page = create_symbols_page ();
1283         label = gtk_label_new (_("Symbols"));
1284         gtk_widget_show (label);
1285         gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
1286
1287         // Create the key bind page.
1288         page = create_keyboard_page ();
1289         label = gtk_label_new (_("Key bindings"));
1290         gtk_widget_show (label);
1291         gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
1292
1293         // Create the romaji page.
1294         page = romaji_page_create_ui ();
1295         label = gtk_label_new (_("Romaji typing"));
1296         gtk_widget_show (label);
1297         gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
1298
1299         // Create the kana page.
1300         page = kana_page_create_ui ();
1301         label = gtk_label_new (_("Kana typing"));
1302         gtk_widget_show (label);
1303         gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
1304
1305         // Create the learning page.
1306         page = create_prediction_page ();
1307         label = gtk_label_new (_("Prediction"));
1308         gtk_widget_show (label);
1309         gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
1310
1311         // Create the learning page.
1312         page = create_learning_page ();
1313         label = gtk_label_new (_("Learning"));
1314         gtk_widget_show (label);
1315         gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
1316
1317         // Create the dictionary page.
1318         page = create_dict_page ();
1319         label = gtk_label_new (_("Dictionary"));
1320         gtk_widget_show (label);
1321         gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
1322
1323         // Create the candidates widnow page.
1324         page = create_candidates_window_page ();
1325         label = gtk_label_new (_("Candidates window"));
1326         gtk_widget_show (label);
1327         gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
1328
1329         // Create the toolbar page.
1330         page = create_toolbar_page ();
1331         label = gtk_label_new (_("Toolbar"));
1332         gtk_widget_show (label);
1333         gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
1334
1335         // Create the appearance  page.
1336         page = create_appearance_page ();
1337         label = gtk_label_new (_("Appearance"));
1338         gtk_widget_show (label);
1339         gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
1340
1341         // Create the appearance  page.
1342         page = create_about_page ();
1343         label = gtk_label_new (_("About"));
1344         gtk_widget_show (label);
1345         gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
1346
1347         // for preventing enabling left arrow.
1348         gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 1);
1349         gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 0);
1350
1351         setup_widget_value ();
1352     }
1353
1354     return window;
1355 }
1356
1357 static void
1358 setup_combo_value (GtkCombo *combo, const String & str)
1359 {
1360     GList *list = NULL;
1361     const char *defval = NULL;
1362
1363     ComboConfigCandidate *data
1364         = static_cast<ComboConfigCandidate*>
1365         (g_object_get_data (G_OBJECT (GTK_COMBO(combo)->entry),
1366                             DATA_POINTER_KEY));
1367
1368     for (unsigned int i = 0; data[i].label; i++) {
1369         list = g_list_append (list, (gpointer) _(data[i].label));
1370         if (!strcmp (data[i].data, str.c_str ()))
1371             defval = _(data[i].label);
1372     }
1373
1374     gtk_combo_set_popdown_strings (combo, list);
1375     g_list_free (list);
1376
1377     if (defval)
1378         gtk_entry_set_text (GTK_ENTRY (combo->entry), defval);
1379 }
1380
1381 static void
1382 setup_option_menu_value (GtkOptionMenu *omenu, const String & str)
1383 {
1384     ComboConfigCandidate *data
1385         = static_cast<ComboConfigCandidate*>
1386         (g_object_get_data (G_OBJECT (omenu), DATA_POINTER_KEY));
1387
1388     for (unsigned int i = 0; data[i].label; i++) {
1389         if (!strcmp (data[i].data, str.c_str ())) {
1390             gtk_option_menu_set_history (omenu, i);
1391             return;
1392         }
1393     }
1394 }
1395
1396 static void
1397 setup_key_theme_menu (GtkOptionMenu *omenu)
1398 {
1399     GtkWidget *menu = gtk_menu_new ();
1400     gtk_option_menu_set_menu (GTK_OPTION_MENU (omenu),
1401                               menu);
1402     gtk_widget_show (menu);
1403
1404     // create menu items
1405     GtkWidget *menuitem = gtk_menu_item_new_with_label (_("User defined"));
1406     gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1407
1408     menuitem = gtk_menu_item_new_with_label (_("Default"));
1409     gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1410     gtk_widget_show (menuitem);
1411
1412     StyleFiles::iterator it;
1413     unsigned int i;
1414     for (i = 0, it = __style_list.begin ();
1415          it != __style_list.end ();
1416          i++, it++)
1417     {
1418         const char *section_name = "KeyBindings";
1419         StyleLines section;
1420         if (!it->get_entry_list (section, section_name))
1421             continue;
1422
1423         menuitem = gtk_menu_item_new_with_label (_(it->get_title().c_str()));
1424         g_object_set_data (G_OBJECT (menuitem),
1425                            INDEX_KEY, GINT_TO_POINTER (i));
1426         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1427         gtk_widget_show (menuitem);
1428     }
1429
1430     // set default value
1431     g_signal_handlers_block_by_func (G_OBJECT (omenu),
1432                                      (gpointer) (on_key_theme_menu_changed),
1433                                      NULL);
1434
1435     gtk_option_menu_set_history (GTK_OPTION_MENU (omenu),
1436                                  KEY_THEME_INDEX_DEFAULT);
1437
1438     if (__config_key_theme_file == __user_style_file.get_file_name () ||
1439         __config_key_theme      == __user_style_file.get_title ())
1440     {
1441         gtk_option_menu_set_history (GTK_OPTION_MENU (omenu),
1442                                      KEY_THEME_INDEX_USER_DEFINED);
1443
1444     } else {
1445         GList *node, *list = gtk_container_get_children (GTK_CONTAINER (menu));
1446         for (i = 2, node = g_list_next (g_list_next (list));
1447              node;
1448              i++, node = g_list_next (node))
1449         {
1450             gint idx = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (node->data),
1451                                                            INDEX_KEY));
1452             if (__style_list[idx].get_file_name () == __config_key_theme_file) {
1453                 gtk_option_menu_set_history (GTK_OPTION_MENU (omenu), i);
1454                 break;
1455             }
1456         }
1457     }
1458
1459     g_signal_handlers_unblock_by_func (G_OBJECT (omenu),
1460                                        (gpointer) (on_key_theme_menu_changed),
1461                                        NULL);
1462 }
1463
1464 static void
1465 setup_widget_value (void)
1466 {
1467     for (unsigned int i = 0; config_bool_common[i].key; i++) {
1468         BoolConfigData &entry = config_bool_common[i];
1469         if (entry.widget)
1470             gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (entry.widget),
1471                                           entry.value);
1472     }
1473
1474     for (unsigned int i = 0; config_int_common[i].key; i++) {
1475         IntConfigData &entry = config_int_common[i];
1476         if (entry.widget)
1477             gtk_spin_button_set_value (GTK_SPIN_BUTTON (entry.widget),
1478                                        entry.value);
1479     }
1480
1481     for (unsigned int i = 0; config_string_common[i].key; i++) {
1482         StringConfigData &entry = config_string_common[i];
1483         if (entry.widget && GTK_IS_OPTION_MENU (entry.widget)) {
1484             setup_option_menu_value (GTK_OPTION_MENU (entry.widget),
1485                                      entry.value);
1486         } else if (entry.widget && GTK_IS_COMBO (entry.widget)) {
1487             setup_combo_value (GTK_COMBO (entry.widget), entry.value);
1488         } else if (entry.widget && GTK_IS_ENTRY (entry.widget)) {
1489             gtk_entry_set_text (GTK_ENTRY (entry.widget),
1490                                 entry.value.c_str ());
1491         }
1492     }
1493
1494     for (unsigned int j = 0; j < __key_conf_pages_num; j++) {
1495         for (unsigned int i = 0; __key_conf_pages[j].data[i].key; i++) {
1496             if (__key_conf_pages[j].data[i].widget) {
1497                 gtk_entry_set_text (
1498                     GTK_ENTRY (__key_conf_pages[j].data[i].widget),
1499                     __key_conf_pages[j].data[i].value.c_str ());
1500             }
1501         }
1502     }
1503     
1504     for (unsigned int i = 0; config_color_common[i].fg_key; i++) {
1505         ColorConfigData &entry = config_color_common[i];
1506         if (entry.widget) {
1507             scim_anthy_color_button_set_colors (SCIM_ANTHY_COLOR_BUTTON (entry.widget),
1508                                                 entry.fg_value, entry.bg_value);
1509         }
1510     }
1511
1512     gtk_option_menu_set_history
1513         (GTK_OPTION_MENU (__widget_key_categories_menu),
1514          KEY_CATEGORY_INDEX_ALL);
1515     GtkTreeView *treeview = GTK_TREE_VIEW (__widget_key_list_view);
1516     GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model (treeview));
1517     gtk_list_store_clear (store);
1518     for (unsigned int i = 0; i < __key_conf_pages_num; i++)
1519         append_key_bindings (treeview, i, NULL);
1520     gtk_widget_set_sensitive (__widget_key_filter, FALSE);
1521     gtk_widget_set_sensitive (__widget_key_filter_button, FALSE);
1522
1523     // setup option menu
1524     setup_key_theme_menu (GTK_OPTION_MENU (__widget_key_theme_menu));
1525 }
1526
1527 bool operator < (const StyleFile &left, const StyleFile &right)
1528 {
1529     if (const_cast<StyleFile&>(left).get_title() <
1530         const_cast<StyleFile&>(right).get_title())
1531     {
1532         return true;
1533     }
1534     return false;
1535 }
1536
1537 bool operator > (const StyleFile &left, const StyleFile &right)
1538 {
1539     if (const_cast<StyleFile&>(left).get_title() >
1540         const_cast<StyleFile&>(right).get_title())
1541     {
1542         return true;
1543     }
1544     return false;
1545 }
1546
1547 static void
1548 load_style_files (const char *dirname)
1549 {
1550     GDir *dir;
1551     GError *error = NULL;
1552     const gchar *entry;
1553
1554     // load system wide style files
1555     dir = g_dir_open (dirname, 0, &error);
1556     if (error)
1557     {
1558         //g_warning ("%s", error->message);
1559         g_error_free (error);
1560     }
1561
1562     if (dir) {
1563         while ((entry = g_dir_read_name (dir)))
1564         {
1565             String file = dirname;
1566             file += SCIM_PATH_DELIM_STRING;
1567             file += entry;
1568
1569             // FIXME! check duplicates
1570             __style_list.push_back (StyleFile ());
1571             StyleFile &style = __style_list.back ();
1572             bool success = style.load (file.c_str ());
1573             if (!success)
1574                 __style_list.pop_back ();
1575         }
1576         g_dir_close (dir);
1577     }
1578     std::sort(__style_list.begin(), __style_list.end());
1579 }
1580
1581 static void
1582 load_config (const ConfigPointer &config)
1583 {
1584     if (config.null ())
1585         return;
1586
1587     __style_list.clear ();
1588
1589     load_style_files (SCIM_ANTHY_STYLEDIR);
1590     load_style_files (__user_style_dir_name.c_str ());
1591
1592     __user_style_file.load (__user_style_file_name.c_str ());
1593
1594     __config_key_theme
1595         = config->read (String (SCIM_ANTHY_CONFIG_KEY_THEME),
1596                         String (SCIM_ANTHY_CONFIG_KEY_THEME_DEFAULT));
1597     __config_key_theme_file
1598         = config->read (String (SCIM_ANTHY_CONFIG_KEY_THEME_FILE),
1599                         String (SCIM_ANTHY_CONFIG_KEY_THEME_FILE_DEFAULT));
1600
1601     for (unsigned int i = 0; config_bool_common[i].key; i++) {
1602         BoolConfigData &entry = config_bool_common[i];
1603         entry.value = config->read (String (entry.key), entry.value);
1604     }
1605
1606     for (unsigned int i = 0; config_int_common[i].key; i++) {
1607         IntConfigData &entry = config_int_common[i];
1608         entry.value = config->read (String (entry.key), entry.value);
1609     }
1610
1611     for (unsigned int i = 0; config_string_common[i].key; i++) {
1612         StringConfigData &entry = config_string_common[i];
1613         entry.value = config->read (String (entry.key), entry.value);
1614     }
1615
1616     for (unsigned int j = 0; j < __key_conf_pages_num; j++) {
1617         for (unsigned int i = 0; __key_conf_pages[j].data[i].key; i++) {
1618             __key_conf_pages[j].data[i].value =
1619                 config->read (String (__key_conf_pages[j].data[i].key),
1620                               __key_conf_pages[j].data[i].value);
1621         }
1622     }
1623
1624     for (unsigned int i = 0; config_color_common[i].fg_key; i++) {
1625         ColorConfigData &entry = config_color_common[i];
1626         entry.fg_value = config->read (String (entry.fg_key), entry.fg_value);
1627         entry.bg_value = config->read (String (entry.bg_key), entry.bg_value);
1628     }
1629
1630     romaji_page_load_config (config);
1631     kana_page_load_config (config);
1632
1633     setup_widget_value ();
1634
1635     for (unsigned int i = 0; config_bool_common[i].key; i++)
1636         config_bool_common[i].changed = false;
1637
1638     for (unsigned int i = 0; config_int_common[i].key; i++)
1639         config_int_common[i].changed = false;
1640
1641     for (unsigned int i = 0; config_string_common[i].key; i++)
1642         config_string_common[i].changed = false;
1643
1644     for (unsigned int j = 0; j < __key_conf_pages_num; j++) {
1645         for (unsigned int i = 0; __key_conf_pages[j].data[i].key; i++)
1646             __key_conf_pages[j].data[i].changed = false;
1647     }
1648
1649     for (unsigned int i = 0; config_color_common[i].fg_key; i++)
1650         config_color_common[i].changed = false;
1651
1652     __config_changed = false;
1653 }
1654
1655 static void
1656 save_config (const ConfigPointer &config)
1657 {
1658     if (config.null ())
1659         return;
1660
1661     __config_key_theme
1662         = config->write (String (SCIM_ANTHY_CONFIG_KEY_THEME),
1663                          String (__config_key_theme));
1664     __config_key_theme_file
1665         = config->write (String (SCIM_ANTHY_CONFIG_KEY_THEME_FILE),
1666                          String (__config_key_theme_file));
1667
1668     for (unsigned int i = 0; config_bool_common[i].key; i++) {
1669         BoolConfigData &entry = config_bool_common[i];
1670         if (entry.changed)
1671             entry.value = config->write (String (entry.key), entry.value);
1672         entry.changed = false;
1673     }
1674
1675     for (unsigned int i = 0; config_int_common[i].key; i++) {
1676         IntConfigData &entry = config_int_common[i];
1677         if (entry.changed)
1678             entry.value = config->write (String (entry.key), entry.value);
1679         entry.changed = false;
1680     }
1681
1682     for (unsigned int i = 0; config_string_common[i].key; i++) {
1683         StringConfigData &entry = config_string_common[i];
1684         if (entry.changed)
1685             entry.value = config->write (String (entry.key), entry.value);
1686         entry.changed = false;
1687     }
1688
1689     for (unsigned int j = 0; j < __key_conf_pages_num; j++) {
1690         for (unsigned int i = 0; __key_conf_pages[j].data[i].key; i++) {
1691             if (__key_conf_pages[j].data[i].changed)
1692                 config->write (String (__key_conf_pages[j].data[i].key),
1693                                String (__key_conf_pages[j].data[i].value));
1694             __key_conf_pages[j].data[i].changed = false;
1695         }
1696     }
1697
1698     for (unsigned int i = 0; config_color_common[i].fg_key; i++) {
1699         ColorConfigData &entry = config_color_common[i];
1700         if (entry.changed) {
1701             entry.fg_value = config->write (String (entry.fg_key),
1702                                             entry.fg_value);
1703             entry.bg_value = config->write (String (entry.bg_key),
1704                                             entry.bg_value);
1705         }
1706         entry.changed = false;
1707     }
1708
1709     __config_changed = false;
1710
1711     if (__style_changed) {
1712         scim_make_dir (__user_config_dir_name);
1713         __user_style_file.save (__user_style_file_name.c_str ());
1714         __style_changed = false;
1715     }
1716
1717     romaji_page_save_config (config);
1718     kana_page_save_config (config);
1719 }
1720
1721 static bool
1722 query_changed (void)
1723 {
1724     return
1725         __config_changed ||
1726         __style_changed ||
1727         romaji_page_query_changed () ||
1728         kana_page_query_changed ();
1729 }
1730
1731
1732 static void
1733 on_default_toggle_button_toggled (GtkToggleButton *togglebutton,
1734                                   gpointer         user_data)
1735 {
1736     BoolConfigData *entry = static_cast<BoolConfigData*> (user_data);
1737
1738     if (entry) {
1739         entry->value = gtk_toggle_button_get_active (togglebutton);
1740         entry->changed = true;
1741         __config_changed = true;
1742     }
1743 }
1744
1745 static void
1746 on_default_spin_button_changed (GtkSpinButton *spinbutton, gpointer user_data)
1747 {
1748     IntConfigData *entry = static_cast<IntConfigData*> (user_data);
1749
1750     if (entry) {
1751         entry->value = static_cast<int> (gtk_spin_button_get_value (spinbutton));
1752         entry->changed = true;
1753         __config_changed = true;
1754     }
1755 }
1756
1757 static void
1758 on_default_editable_changed (GtkEditable *editable,
1759                              gpointer     user_data)
1760 {
1761     StringConfigData *entry = static_cast <StringConfigData*> (user_data);
1762
1763     if (entry) {
1764         entry->value = String (gtk_entry_get_text (GTK_ENTRY (editable)));
1765         entry->changed = true;
1766         __config_changed = true;
1767     }
1768 }
1769
1770 static void
1771 on_default_key_selection_clicked (GtkButton *button,
1772                                   gpointer   user_data)
1773 {
1774     StringConfigData *data = static_cast <StringConfigData*> (user_data);
1775
1776     if (data) {
1777         GtkWidget *dialog = scim_key_selection_dialog_new (_(data->title));
1778         gint result;
1779
1780         scim_key_selection_dialog_set_keys (
1781             SCIM_KEY_SELECTION_DIALOG (dialog),
1782             gtk_entry_get_text (GTK_ENTRY (data->widget)));
1783
1784         result = gtk_dialog_run (GTK_DIALOG (dialog));
1785
1786         if (result == GTK_RESPONSE_OK) {
1787             const gchar *keys = scim_key_selection_dialog_get_keys (
1788                             SCIM_KEY_SELECTION_DIALOG (dialog));
1789
1790             if (!keys) keys = "";
1791
1792             if (strcmp (keys, gtk_entry_get_text (GTK_ENTRY (data->widget))))
1793                 gtk_entry_set_text (GTK_ENTRY (data->widget), keys);
1794         }
1795
1796         gtk_widget_destroy (dialog);
1797     }
1798 }
1799
1800 static void
1801 on_default_combo_changed (GtkEditable *editable,
1802                           gpointer user_data)
1803 {
1804     StringConfigData *entry = static_cast<StringConfigData*> (user_data);
1805     ComboConfigCandidate *data = static_cast<ComboConfigCandidate*>
1806         (g_object_get_data (G_OBJECT (editable),
1807                             DATA_POINTER_KEY));
1808
1809     if (!entry) return;
1810     if (!data) return;
1811
1812     const char *label =  gtk_entry_get_text (GTK_ENTRY (editable));
1813
1814     for (unsigned int i = 0; data[i].label; i++) {
1815         if (label && !strcmp (_(data[i].label), label)) {
1816             entry->value     = data[i].data;
1817             entry->changed   = true;
1818             __config_changed = true;
1819             break;
1820         }
1821     }
1822 }
1823
1824 static void
1825 on_default_option_menu_changed (GtkOptionMenu *omenu, gpointer user_data)
1826 {
1827     StringConfigData *entry = static_cast<StringConfigData*> (user_data);
1828     ComboConfigCandidate *data = static_cast<ComboConfigCandidate*>
1829         (g_object_get_data (G_OBJECT (omenu),
1830                             DATA_POINTER_KEY));
1831
1832     if (!entry) return;
1833     if (!data) return;
1834
1835     for (int i = 0; data[i].label; i++) {
1836         if (i == gtk_option_menu_get_history (omenu)) {
1837             entry->value     = data[i].data;
1838             entry->changed   = true;
1839             __config_changed = true;
1840             break;
1841         }
1842     }
1843 }
1844
1845 static void
1846 on_preedit_style_menu_changed (GtkOptionMenu *omenu, gpointer user_data)
1847 {
1848     GtkWidget *widget = GTK_WIDGET (user_data);
1849
1850     gint idx = gtk_option_menu_get_history (omenu);
1851
1852     for (int i = 0; preedit_style[i].data && i <= idx; i++) {
1853         if (i == idx &&
1854             (!strcmp (preedit_style[i].data, "Color") ||
1855              !strcmp (preedit_style[i].data, "FGColor") ||
1856              !strcmp (preedit_style[i].data, "BGColor")))
1857         {
1858             gtk_widget_set_sensitive (widget, TRUE);
1859             return;
1860         }
1861     }
1862
1863     gtk_widget_set_sensitive (widget, FALSE);
1864 }
1865
1866 static void
1867 on_dict_menu_label_toggled (GtkToggleButton *togglebutton,
1868                             gpointer         user_data)
1869 {
1870     bool active = gtk_toggle_button_get_active (togglebutton);
1871
1872     BoolConfigData *entry;
1873     entry = find_bool_config_entry (SCIM_ANTHY_CONFIG_SHOW_DICT_ADMIN_LABEL);
1874     if (entry->widget)
1875         gtk_widget_set_sensitive (GTK_WIDGET (entry->widget), active);
1876     entry = find_bool_config_entry (SCIM_ANTHY_CONFIG_SHOW_ADD_WORD_LABEL);
1877     if (entry->widget)
1878         gtk_widget_set_sensitive (GTK_WIDGET (entry->widget), active);
1879 }
1880
1881 static void
1882 on_key_category_menu_changed (GtkOptionMenu *omenu, gpointer user_data)
1883 {
1884     GtkTreeView *treeview = GTK_TREE_VIEW (user_data);
1885     GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model (treeview));
1886
1887     gtk_list_store_clear (store);
1888
1889     gint idx = gtk_option_menu_get_history (omenu);
1890
1891     bool use_filter = false;
1892
1893     if (idx >= 0 && idx < (gint) __key_conf_pages_num) {
1894         append_key_bindings (treeview, idx, NULL);
1895
1896     } else if (idx == KEY_CATEGORY_INDEX_SEARCH_BY_KEY) {
1897         // search by key
1898         use_filter = true;
1899         const char *str = gtk_entry_get_text (GTK_ENTRY (__widget_key_filter));
1900         for (unsigned int i = 0; i < __key_conf_pages_num; i++)
1901             append_key_bindings (treeview, i, str);
1902
1903     } else if (idx == KEY_CATEGORY_INDEX_ALL) {
1904         // all
1905         for (unsigned int i = 0; i < __key_conf_pages_num; i++)
1906             append_key_bindings (treeview, i, NULL);
1907     }
1908
1909     gtk_widget_set_sensitive (__widget_key_filter,        use_filter);
1910     gtk_widget_set_sensitive (__widget_key_filter_button, use_filter);
1911 }
1912
1913 static void
1914 on_key_theme_menu_changed (GtkOptionMenu *omenu, gpointer user_data)
1915 {
1916     gint idx = gtk_option_menu_get_history (omenu);
1917     GtkWidget *menu = gtk_option_menu_get_menu (omenu);
1918     GList *list = gtk_container_get_children (GTK_CONTAINER (menu));
1919     GtkWidget *menuitem = GTK_WIDGET (g_list_nth_data (list, idx));
1920
1921     if (!menuitem)
1922         return;
1923
1924     gint theme_idx = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menuitem),
1925                                                          INDEX_KEY));
1926
1927     // clear all key bindings
1928     if (idx != 0) {
1929         for (unsigned int j = 0; j < __key_conf_pages_num; j++) {
1930             for (unsigned int i = 0; __key_conf_pages[j].data[i].key; i++) {
1931                 __key_conf_pages[j].data[i].value = "";
1932                 __key_conf_pages[j].data[i].changed = true;
1933             }
1934         }
1935     }
1936
1937     // set new key bindings
1938     if (idx == KEY_THEME_INDEX_USER_DEFINED) {
1939         __config_key_theme      = String ("User defined");
1940         __config_key_theme_file = String (""); //__user_style_file.get_file_name ();
1941
1942     } else if (idx == KEY_THEME_INDEX_DEFAULT) {
1943         for (unsigned int j = 0; j < __key_conf_pages_num; j++) {
1944             for (unsigned int i = 0; __key_conf_pages[j].data[i].key; i++) {
1945                 __key_conf_pages[j].data[i].value
1946                     = __key_conf_pages[j].data[i].default_value;
1947             }
1948         }
1949         __config_key_theme      = String ("Default");
1950         __config_key_theme_file = String ("");
1951
1952     } else if (theme_idx >= 0) {
1953         // reset key bindings
1954         StyleLines lines;
1955         StyleLines::iterator it;
1956         __style_list[theme_idx].get_entry_list (lines, "KeyBindings");
1957         for (it = lines.begin (); it != lines.end (); it++) {
1958             if (it->get_type () != SCIM_ANTHY_STYLE_LINE_KEY)
1959                 continue;
1960             String key, fullkey;
1961             it->get_key (key);
1962             fullkey = String ("/IMEngine/Anthy/") + key;
1963             StringConfigData *entry = find_key_config_entry (fullkey.c_str ());
1964             if (entry) {
1965                 it->get_value (entry->value);
1966                 entry->changed = true;
1967             } else {
1968                 std::cerr << "No entry for : " << key << std::endl;
1969             }
1970         }
1971         __config_key_theme      = __style_list[theme_idx].get_title ();
1972         __config_key_theme_file = __style_list[theme_idx].get_file_name ();
1973     }
1974
1975     // sync widgets
1976     if (idx != KEY_THEME_INDEX_USER_DEFINED) {
1977         gtk_option_menu_set_history
1978             (GTK_OPTION_MENU (__widget_key_categories_menu),
1979              KEY_CATEGORY_INDEX_ALL);
1980         gtk_widget_set_sensitive (__widget_key_filter, FALSE);
1981         gtk_widget_set_sensitive (__widget_key_filter_button, FALSE);
1982         GtkTreeModel *model;
1983         model = gtk_tree_view_get_model (
1984             GTK_TREE_VIEW (__widget_key_list_view));
1985         gtk_list_store_clear (GTK_LIST_STORE (model));
1986 #if 0
1987         append_key_bindings (GTK_TREE_VIEW (__widget_key_list_view),
1988                              KEY_CATEGORY_INDEX_ALL, NULL);
1989 #else
1990         for (unsigned int i = 0; i < __key_conf_pages_num; i++)
1991             append_key_bindings (GTK_TREE_VIEW (__widget_key_list_view),
1992                                  i, NULL);
1993 #endif
1994     }
1995
1996     __config_changed = true;
1997 }
1998
1999 static void
2000 on_key_filter_selection_clicked (GtkButton *button,
2001                                  gpointer   user_data)
2002 {
2003     GtkEntry *entry = static_cast <GtkEntry*> (user_data);
2004
2005     if (entry) {
2006         GtkWidget *dialog = scim_key_selection_dialog_new (_("Set key filter"));
2007         gint result;
2008
2009         scim_key_selection_dialog_set_keys (
2010             SCIM_KEY_SELECTION_DIALOG (dialog),
2011             gtk_entry_get_text (entry));
2012
2013         result = gtk_dialog_run (GTK_DIALOG (dialog));
2014
2015         if (result == GTK_RESPONSE_OK) {
2016             const gchar *keys = scim_key_selection_dialog_get_keys (
2017                 SCIM_KEY_SELECTION_DIALOG (dialog));
2018
2019             if (!keys) keys = "";
2020
2021             if (strcmp (keys, gtk_entry_get_text (entry)))
2022                 gtk_entry_set_text (entry, keys);
2023
2024             GtkTreeModel *model;
2025             model = gtk_tree_view_get_model (
2026                 GTK_TREE_VIEW (__widget_key_list_view));
2027             gtk_list_store_clear (GTK_LIST_STORE (model));
2028             for (unsigned int i = 0; i < __key_conf_pages_num; i++)
2029                 append_key_bindings (GTK_TREE_VIEW (__widget_key_list_view),
2030                                      i, keys);
2031         }
2032
2033         gtk_widget_destroy (dialog);
2034     }
2035 }
2036
2037 static gboolean
2038 on_key_list_view_key_press (GtkWidget *widget, GdkEventKey *event,
2039                             gpointer user_data)
2040 {
2041     GtkTreeView *treeview = GTK_TREE_VIEW (widget);
2042
2043     switch (event->keyval) {
2044     case GDK_Return:
2045     case GDK_KP_Enter:
2046         key_list_view_popup_key_selection (treeview);
2047         break;
2048     }
2049
2050     return FALSE;
2051 }
2052
2053 static gboolean
2054 on_key_list_view_button_press (GtkWidget *widget, GdkEventButton *event,
2055                                gpointer user_data)
2056 {
2057     GtkTreeView *treeview = GTK_TREE_VIEW (widget);
2058
2059     if (event->type == GDK_2BUTTON_PRESS) {
2060         key_list_view_popup_key_selection (treeview);
2061         return TRUE;
2062     }
2063
2064     return FALSE;
2065 }
2066
2067 static void
2068 on_key_list_selection_changed (GtkTreeSelection *selection, gpointer data)
2069 {
2070     GtkTreeModel *model = NULL;
2071     GtkTreeIter iter;
2072
2073     gboolean selected;
2074
2075     selected = gtk_tree_selection_get_selected (selection, &model, &iter);
2076
2077     if (__widget_choose_keys_button) {
2078         if (selected) {
2079             gtk_widget_set_sensitive (__widget_choose_keys_button, true);
2080         } else {
2081             gtk_widget_set_sensitive (__widget_choose_keys_button, false);
2082         }
2083     }
2084 }
2085
2086 static void
2087 on_choose_keys_button_clicked (GtkWidget *button, gpointer data)
2088 {
2089     GtkTreeView *treeview = GTK_TREE_VIEW (data);
2090     key_list_view_popup_key_selection (treeview);
2091 }
2092
2093 static void
2094 on_dict_launch_button_clicked (GtkButton *button, gpointer user_data)
2095 {
2096     StringConfigData *entry = static_cast <StringConfigData*> (user_data);
2097
2098     if (entry->widget) {
2099         const char *command = gtk_entry_get_text (GTK_ENTRY (entry->widget));
2100         if (command && *command)
2101             util_launch_program (command);
2102     }
2103 }
2104
2105 static void
2106 on_color_button_changed (ScimAnthyColorButton *button,
2107                          gpointer         user_data)
2108 {
2109     ColorConfigData *entry = static_cast <ColorConfigData*> (user_data);
2110
2111     if (entry->widget) {
2112         scim_anthy_color_button_get_colors (button, &entry->fg_value, &entry->bg_value);
2113         entry->changed = true;
2114         __config_changed = true;
2115     }
2116 }
2117
2118 }
2119 /*
2120 vi:ts=4:nowrap:ai:expandtab
2121 */