Tizen 2.1 base
[framework/uifw/ise-engine-anthy.git] / src / scim_anthy_setup_kana.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 #ifdef HAVE_CONFIG_H
22   #include <config.h>
23 #endif
24
25 #include <gtk/gtk.h>
26 #include <gdk/gdkkeysyms.h>
27
28 #define Uses_SCIM_CONFIG_BASE
29 #define Uses_SCIM_EVENT
30 #define SCIM_ANTHY_USE_GTK
31 #include <scim.h>
32 //#include "scim_anthy_setup_kana.h"
33 #include "scim_anthy_intl.h"
34 #include "scim_anthy_style_file.h"
35 #include "scim_anthy_prefs.h"
36 #include "scim_anthy_default_tables.h"
37 #include "scim_anthy_setup.h"
38 #include "scim_anthy_table_editor.h"
39
40 using namespace scim;
41
42 namespace scim_anthy {
43
44 #define INDEX_KEY "scim-anthy::Index"
45 static const char * const __kana_fund_table   = "KanaTable/FundamentalTable";
46 static const char * const __nicola_fund_table = "NICOLATable/FundamentalTable";
47
48 static const int KANA_LAYOUT_INDEX_USER_DEFINED = 0;
49 static const int KANA_LAYOUT_INDEX_DEFAULT      = 1;
50
51 static const int NICOLA_LAYOUT_INDEX_USER_DEFINED = 0;
52 static const int NICOLA_LAYOUT_INDEX_DEFAULT      = 1;
53
54 // Internal data declaration.
55 static GtkWidget   * __widget_kana_layout_menu     = NULL;
56 static GtkWidget   * __widget_kana_layout_menu2    = NULL;
57 static GtkWidget   * __widget_nicola_layout_menu   = NULL;
58 static GtkWidget   * __widget_nicola_layout_menu2  = NULL;
59
60 static String __config_kana_layout_file   = SCIM_ANTHY_CONFIG_KANA_LAYOUT_FILE_DEFAULT;
61 static String __config_nicola_layout_file = SCIM_ANTHY_CONFIG_NICOLA_LAYOUT_FILE_DEFAULT;
62
63
64 static GtkWidget *create_kana_window                 (GtkWindow            *parent);
65 static GtkWidget *create_nicola_window               (GtkWindow            *parent);
66
67 static void     setup_kana_page                      (void);
68 static void     setup_kana_layout_menu               (GtkOptionMenu        *omenu);
69 static void     setup_nicola_layout_menu             (GtkOptionMenu        *omenu);
70 static void     setup_kana_window_value              (ScimAnthyTableEditor *editor);
71 static void     setup_nicola_window_value            (ScimAnthyTableEditor *editor);
72
73 static bool     load_kana_layout                     (void);
74 static bool     load_nicola_layout                   (void);
75
76 static void     on_kana_layout_menu_changed          (GtkOptionMenu        *omenu,
77                                                       gpointer              user_data);
78 static void     on_kana_customize_button_clicked     (GtkWidget            *button,
79                                                       gpointer              data);
80 static void     on_kana_table_editor_add_entry       (ScimAnthyTableEditor *editor,
81                                                       gpointer              data);
82 static void     on_kana_table_editor_added_entry     (ScimAnthyTableEditor *editor,
83                                                       gpointer              data);
84 static void     on_kana_table_editor_remove_entry    (ScimAnthyTableEditor *editor,
85                                                       gpointer              data);
86 static void     on_kana_table_editor_removed_entry   (ScimAnthyTableEditor *editor,
87                                                       gpointer              data);
88 static void     on_nicola_layout_menu_changed        (GtkOptionMenu        *omenu,
89                                                       gpointer              user_data);
90 static void     on_nicola_customize_button_clicked   (GtkWidget            *button,
91                                                       gpointer              data);
92 static void     on_nicola_table_editor_add_entry     (ScimAnthyTableEditor *editor,
93                                                       gpointer              data);
94 static void     on_nicola_table_editor_added_entry   (ScimAnthyTableEditor *editor,
95                                                       gpointer              data);
96 static void     on_nicola_table_editor_remove_entry  (ScimAnthyTableEditor *editor,
97                                                       gpointer              data);
98 static void     on_nicola_table_editor_removed_entry (ScimAnthyTableEditor *editor,
99                                                       gpointer              data);
100
101 GtkWidget *
102 kana_page_create_ui (void)
103 {
104     GtkWidget *vbox;
105
106     vbox = gtk_vbox_new (FALSE, 0);
107     gtk_widget_show (vbox);
108
109     // JIS Kana Layout
110     GtkWidget *hbox = gtk_hbox_new (FALSE, 0);
111     gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 4);
112     gtk_widget_show (hbox);
113
114     GtkWidget *label = gtk_label_new (_("<b>JIS Kana Layout</b>"));
115     gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
116     gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 4);
117     gtk_widget_show (label);
118
119     GtkWidget *alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
120     gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 8, 24, 0);
121     gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0);
122     gtk_widget_show (alignment);
123
124     /* kana table */
125     hbox = gtk_hbox_new (FALSE, 0);
126     gtk_container_set_border_width (GTK_CONTAINER (hbox), 4);
127     gtk_container_add (GTK_CONTAINER (alignment), hbox);
128     gtk_widget_show(hbox);
129
130     label = gtk_label_new_with_mnemonic (_("La_yout:"));
131     gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 2);
132     gtk_widget_show (label);
133
134     GtkWidget *omenu = gtk_option_menu_new ();
135     __widget_kana_layout_menu = omenu;
136     g_signal_connect (G_OBJECT (omenu), "changed",
137                       G_CALLBACK (on_kana_layout_menu_changed), NULL);
138     gtk_box_pack_start (GTK_BOX (hbox), omenu, FALSE, FALSE, 2);
139     gtk_widget_show (omenu);
140
141     gtk_label_set_mnemonic_widget (GTK_LABEL(label), omenu);
142
143     GtkWidget *button = gtk_button_new_with_mnemonic (_("_Customize..."));
144     g_signal_connect (G_OBJECT (button), "clicked",
145                       G_CALLBACK (on_kana_customize_button_clicked), NULL);
146     gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 2);
147     gtk_widget_show (button);
148
149
150     // Thumb Shift Layout
151     hbox = gtk_hbox_new (FALSE, 0);
152     gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 4);
153     gtk_widget_show (hbox);
154
155     label = gtk_label_new (_("<b>Thumb Shift Layout</b>"));
156     gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
157     gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 4);
158     gtk_widget_show (label);
159
160     alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
161     gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 24, 0);
162     gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0);
163     gtk_widget_show (alignment);
164
165     GtkWidget *vbox2 = gtk_vbox_new (FALSE, 0);
166     gtk_container_add (GTK_CONTAINER (alignment), vbox2);
167     gtk_widget_show (vbox2);
168
169     /* nicola table */
170     hbox = gtk_hbox_new (FALSE, 0);
171     gtk_container_set_border_width (GTK_CONTAINER (hbox), 4);
172     gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, FALSE, 0);
173     gtk_widget_show(hbox);
174
175     label = gtk_label_new_with_mnemonic (_("La_yout:"));
176     gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 2);
177     gtk_widget_show (label);
178
179     omenu = gtk_option_menu_new ();
180     __widget_nicola_layout_menu = omenu;
181     g_signal_connect (G_OBJECT (omenu), "changed",
182                       G_CALLBACK (on_nicola_layout_menu_changed), NULL);
183     gtk_box_pack_start (GTK_BOX (hbox), omenu, FALSE, FALSE, 2);
184     gtk_widget_show (omenu);
185
186     gtk_label_set_mnemonic_widget (GTK_LABEL(label), omenu);
187
188     button = gtk_button_new_with_mnemonic (_("_Customize..."));
189     g_signal_connect (G_OBJECT (button), "clicked",
190                       G_CALLBACK (on_nicola_customize_button_clicked), NULL);
191     gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 2);
192     gtk_widget_show (button);
193
194     /* thumb shift keys */
195     hbox = gtk_hbox_new (FALSE, 0);
196     gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, FALSE, 0);
197     gtk_widget_show (hbox);
198
199     GtkWidget *table = gtk_table_new (2, 2, FALSE);
200     gtk_box_pack_start (GTK_BOX (vbox2), table, FALSE, FALSE, 4);
201     gtk_widget_show (table);
202
203     // left
204     GtkWidget *widget = create_entry (SCIM_ANTHY_CONFIG_LEFT_THUMB_SHIFT_KEY,
205                                       GTK_TABLE (table), 0);
206     gtk_entry_set_editable (GTK_ENTRY (widget), FALSE);
207     widget = create_key_select_button (SCIM_ANTHY_CONFIG_LEFT_THUMB_SHIFT_KEY,
208                                        GTK_TABLE (table), 0);
209
210     // right
211     widget = create_entry (SCIM_ANTHY_CONFIG_RIGHT_THUMB_SHIFT_KEY,
212                            GTK_TABLE (table), 1);
213     gtk_entry_set_editable (GTK_ENTRY (widget), FALSE);
214     widget = create_key_select_button (SCIM_ANTHY_CONFIG_RIGHT_THUMB_SHIFT_KEY,
215                                        GTK_TABLE (table), 1);
216
217     /* NICOLA time */
218     create_spin_button (SCIM_ANTHY_CONFIG_NICOLA_TIME,
219                         GTK_TABLE (table), 3);
220
221     // prepare
222     setup_kana_page ();
223
224     return vbox;
225 }
226
227 void
228 kana_page_load_config (const ConfigPointer &config)
229 {
230     __config_kana_layout_file
231         = config->read (String (SCIM_ANTHY_CONFIG_KANA_LAYOUT_FILE),
232                         String (SCIM_ANTHY_CONFIG_KANA_LAYOUT_FILE_DEFAULT));
233     __config_nicola_layout_file
234         = config->read (String (SCIM_ANTHY_CONFIG_NICOLA_LAYOUT_FILE),
235                         String (SCIM_ANTHY_CONFIG_NICOLA_LAYOUT_FILE_DEFAULT));
236     setup_kana_page ();
237 }
238
239 void
240 kana_page_save_config (const ConfigPointer &config)
241 {
242     __config_kana_layout_file
243         = config->write (String (SCIM_ANTHY_CONFIG_KANA_LAYOUT_FILE),
244                          String (__config_kana_layout_file));
245     __config_nicola_layout_file
246         = config->write (String (SCIM_ANTHY_CONFIG_NICOLA_LAYOUT_FILE),
247                          String (__config_nicola_layout_file));
248 }
249
250 bool
251 kana_page_query_changed (void)
252 {
253     return __config_changed || __style_changed;
254 }
255
256
257 static GtkWidget *
258 create_kana_window (GtkWindow *parent)
259 {
260     GtkWidget *dialog = scim_anthy_table_editor_new ();
261     const char *titles[3];
262     titles[0] = _("Key");
263     titles[1] = _("Result");
264     titles[2] = NULL;
265     scim_anthy_table_editor_set_columns (SCIM_ANTHY_TABLE_EDITOR (dialog),
266                                          titles);
267     gtk_window_set_transient_for (GTK_WINDOW (dialog),
268                                   GTK_WINDOW (parent));
269     gtk_window_set_title (GTK_WINDOW (dialog),
270                           _("Customize kana layout table"));
271
272     // option menu area
273     GtkWidget *hbox = gtk_hbox_new (FALSE, 0);
274     gtk_container_set_border_width (GTK_CONTAINER (hbox), 4);
275     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox,
276                         FALSE, FALSE, 0);
277     gtk_box_reorder_child (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, 0);
278     gtk_widget_show(hbox);
279
280     GtkWidget *label = gtk_label_new_with_mnemonic (_("Layout _table:"));
281     gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 2);
282     gtk_widget_show (label);
283
284     GtkWidget *omenu = gtk_option_menu_new ();
285     __widget_kana_layout_menu2 = omenu;
286     g_object_add_weak_pointer (G_OBJECT (omenu),
287                                (gpointer*) &__widget_kana_layout_menu2);
288     gtk_box_pack_start (GTK_BOX (hbox), omenu, FALSE, FALSE, 2);
289     setup_kana_layout_menu (GTK_OPTION_MENU (omenu));
290     gtk_option_menu_set_history
291         (GTK_OPTION_MENU (omenu),
292          gtk_option_menu_get_history (
293              GTK_OPTION_MENU (__widget_kana_layout_menu)));
294     gtk_widget_show (omenu);
295
296     gtk_label_set_mnemonic_widget (GTK_LABEL(label), omenu);
297
298 #if 0
299     GtkWidget *button = gtk_button_new_with_mnemonic ("Save _as...");
300     gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 2);
301     gtk_widget_show (button);
302 #endif
303
304     // set data and connect signals
305     setup_kana_window_value (SCIM_ANTHY_TABLE_EDITOR (dialog));
306     g_signal_connect (G_OBJECT (omenu), "changed",
307                       G_CALLBACK (on_kana_layout_menu_changed),
308                       dialog);
309     g_signal_connect (G_OBJECT (dialog), "add-entry",
310                       G_CALLBACK (on_kana_table_editor_add_entry),
311                       NULL);
312     g_signal_connect (G_OBJECT (dialog), "remove-entry",
313                       G_CALLBACK (on_kana_table_editor_remove_entry),
314                       NULL);
315     g_signal_connect_after (G_OBJECT (dialog), "add-entry",
316                             G_CALLBACK (on_kana_table_editor_added_entry),
317                             NULL);
318     g_signal_connect_after (G_OBJECT (dialog), "remove-entry",
319                             G_CALLBACK (on_kana_table_editor_removed_entry),
320                             NULL);
321
322     return dialog;
323 }
324
325
326 static GtkWidget *
327 create_nicola_window (GtkWindow *parent)
328 {
329     GtkWidget *dialog = scim_anthy_table_editor_new ();
330     gtk_window_set_default_size (GTK_WINDOW (dialog), 450, 350);
331     const char *titles[5];
332     titles[0] = _("Key");
333     titles[1] = _("Single press");
334     titles[2] = _("Left thumb shift");
335     titles[3] = _("Right thumb shift");
336     titles[4] = NULL;
337     scim_anthy_table_editor_set_columns (SCIM_ANTHY_TABLE_EDITOR (dialog),
338                                          titles);
339     gtk_window_set_transient_for (GTK_WINDOW (dialog),
340                                   GTK_WINDOW (parent));
341     gtk_window_set_title (GTK_WINDOW (dialog),
342                           _("Customize thumb shift layout table"));
343
344     // option menu area
345     GtkWidget *hbox = gtk_hbox_new (FALSE, 0);
346     gtk_container_set_border_width (GTK_CONTAINER (hbox), 4);
347     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox,
348                         FALSE, FALSE, 0);
349     gtk_box_reorder_child (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, 0);
350     gtk_widget_show(hbox);
351
352     GtkWidget *label = gtk_label_new_with_mnemonic (_("Layout _table:"));
353     gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 2);
354     gtk_widget_show (label);
355
356     GtkWidget *omenu = gtk_option_menu_new ();
357     __widget_nicola_layout_menu2 = omenu;
358     g_object_add_weak_pointer (G_OBJECT (omenu),
359                                (gpointer*) &__widget_nicola_layout_menu2);
360     gtk_box_pack_start (GTK_BOX (hbox), omenu, FALSE, FALSE, 2);
361     setup_nicola_layout_menu (GTK_OPTION_MENU (omenu));
362     gtk_option_menu_set_history
363         (GTK_OPTION_MENU (omenu),
364          gtk_option_menu_get_history (
365              GTK_OPTION_MENU (__widget_nicola_layout_menu)));
366     gtk_widget_show (omenu);
367
368     gtk_label_set_mnemonic_widget (GTK_LABEL(label), omenu);
369
370 #if 0
371     GtkWidget *button = gtk_button_new_with_mnemonic ("Save _as...");
372     gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 2);
373     gtk_widget_show (button);
374 #endif
375
376     // set data and connect signals
377     setup_nicola_window_value (SCIM_ANTHY_TABLE_EDITOR (dialog));
378     g_signal_connect (G_OBJECT (omenu), "changed",
379                       G_CALLBACK (on_nicola_layout_menu_changed),
380                       dialog);
381     g_signal_connect (G_OBJECT (dialog), "add-entry",
382                       G_CALLBACK (on_nicola_table_editor_add_entry),
383                       NULL);
384     g_signal_connect (G_OBJECT (dialog), "remove-entry",
385                       G_CALLBACK (on_nicola_table_editor_remove_entry),
386                       NULL);
387     g_signal_connect_after (G_OBJECT (dialog), "add-entry",
388                             G_CALLBACK (on_nicola_table_editor_added_entry),
389                             NULL);
390     g_signal_connect_after (G_OBJECT (dialog), "remove-entry",
391                             G_CALLBACK (on_nicola_table_editor_removed_entry),
392                             NULL);
393
394     return dialog;
395 }
396
397 static void
398 setup_kana_page (void)
399 {
400     setup_kana_layout_menu (GTK_OPTION_MENU (__widget_kana_layout_menu));
401     setup_nicola_layout_menu (GTK_OPTION_MENU (__widget_nicola_layout_menu));
402 }
403
404 static void
405 setup_kana_layout_menu (GtkOptionMenu *omenu)
406 {
407     GtkWidget *menu = gtk_menu_new ();
408     gtk_option_menu_set_menu (GTK_OPTION_MENU (omenu),
409                               menu);
410     gtk_widget_show (menu);
411
412     // create menu items
413     GtkWidget *menuitem = gtk_menu_item_new_with_label (_("User defined"));
414     gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
415
416     menuitem = gtk_menu_item_new_with_label (_("Default"));
417     gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
418     gtk_widget_show (menuitem);
419
420     StyleFiles::iterator it;
421     unsigned int i;
422     for (i = 0, it = __style_list.begin ();
423          it != __style_list.end ();
424          i++, it++)
425     {
426         StyleLines section;
427         if (!it->get_entry_list (section, __kana_fund_table))
428             continue;
429
430         menuitem = gtk_menu_item_new_with_label (_(it->get_title().c_str()));
431         g_object_set_data (G_OBJECT (menuitem),
432                            INDEX_KEY, GINT_TO_POINTER (i));
433         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
434         gtk_widget_show (menuitem);
435     }
436
437     // set default value
438     g_signal_handlers_block_by_func (
439         G_OBJECT (omenu),
440         (gpointer) (on_kana_layout_menu_changed),
441         NULL);
442
443     gtk_option_menu_set_history (GTK_OPTION_MENU (omenu),
444                                  KANA_LAYOUT_INDEX_DEFAULT);
445
446     if (__config_kana_layout_file == __user_style_file.get_file_name ()) {
447         gtk_option_menu_set_history (GTK_OPTION_MENU (omenu),
448                                      KANA_LAYOUT_INDEX_USER_DEFINED);
449
450     } else {
451         GList *node, *list = gtk_container_get_children (GTK_CONTAINER (menu));
452         for (i = 2, node = g_list_next (g_list_next (list));
453              node;
454              i++, node = g_list_next (node))
455         {
456             gint idx = GPOINTER_TO_INT (
457                 g_object_get_data (G_OBJECT (node->data), INDEX_KEY));
458             if (__style_list[idx].get_file_name () == __config_kana_layout_file) {
459                 gtk_option_menu_set_history (GTK_OPTION_MENU (omenu), i);
460                 break;
461             }
462         }
463     }
464
465     g_signal_handlers_unblock_by_func (
466         G_OBJECT (omenu),
467         (gpointer) (on_kana_layout_menu_changed),
468         NULL);
469 }
470
471 static void
472 setup_nicola_layout_menu (GtkOptionMenu *omenu)
473 {
474     GtkWidget *menu = gtk_menu_new ();
475     gtk_option_menu_set_menu (GTK_OPTION_MENU (omenu),
476                               menu);
477     gtk_widget_show (menu);
478
479     // create menu items
480     GtkWidget *menuitem = gtk_menu_item_new_with_label (_("User defined"));
481     gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
482
483     menuitem = gtk_menu_item_new_with_label (_("Default"));
484     gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
485     gtk_widget_show (menuitem);
486
487     StyleFiles::iterator it;
488     unsigned int i;
489     for (i = 0, it = __style_list.begin ();
490          it != __style_list.end ();
491          i++, it++)
492     {
493         StyleLines section;
494         if (!it->get_entry_list (section, __nicola_fund_table))
495             continue;
496
497         menuitem = gtk_menu_item_new_with_label (_(it->get_title().c_str()));
498         g_object_set_data (G_OBJECT (menuitem),
499                            INDEX_KEY, GINT_TO_POINTER (i));
500         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
501         gtk_widget_show (menuitem);
502     }
503
504     // set default value
505     g_signal_handlers_block_by_func (
506         G_OBJECT (omenu),
507         (gpointer) (on_nicola_layout_menu_changed),
508         NULL);
509
510     gtk_option_menu_set_history (GTK_OPTION_MENU (omenu),
511                                  NICOLA_LAYOUT_INDEX_DEFAULT);
512
513     if (__config_nicola_layout_file == __user_style_file.get_file_name ()) {
514         gtk_option_menu_set_history (GTK_OPTION_MENU (omenu),
515                                      NICOLA_LAYOUT_INDEX_USER_DEFINED);
516
517     } else {
518         GList *node, *list = gtk_container_get_children (GTK_CONTAINER (menu));
519         for (i = 2, node = g_list_next (g_list_next (list));
520              node;
521              i++, node = g_list_next (node))
522         {
523             gint idx = GPOINTER_TO_INT (
524                 g_object_get_data (G_OBJECT (node->data), INDEX_KEY));
525             if (__style_list[idx].get_file_name () == __config_nicola_layout_file) {
526                 gtk_option_menu_set_history (GTK_OPTION_MENU (omenu), i);
527                 break;
528             }
529         }
530     }
531
532     g_signal_handlers_unblock_by_func (
533         G_OBJECT (omenu),
534         (gpointer) (on_nicola_layout_menu_changed),
535         NULL);
536 }
537
538 static void
539 setup_kana_window_value (ScimAnthyTableEditor *editor)
540 {
541     GtkTreeView *treeview = GTK_TREE_VIEW (editor->treeview);
542     GtkTreeModel *model = gtk_tree_view_get_model (treeview);
543     GtkListStore *store = GTK_LIST_STORE (model);
544
545     gtk_list_store_clear (store);
546
547     std::vector<String> keys;
548     __user_style_file.get_key_list (keys, __kana_fund_table);
549     if (keys.empty ()) {
550         load_kana_layout ();
551         __user_style_file.get_key_list (keys, __kana_fund_table);
552     }
553
554     std::vector<String>::iterator it;
555     for (it = keys.begin (); it != keys.end (); it++) {
556         std::vector<WideString> value;
557         __user_style_file.get_string_array (value, __kana_fund_table, *it);
558         String result, cont;
559         if (value.size () > 0) result = utf8_wcstombs(value[0]);
560         if (value.size () > 1) result = utf8_wcstombs(value[1]);
561         GtkTreeIter iter;
562         gtk_list_store_append (store, &iter);
563         gtk_list_store_set (store, &iter,
564                             0, it->c_str (),
565                             1, result.c_str (),
566                             -1);
567     }
568 }
569
570 static void
571 setup_nicola_window_value (ScimAnthyTableEditor *editor)
572 {
573     GtkTreeView *treeview = GTK_TREE_VIEW (editor->treeview);
574     GtkTreeModel *model = gtk_tree_view_get_model (treeview);
575     GtkListStore *store = GTK_LIST_STORE (model);
576
577     gtk_list_store_clear (store);
578
579     std::vector<String> keys;
580     __user_style_file.get_key_list (keys, __nicola_fund_table);
581     if (keys.empty ()) {
582         load_nicola_layout ();
583         __user_style_file.get_key_list (keys, __nicola_fund_table);
584     }
585
586     std::vector<String>::iterator it;
587     for (it = keys.begin (); it != keys.end (); it++) {
588         std::vector<WideString> value;
589         __user_style_file.get_string_array (value, __nicola_fund_table, *it);
590         String single, left, right;
591         if (value.size () > 0) single = utf8_wcstombs(value[0]);
592         if (value.size () > 1) left   = utf8_wcstombs(value[1]);
593         if (value.size () > 2) right  = utf8_wcstombs(value[2]);
594         GtkTreeIter iter;
595         gtk_list_store_append (store, &iter);
596         gtk_list_store_set (store, &iter,
597                             0, it->c_str (),
598                             1, single.c_str (),
599                             2, left.c_str (),
600                             3, right.c_str (),
601                             -1);
602     }
603 }
604
605 static void
606 setup_default_kana_table (void)
607 {
608     __user_style_file.delete_section (__kana_fund_table);
609     ConvRule *table = scim_anthy_kana_typing_rule;
610     for (unsigned int i = 0; table[i].string; i++) {
611         std::vector<String> value;
612         if ((table[i].result && *(table[i].result)) ||
613             (table[i].cont && *(table[i].cont)))
614         {
615             const char *result = table[i].result ? table[i].result : "";
616             value.push_back (result);
617         }
618         if (table[i].cont && *(table[i].cont)) {
619             value.push_back (table[i].cont);
620         }
621         __user_style_file.set_string_array (__kana_fund_table,
622                                             table[i].string,
623                                             value);
624     }
625 }
626
627 static void
628 setup_default_nicola_table (void)
629 {
630     __user_style_file.delete_section (__nicola_fund_table);
631     NicolaRule *table = scim_anthy_nicola_table;
632     for (unsigned int i = 0; table[i].key; i++) {
633         std::vector<String> value;
634         const char *str;
635         str = table[i].single ? table[i].single : "";
636         value.push_back (str);
637         str = table[i].left_shift ? table[i].left_shift : "";
638         value.push_back (str);
639         str = table[i].right_shift ? table[i].right_shift : "";
640         value.push_back (str);
641         __user_style_file.set_string_array (__nicola_fund_table,
642                                             table[i].key,
643                                             value);
644     }
645 }
646
647 static bool
648 load_kana_layout (void)
649 {
650     GtkOptionMenu *omenu = GTK_OPTION_MENU (__widget_kana_layout_menu);
651     gint idx = gtk_option_menu_get_history (omenu);
652     GtkWidget *menu = gtk_option_menu_get_menu (omenu);
653     GList *list = gtk_container_get_children (GTK_CONTAINER (menu));
654     GtkWidget *menuitem = GTK_WIDGET (g_list_nth_data (list, idx));
655
656     if (!menuitem)
657         return false;
658
659     gint theme_idx = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menuitem),
660                                                          INDEX_KEY));
661
662     // set new kana table
663     if (idx == KANA_LAYOUT_INDEX_USER_DEFINED) {
664         // User defined table
665         __config_kana_layout_file = __user_style_file.get_file_name ();
666         StyleLines lines;
667         bool success = __user_style_file.get_entry_list
668                            (lines, __kana_fund_table);
669         if (!success || lines.empty ())
670             setup_default_kana_table ();
671
672         return true;
673
674     } else if (idx == KANA_LAYOUT_INDEX_DEFAULT) {
675         // Default table
676         __config_kana_layout_file = "";
677         setup_default_kana_table ();
678
679         return true;
680
681     } else if (theme_idx >= 0 && theme_idx < (int) __style_list.size ()) {
682         // Tables defined in system theme files
683         __config_kana_layout_file = __style_list[theme_idx].get_file_name ();
684         __user_style_file.delete_section (__kana_fund_table);
685
686         std::vector<String> keys;
687         bool success = __style_list[theme_idx].get_key_list
688                            (keys, __kana_fund_table);
689         if (success) {
690             std::vector<String>::iterator it;
691             for (it = keys.begin (); it != keys.end (); it++) {
692                 std::vector<WideString> value;
693                 __style_list[theme_idx].get_string_array
694                     (value, __kana_fund_table, *it);
695                 __user_style_file.set_string_array (__kana_fund_table,
696                                                     *it, value);
697             }
698         }
699         return true;
700
701     } else {
702         // error
703         return false;
704     }
705 }
706
707 static bool
708 load_nicola_layout (void)
709 {
710     GtkOptionMenu *omenu = GTK_OPTION_MENU (__widget_nicola_layout_menu);
711     gint idx = gtk_option_menu_get_history (omenu);
712     GtkWidget *menu = gtk_option_menu_get_menu (omenu);
713     GList *list = gtk_container_get_children (GTK_CONTAINER (menu));
714     GtkWidget *menuitem = GTK_WIDGET (g_list_nth_data (list, idx));
715
716     if (!menuitem)
717         return false;
718
719     gint theme_idx = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menuitem),
720                                                          INDEX_KEY));
721
722     // set new NICOLA table
723     if (idx == NICOLA_LAYOUT_INDEX_USER_DEFINED) {
724         // User defined table
725         __config_nicola_layout_file = __user_style_file.get_file_name ();
726         StyleLines lines;
727         bool success = __user_style_file.get_entry_list
728                            (lines, __nicola_fund_table);
729         if (!success || lines.empty ())
730             setup_default_nicola_table ();
731
732         return true;
733
734     } else if (idx == NICOLA_LAYOUT_INDEX_DEFAULT) {
735         // Default table
736         __config_nicola_layout_file = "";
737         setup_default_nicola_table ();
738
739         return true;
740
741     } else if (theme_idx >= 0 && theme_idx < (int) __style_list.size ()) {
742         // Tables defined in system theme files
743         __config_nicola_layout_file = __style_list[theme_idx].get_file_name ();
744         __user_style_file.delete_section (__nicola_fund_table);
745
746         std::vector<String> keys;
747         bool success = __style_list[theme_idx].get_key_list
748                            (keys, __nicola_fund_table);
749         if (success) {
750             std::vector<String>::iterator it;
751             for (it = keys.begin (); it != keys.end (); it++) {
752                 std::vector<WideString> value;
753                 __style_list[theme_idx].get_string_array
754                     (value, __nicola_fund_table, *it);
755                 __user_style_file.set_string_array (__nicola_fund_table,
756                                                     *it, value);
757             }
758         }
759         return true;
760
761     } else {
762         // error
763         return false;
764     }
765 }
766
767 static bool
768 has_voiced_consonant (String str)
769 {
770     ConvRule *table = scim_anthy_kana_voiced_consonant_rule;
771
772     WideString str1_wide = utf8_mbstowcs (str);
773     if (str1_wide.length () <= 0)
774         return false;
775
776     for (unsigned int i = 0; table[i].string; i++) {
777         WideString str2_wide = utf8_mbstowcs (table[i].string);
778         if (str2_wide.length () <= 0)
779             continue;
780         if (str1_wide[0] == str2_wide[0])
781             return true;
782     }
783
784     return false;
785 }
786
787 static void
788 on_kana_layout_menu_changed (GtkOptionMenu *omenu, gpointer user_data)
789 {
790     bool success;
791
792     if (__widget_kana_layout_menu != GTK_WIDGET (omenu)) {
793         g_signal_handlers_block_by_func (
794             G_OBJECT (__widget_kana_layout_menu),
795             (gpointer) (on_kana_layout_menu_changed),
796             NULL);
797         gtk_option_menu_set_history (
798             GTK_OPTION_MENU (__widget_kana_layout_menu),
799             gtk_option_menu_get_history (omenu));
800         g_signal_handlers_unblock_by_func (
801             G_OBJECT (__widget_kana_layout_menu),
802             (gpointer) (on_kana_layout_menu_changed),
803             NULL);
804
805         success = load_kana_layout ();
806
807         setup_kana_window_value (SCIM_ANTHY_TABLE_EDITOR (user_data));
808     } else {
809         success = load_kana_layout ();
810     }
811
812     if (success) {
813         // sync widgets
814         __style_changed  = true;
815         __config_changed = true;
816     }
817 }
818
819 static void
820 on_kana_customize_button_clicked (GtkWidget *button, gpointer data)
821 {
822     GtkWidget *widget = create_kana_window (
823         GTK_WINDOW (gtk_widget_get_toplevel (button)));
824     gtk_dialog_run (GTK_DIALOG (widget));
825     gtk_widget_destroy (widget);
826 }
827
828 static void
829 on_kana_table_editor_add_entry (ScimAnthyTableEditor *editor, gpointer data)
830 {
831     const gchar *sequence, *result;
832     sequence = scim_anthy_table_editor_get_nth_text (editor, 0);
833     result   = scim_anthy_table_editor_get_nth_text (editor, 1);
834
835     // real add
836     std::vector<String> value;
837     if (has_voiced_consonant (result))
838         value.push_back ("");
839     value.push_back (result);
840     __user_style_file.set_string_array (__kana_fund_table, sequence, value);
841 }
842
843 static void
844 on_kana_table_editor_added_entry (ScimAnthyTableEditor *editor, gpointer data)
845 {
846     // change menu item to "User defined"
847     gtk_option_menu_set_history (
848         GTK_OPTION_MENU (__widget_kana_layout_menu2),
849         KANA_LAYOUT_INDEX_USER_DEFINED);
850
851     __style_changed = true;
852 }
853
854 static void
855 on_kana_table_editor_remove_entry (ScimAnthyTableEditor *editor, gpointer data)
856 {
857     const gchar *sequence;
858     sequence = scim_anthy_table_editor_get_nth_text (editor, 0);
859
860     // real remove
861     __user_style_file.delete_key (__kana_fund_table, sequence);
862 }
863
864 static void
865 on_kana_table_editor_removed_entry (ScimAnthyTableEditor *editor, gpointer data)
866 {
867     // change menu item to "User deined"
868     gtk_option_menu_set_history (
869         GTK_OPTION_MENU (__widget_kana_layout_menu2),
870         KANA_LAYOUT_INDEX_USER_DEFINED);
871
872     __style_changed = true;
873 }
874
875 static void
876 on_nicola_layout_menu_changed (GtkOptionMenu *omenu, gpointer user_data)
877 {
878     bool success;
879
880     if (__widget_nicola_layout_menu != GTK_WIDGET (omenu)) {
881         g_signal_handlers_block_by_func (
882             G_OBJECT (__widget_nicola_layout_menu),
883             (gpointer) (on_nicola_layout_menu_changed),
884             NULL);
885         gtk_option_menu_set_history (
886             GTK_OPTION_MENU (__widget_nicola_layout_menu),
887             gtk_option_menu_get_history (omenu));
888         g_signal_handlers_unblock_by_func (
889             G_OBJECT (__widget_nicola_layout_menu),
890             (gpointer) (on_nicola_layout_menu_changed),
891             NULL);
892
893         success = load_nicola_layout ();
894
895         setup_nicola_window_value (SCIM_ANTHY_TABLE_EDITOR (user_data));
896     } else {
897         success = load_nicola_layout ();
898     }
899
900     if (success) {
901         // sync widgets
902         __style_changed  = true;
903         __config_changed = true;
904     }
905 }
906
907 static void
908 on_nicola_customize_button_clicked (GtkWidget *button, gpointer data)
909 {
910     GtkWidget *widget = create_nicola_window (
911         GTK_WINDOW (gtk_widget_get_toplevel (button)));
912     gtk_dialog_run (GTK_DIALOG (widget));
913     gtk_widget_destroy (widget);
914 }
915
916 static void
917 on_nicola_table_editor_add_entry (ScimAnthyTableEditor *editor, gpointer data)
918 {
919     const gchar *key = scim_anthy_table_editor_get_nth_text (editor, 0);
920     std::vector<String> value;
921     value.push_back (scim_anthy_table_editor_get_nth_text (editor, 1));
922     value.push_back (scim_anthy_table_editor_get_nth_text (editor, 2));
923     value.push_back (scim_anthy_table_editor_get_nth_text (editor, 3));
924     __user_style_file.set_string_array (__nicola_fund_table, key, value);
925 }
926
927 static void
928 on_nicola_table_editor_added_entry (ScimAnthyTableEditor *editor, gpointer data)
929 {
930     // change menu item to "User defined"
931     gtk_option_menu_set_history (
932         GTK_OPTION_MENU (__widget_nicola_layout_menu2),
933         NICOLA_LAYOUT_INDEX_USER_DEFINED);
934
935     __style_changed = true;
936 }
937
938 static void
939 on_nicola_table_editor_remove_entry (ScimAnthyTableEditor *editor, gpointer data)
940 {
941     const gchar *sequence;
942     sequence = scim_anthy_table_editor_get_nth_text (editor, 0);
943
944     // real remove
945     __user_style_file.delete_key (__nicola_fund_table, sequence);
946 }
947
948 static void
949 on_nicola_table_editor_removed_entry (ScimAnthyTableEditor *editor, gpointer data)
950 {
951     // change menu item to "User deined"
952     gtk_option_menu_set_history (
953         GTK_OPTION_MENU (__widget_nicola_layout_menu2),
954         NICOLA_LAYOUT_INDEX_USER_DEFINED);
955
956     __style_changed = true;
957 }
958
959 }