change layout
[platform/core/uifw/ise-engine-unikey.git] / setup / scim_unikey_setup.cpp
1 /**
2    Scim-Unikey Input Method
3
4    Copyright (C) 2008-2009 Ubuntu-VN <http://www.ubuntu-vn.org>
5    Author: Le Quoc Tuan <mr.lequoctuan@gmail.com>
6    Home: http://scim-unikey.googlecode.com
7    License: GNU LESSER GENERAL PUBLIC LICENSE v2.1
8 */
9
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
13
14 #define Uses_SCIM_CONFIG_BASE
15
16 #include <libintl.h>
17 #define _(String) dgettext(PACKAGE_NAME,String)
18
19 #include <iostream>
20 #include <gtk/gtk.h>
21 #include <string.h>
22
23 #include <scim.h>
24 #include "scim_unikey_const.h"
25 #include "scim_unikey_utils.h"
26 #include "keycons.h"
27 #include "mactab.h"
28 #include "scimkeyselection.h"
29
30 using namespace scim;
31
32 #define scim_module_init unikey_setup_LTX_scim_module_init
33 #define scim_module_exit unikey_setup_LTX_scim_module_exit
34
35 #define scim_setup_module_create_ui       unikey_setup_LTX_scim_setup_module_create_ui
36 #define scim_setup_module_get_category    unikey_setup_LTX_scim_setup_module_get_category
37 #define scim_setup_module_get_name        unikey_setup_LTX_scim_setup_module_get_name
38 #define scim_setup_module_get_description unikey_setup_LTX_scim_setup_module_get_description
39 #define scim_setup_module_load_config     unikey_setup_LTX_scim_setup_module_load_config
40 #define scim_setup_module_save_config     unikey_setup_LTX_scim_setup_module_save_config
41 #define scim_setup_module_query_changed   unikey_setup_LTX_scim_setup_module_query_changed
42
43 static bool    __have_changed                       = false;
44
45 static bool    __unikey_preedit                     = SCIM_IMENGINE_UNIKEY_PREEDIT_DEF;
46 static bool    __unikey_freemarking                 = SCIM_IMENGINE_UNIKEY_FREEMARKING_DEF;
47 static bool    __unikey_modernstyle                 = SCIM_IMENGINE_UNIKEY_MODERNSTYLE_DEF;
48 static bool    __unikey_macroenabled                = SCIM_IMENGINE_UNIKEY_MACROENABLED_DEF;
49 static bool    __unikey_spellcheckenabled           = SCIM_IMENGINE_UNIKEY_SPELLCHECKENABLED_DEF;
50 static bool    __unikey_autononvnrestore            = SCIM_IMENGINE_UNIKEY_AUTONONVNRESTORE_DEF;
51 static bool    __unikey_processwatwordbegin       = SCIM_IMENGINE_UNIKEY_PROCESSWATWORDBEGIN_DEF;
52
53 static GtkTooltips  *__widget_tooltips              = 0;
54 static GtkWidget    *__widget_preedit               = 0;
55 static GtkWidget    *__widget_preedit_skey          = 0;
56 static GtkWidget    *__widget_freemarking           = 0;
57 static GtkWidget    *__widget_modernstyle           = 0;
58 static GtkWidget    *__widget_macroenabled          = 0;
59 static GtkWidget    *__widget_spellcheckenabled     = 0;
60 static GtkWidget    *__widget_autononvnrestore      = 0;
61 static GtkWidget    *__widget_processwatwordbegin   = 0;
62 static CMacroTable  __macStore;
63
64 static GtkWidget* create_setup_window();
65 static void load_config(const ConfigPointer &config);
66 static void save_config(const ConfigPointer &config);
67 static bool query_changed();
68
69 static void setup_widget_value();
70 static GtkListStore* create_and_fill_list_store();
71
72 static void on_default_toggle_button_toggled(GtkToggleButton *togglebutton, gpointer user_data);
73 static void on_macrotable_button_clicked(GtkButton *button, gpointer user_data);
74 static void on_key_edited (GtkCellRendererText *celltext, const gchar *string_path, const gchar *new_text, gpointer data);
75 static void on_replace_edited (GtkCellRendererText *celltext, const gchar *string_path, const gchar *new_text, gpointer data);
76 static void on_end_macro_table(GtkListStore *liststore);
77 static void on_del_macro_clicked(GtkButton *button, gpointer user_data);
78 static void on_delall_macro_clicked(GtkButton *button, gpointer user_data);
79 static gboolean iter_2_macro(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data);
80 static void on_hotkey_button_clicked(GtkButton *button, gpointer user_data);
81
82 extern "C"
83 {
84     void scim_module_init(void)
85     {
86     }
87
88     void scim_module_exit(void)
89     {
90     }
91
92     GtkWidget * scim_setup_module_create_ui (void)
93     {
94         return create_setup_window();
95     }
96
97     String scim_setup_module_get_category (void)
98     {
99         return String("IMEngine");
100     }
101
102     String scim_setup_module_get_name(void)
103     {
104         return String(_("Unikey Setup"));
105     }
106
107     String scim_setup_module_get_description(void)
108     {
109         return String("Setup scim-unikey v" SCIM_UNIKEY_VERSION " IMEngine.");
110     }
111
112     void scim_setup_module_load_config(const ConfigPointer &config)
113     {
114         load_config(config);
115     }
116
117     void scim_setup_module_save_config(const ConfigPointer &config)
118     {
119         save_config(config);
120     }
121
122     bool scim_setup_module_query_changed()
123     {
124         return query_changed();
125     }
126 } // extern "C"
127
128 static GtkWidget* create_setup_window()
129 {
130     static GtkWidget *window = 0;
131     if (!window)
132     {
133         gtk_window_set_default_icon_from_file(SCIM_ICONDIR SCIM_UNIKEY_ICON_FILENAME, NULL);
134         __widget_tooltips = gtk_tooltips_new();
135
136 // create Unikey option frame
137         GtkWidget *frUkOpt = gtk_frame_new(_("Unikey option"));
138         gtk_container_set_border_width(GTK_CONTAINER(frUkOpt), 5);
139
140         // create box for frame
141         GtkWidget *vbox = gtk_vbox_new(true, 0);
142         gtk_container_add(GTK_CONTAINER(frUkOpt), vbox);
143
144
145         // create spellcheck checkbox
146         __widget_spellcheckenabled = gtk_check_button_new_with_label(_("Enable spell check"));
147         gtk_box_pack_start(GTK_BOX(vbox), __widget_spellcheckenabled, false, false, 0);
148         gtk_container_set_border_width(GTK_CONTAINER(__widget_spellcheckenabled), 5);
149         g_signal_connect(__widget_spellcheckenabled, "toggled", G_CALLBACK(on_default_toggle_button_toggled), &__unikey_spellcheckenabled);
150
151         gtk_tooltips_set_tip (__widget_tooltips, __widget_spellcheckenabled,
152                               _("If enable, you can decrease mistake when typing"), NULL);
153
154         // create autononvnrestore checkbox
155         __widget_autononvnrestore = gtk_check_button_new_with_label(_("Auto restore keys with invalid words"));
156         gtk_box_pack_start(GTK_BOX(vbox), __widget_autononvnrestore, false, false, 0);
157         gtk_container_set_border_width(GTK_CONTAINER(__widget_autononvnrestore), 5);
158         g_signal_connect(__widget_autononvnrestore, "toggled", G_CALLBACK(on_default_toggle_button_toggled), &__unikey_autononvnrestore);
159
160         gtk_tooltips_set_tip (__widget_tooltips, __widget_autononvnrestore,
161                               _("When typing a word not in Vietnamese,\n"
162                               "it will auto restore keystroke into orginal"), NULL);
163
164         // create modernstyle checkbox
165         __widget_modernstyle = gtk_check_button_new_with_label(_("Use oà, uý (instead of òa, úy)"));
166         gtk_box_pack_start(GTK_BOX(vbox), __widget_modernstyle, false, false, 0);
167         gtk_container_set_border_width(GTK_CONTAINER(__widget_modernstyle), 5);
168         g_signal_connect(__widget_modernstyle, "toggled", G_CALLBACK(on_default_toggle_button_toggled), &__unikey_modernstyle);
169
170         // create freemarking checkbox
171         __widget_freemarking = gtk_check_button_new_with_label(_("Allow type with more freedom"));
172         gtk_box_pack_start(GTK_BOX(vbox), __widget_freemarking, false, false, 0);
173         gtk_container_set_border_width(GTK_CONTAINER(__widget_freemarking), 5);
174         g_signal_connect(__widget_freemarking, "toggled", G_CALLBACK(on_default_toggle_button_toggled), &__unikey_freemarking);
175
176 // create Macro option frame
177         GtkWidget* frMacro = gtk_frame_new(_("Macro option"));
178         gtk_container_set_border_width(GTK_CONTAINER(frMacro), 5);
179
180         vbox = gtk_vbox_new(true, 0);
181         gtk_container_add(GTK_CONTAINER(frMacro), vbox);
182
183         // create macroenabled checkbox
184         __widget_macroenabled = gtk_check_button_new_with_label(_("Enable Macro"));
185         gtk_box_pack_start(GTK_BOX(vbox), __widget_macroenabled, false, false, 0);
186         gtk_container_set_border_width(GTK_CONTAINER(__widget_macroenabled), 5);
187         g_signal_connect(__widget_macroenabled, "toggled", G_CALLBACK(on_default_toggle_button_toggled), &__unikey_macroenabled);
188
189         // create macroedit button
190         GtkWidget* __widget_macrotable = gtk_button_new_with_label(_("Macro Table"));
191         gtk_box_pack_start(GTK_BOX(vbox), __widget_macrotable, false, false, 0);
192         gtk_container_set_border_width(GTK_CONTAINER(__widget_macrotable), 5);
193         g_signal_connect(__widget_macrotable, "clicked", G_CALLBACK(on_macrotable_button_clicked), NULL);
194
195         gtk_tooltips_set_tip (__widget_tooltips, __widget_macrotable,
196                               _("Edit the macro table for Macro function"), NULL);
197
198
199 // create Telex option frame
200         GtkWidget *frTelex = gtk_frame_new(_("Telex option"));
201         gtk_container_set_border_width(GTK_CONTAINER(frTelex), 5);
202
203         vbox = gtk_vbox_new(true, 0);
204         gtk_container_add(GTK_CONTAINER(frTelex), vbox);
205
206         // create process w at word begin checkbox
207         __widget_processwatwordbegin = gtk_check_button_new_with_label(_("Process W at word begin"));
208         gtk_box_pack_start(GTK_BOX(vbox), __widget_processwatwordbegin, false, false, 0);
209         gtk_container_set_border_width(GTK_CONTAINER(__widget_processwatwordbegin), 5);
210         g_signal_connect(__widget_processwatwordbegin, "toggled", G_CALLBACK(on_default_toggle_button_toggled), &__unikey_processwatwordbegin);
211
212         gtk_tooltips_set_tip (__widget_tooltips, __widget_processwatwordbegin,
213                               _("If enable, type W at begin\n"
214                               "of word will change to Ư."), NULL);
215
216 // create preedit frame
217         GtkWidget *frPreEdit = gtk_frame_new(_("Typing mode"));
218         gtk_container_set_border_width(GTK_CONTAINER(frPreEdit), 5);
219
220         vbox = gtk_vbox_new(true, 0);
221         gtk_container_add(GTK_CONTAINER(frPreEdit), vbox);
222
223         // create preedit switch key
224         GtkWidget *psbox = gtk_hbox_new(false, 0);
225         gtk_box_pack_start(GTK_BOX(vbox), psbox, false, false, 0);
226
227
228         GtkWidget *lpskey = gtk_label_new(_("Mode switch key:"));
229         gtk_box_pack_start(GTK_BOX(psbox), lpskey, false, false, 5);
230
231
232         GtkWidget *bpskey = gtk_button_new_with_label("...");
233         gtk_box_pack_end(GTK_BOX(psbox), bpskey, false, false, 0);
234         gtk_container_set_border_width(GTK_CONTAINER(bpskey), 5);
235         g_signal_connect(bpskey, "clicked", G_CALLBACK(on_hotkey_button_clicked), __widget_preedit_skey);
236
237         __widget_preedit_skey = gtk_entry_new();
238         gtk_entry_set_editable(GTK_ENTRY(__widget_preedit_skey), false);
239         gtk_box_pack_end(GTK_BOX(psbox), __widget_preedit_skey, true, true, 0);
240
241
242         // create preedit checkbox
243         __widget_preedit = gtk_check_button_new_with_label(_("Preedit is default"));
244         gtk_box_pack_start(GTK_BOX(vbox), __widget_preedit, false, false, 0);
245         gtk_container_set_border_width(GTK_CONTAINER(__widget_preedit), 5);
246         g_signal_connect(__widget_preedit, "toggled", G_CALLBACK(on_default_toggle_button_toggled), &__unikey_preedit);
247
248         gtk_tooltips_set_tip (__widget_tooltips, __widget_preedit,
249                               _("This option is best for most application\n"
250                               "But you may don't like it because it have an underline when typing"), NULL);
251
252
253 // Create the toplevel box.
254         window = gtk_vbox_new(false, 0);
255
256         GtkWidget* hbox = gtk_hbox_new(false, 0);
257         gtk_box_pack_start(GTK_BOX(window), hbox, true, true, 0);
258         gtk_box_pack_start(GTK_BOX(window), frPreEdit, true, true, 0);
259
260         
261         vbox = gtk_vbox_new(false, 0);
262         // add frame to hbox
263         gtk_box_pack_start(GTK_BOX(hbox), frUkOpt, true, true, 0);
264         gtk_box_pack_start(GTK_BOX(hbox), vbox, true, true, 0);
265
266         // add frame to vbox
267         gtk_box_pack_start(GTK_BOX(vbox), frMacro, true, true, 0);
268         gtk_box_pack_start(GTK_BOX(vbox), frTelex, true, true, 0);
269
270         setup_widget_value();
271         gtk_widget_show_all(window);
272     }
273     return window;
274 }
275
276 static void setup_widget_value()
277 {
278     if (__widget_preedit)
279         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(__widget_preedit), __unikey_preedit);
280
281     if (__widget_spellcheckenabled)
282         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(__widget_spellcheckenabled), __unikey_spellcheckenabled);
283
284     if (__widget_autononvnrestore)
285         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(__widget_autononvnrestore), __unikey_autononvnrestore);
286
287     if (__widget_modernstyle)
288         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(__widget_modernstyle), __unikey_modernstyle);
289
290     if (__widget_freemarking)
291         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(__widget_freemarking), __unikey_freemarking);
292
293     if (__widget_macroenabled)
294         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(__widget_macroenabled), __unikey_macroenabled);
295
296     if (__widget_processwatwordbegin)
297         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(__widget_processwatwordbegin), __unikey_processwatwordbegin);
298 }
299
300 static void load_config(const ConfigPointer &config)
301 {
302     if (!config.null())
303     {
304         bool t;
305         t = config->read(SCIM_IMENGINE_UNIKEY_PREEDIT, &__unikey_preedit);
306         if (!t) __unikey_preedit = SCIM_IMENGINE_UNIKEY_PREEDIT_DEF;
307
308         String s;        
309         t = config->read(SCIM_IMENGINE_UNIKEY_PREEDIT_SWITCH_KEY, &s);
310         gtk_entry_set_text(GTK_ENTRY(__widget_preedit_skey), t?s.c_str():SCIM_IMENGINE_UNIKEY_PREEDIT_SWITCH_KEY_DEF);
311
312         t = config->read(SCIM_IMENGINE_UNIKEY_FREEMARKING, &__unikey_freemarking);
313         if (!t) __unikey_freemarking = SCIM_IMENGINE_UNIKEY_FREEMARKING_DEF;
314
315         t = config->read(SCIM_IMENGINE_UNIKEY_MODERNSTYLE, &__unikey_modernstyle);
316         if (!t) __unikey_modernstyle = SCIM_IMENGINE_UNIKEY_MODERNSTYLE_DEF;
317
318         t = config->read(SCIM_IMENGINE_UNIKEY_MACROENABLED, &__unikey_macroenabled);
319         if (!t) __unikey_macroenabled = SCIM_IMENGINE_UNIKEY_MACROENABLED_DEF;
320
321         t = config->read(SCIM_IMENGINE_UNIKEY_SPELLCHECKENABLED, &__unikey_spellcheckenabled);
322         if (!t) __unikey_spellcheckenabled = SCIM_IMENGINE_UNIKEY_SPELLCHECKENABLED_DEF;
323
324         t = config->read(SCIM_IMENGINE_UNIKEY_AUTONONVNRESTORE, &__unikey_autononvnrestore);
325         if (!t) __unikey_autononvnrestore = SCIM_IMENGINE_UNIKEY_AUTONONVNRESTORE_DEF;
326
327         t = config->read(SCIM_IMENGINE_UNIKEY_PROCESSWATWORDBEGIN, &__unikey_processwatwordbegin);
328         if (!t) __unikey_processwatwordbegin = SCIM_IMENGINE_UNIKEY_PROCESSWATWORDBEGIN_DEF;
329
330         __macStore.init();
331         __macStore.loadFromFile(getMacroFile());
332
333         setup_widget_value();
334         __have_changed = false;
335     }
336 }
337
338 static void save_config(const ConfigPointer &config)
339 {
340     if (!config.null())
341     {
342         config->write(SCIM_IMENGINE_UNIKEY_PREEDIT, __unikey_preedit);
343         String s = String(gtk_entry_get_text(GTK_ENTRY(__widget_preedit_skey)));
344         config->write(SCIM_IMENGINE_UNIKEY_PREEDIT_SWITCH_KEY, s);
345         config->write(SCIM_IMENGINE_UNIKEY_FREEMARKING, __unikey_freemarking);
346         config->write(SCIM_IMENGINE_UNIKEY_MODERNSTYLE, __unikey_modernstyle);
347         config->write(SCIM_IMENGINE_UNIKEY_MACROENABLED, __unikey_macroenabled);
348         config->write(SCIM_IMENGINE_UNIKEY_SPELLCHECKENABLED, __unikey_spellcheckenabled);
349         config->write(SCIM_IMENGINE_UNIKEY_AUTONONVNRESTORE, __unikey_autononvnrestore);
350         config->write(SCIM_IMENGINE_UNIKEY_AUTONONVNRESTORE, __unikey_autononvnrestore);
351         config->write(SCIM_IMENGINE_UNIKEY_PROCESSWATWORDBEGIN, __unikey_processwatwordbegin);
352
353         s = String(getMacroFile());
354         FILE *f = fopen(s.c_str(), "wt");
355         if (f == NULL)
356         {
357             s = s.substr(0, s.rfind('/'));
358             int tmp=system((String("mkdir ") + s).c_str());
359         }
360         else
361             fclose(f);
362
363         __macStore.writeToFile(getMacroFile());
364
365         __have_changed = false;
366     }
367 }
368
369 static bool query_changed()
370 {
371     return __have_changed;
372 }
373
374 static void on_default_toggle_button_toggled(GtkToggleButton *togglebutton, gpointer user_data)
375 {
376     bool *toggle = static_cast<bool*> (user_data);
377
378     if (toggle)
379     {
380         *toggle = gtk_toggle_button_get_active (togglebutton);
381         __have_changed = true;
382     }
383 }
384
385 enum {COL_KEY = 0, COL_REPLACE, NUM_COLS};
386
387 static void on_macrotable_button_clicked(GtkButton *button, gpointer user_data)
388 {
389     GtkWidget           *dialog;
390     GtkWidget           *treeview;
391     GtkTreeModel        *model;
392     GtkTreeViewColumn   *col;
393     GtkWidget           *contentarea;
394     GtkWidget           *hbox, *vbox;
395     GtkCellRenderer     *renderer;
396
397 // create main dialog
398     dialog = gtk_dialog_new();
399     gtk_window_set_default_size(GTK_WINDOW(dialog), 600, 300);
400     gtk_window_set_title(GTK_WINDOW(dialog), _("Macro table definition"));
401     gtk_dialog_add_buttons(GTK_DIALOG(dialog),
402                            GTK_STOCK_OK, GTK_RESPONSE_OK,
403                            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
404                            NULL);
405
406     //contentarea = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); // only for GTK >= 2.14
407     contentarea = GTK_DIALOG(dialog)->vbox;
408
409     hbox = gtk_hbox_new (false, 5);
410     gtk_container_add(GTK_CONTAINER(contentarea), hbox);
411
412 // create scroll window and tree view
413     model = GTK_TREE_MODEL(create_and_fill_list_store());
414
415     treeview = gtk_tree_view_new_with_model (model);
416
417     GtkWidget *scroll = gtk_scrolled_window_new(NULL, NULL);
418     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
419
420     gtk_box_pack_start(GTK_BOX(hbox), scroll, true, true, 0);
421     gtk_container_add(GTK_CONTAINER(scroll), treeview);
422
423 // create key column
424     renderer = gtk_cell_renderer_text_new();
425     g_object_set(renderer, "editable", true, NULL);
426     g_object_set(renderer, "width-chars", MAX_MACRO_KEY_LEN+4, NULL);
427     g_signal_connect(renderer, "edited", G_CALLBACK(on_key_edited), model);
428     col = gtk_tree_view_column_new_with_attributes(_("Word"), renderer, "text", COL_KEY, NULL);
429     gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), col);
430
431 // create replace column
432     renderer = gtk_cell_renderer_text_new();
433     g_object_set(renderer, "editable", true, NULL);
434     //g_object_set(renderer, "width-chars", MAX_MACRO_KEY_LEN*3, NULL);
435     g_signal_connect(renderer, "edited", G_CALLBACK(on_replace_edited), model);
436     col = gtk_tree_view_column_new_with_attributes(_("Replace with"), renderer, "text", COL_REPLACE, NULL);
437     gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), col);
438
439     vbox = gtk_vbox_new (false, 0);
440     gtk_box_pack_end(GTK_BOX(hbox), vbox, false, false, 6);
441
442 // create Del button
443     GtkWidget* btDel = gtk_button_new_with_label (_("Delete"));
444     gtk_box_pack_start(GTK_BOX(vbox), btDel, false, true, 3);
445     g_signal_connect(btDel, "clicked", G_CALLBACK(on_del_macro_clicked), treeview);
446
447 // create DelAll button
448     GtkWidget *btDelAll = gtk_button_new_with_label (_("Delete All"));
449     gtk_box_pack_start(GTK_BOX(vbox), btDelAll, false, true, 3);
450     g_signal_connect(btDelAll, "clicked", G_CALLBACK(on_delall_macro_clicked), model);
451
452     gtk_widget_show_all(dialog);
453     gint result = gtk_dialog_run(GTK_DIALOG(dialog));
454
455 // save Macro Table
456     if (result == GTK_RESPONSE_OK)
457     {
458         __macStore.init();
459         gtk_tree_model_foreach(model, iter_2_macro, NULL);
460
461         __have_changed = true;
462     }
463
464     g_object_unref(model);
465     gtk_widget_destroy(dialog);
466 }
467
468 static void on_end_macro_table(GtkListStore *liststore)
469 {
470     GtkTreeIter     iter;
471     gchar           *lastkey;
472     gint n;
473
474     n = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(liststore), NULL);
475     if (n)
476     {
477         gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(liststore), &iter, NULL, n-1);
478     }
479     else
480     {
481         gtk_list_store_append(liststore, &iter);
482         gtk_list_store_set(liststore, &iter, COL_KEY, "...", COL_REPLACE, "...", -1);
483         return;
484     }
485
486     gtk_tree_model_get(GTK_TREE_MODEL(liststore), &iter, COL_KEY, &lastkey, -1);
487     if (strcmp(lastkey, "...") || n==0)
488     {
489         gtk_list_store_append(liststore, &iter);
490         gtk_list_store_set(liststore, &iter, COL_KEY, "...", COL_REPLACE, "...", -1);
491     }
492 }
493
494 static void on_del_macro_clicked(GtkButton *button, gpointer user_data)
495 {
496     GtkTreeView     *treeview;
497     GtkListStore    *liststore;
498     GtkTreeSelection*tselect;
499     GtkTreeIter     iter;
500     gchar           *lastkey;
501
502     treeview = GTK_TREE_VIEW(user_data);
503     tselect = gtk_tree_view_get_selection(treeview);
504
505     if (gtk_tree_selection_get_selected(tselect, NULL, &iter))
506     {
507         liststore = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
508         gtk_tree_model_get(GTK_TREE_MODEL(liststore), &iter, COL_KEY, &lastkey, -1);
509         if (strcmp(lastkey, "..."))
510             gtk_list_store_remove(liststore, &iter);
511     }
512 }
513
514 static void on_delall_macro_clicked(GtkButton *button, gpointer user_data)
515 {
516     GtkListStore    *liststore;
517     GtkTreeIter     iter;
518
519     liststore = GTK_LIST_STORE(user_data);
520
521     gtk_list_store_clear(liststore);
522     on_end_macro_table(liststore);
523 }
524
525 static GtkListStore* create_and_fill_list_store()
526 {
527     GtkListStore*   liststore;
528     GtkTreeIter     iter;
529     FILE            *f;
530     char            key[MAX_MACRO_KEY_LEN*3], replace[MAX_MACRO_TEXT_LEN*3];
531     UKBYTE          *p;
532     int             i, inLen, maxOutLen, ret;
533
534     liststore = gtk_list_store_new (NUM_COLS, G_TYPE_STRING, G_TYPE_STRING);
535
536 // add key and replace to liststore
537     for (int i=0 ; i < __macStore.getCount() ; i++)
538     {
539         p = (UKBYTE *)__macStore.getKey(i);
540         inLen = -1;
541         maxOutLen = sizeof(key);
542         ret = VnConvert(CONV_CHARSET_VNSTANDARD, CONV_CHARSET_UNIUTF8,
543                         (UKBYTE *) p, (UKBYTE *)key,
544                         &inLen, &maxOutLen);
545         if (ret != 0)
546             continue;
547
548         p = (UKBYTE *)__macStore.getText(i);
549         inLen = -1;
550         maxOutLen = sizeof(replace);
551         ret = VnConvert(CONV_CHARSET_VNSTANDARD, CONV_CHARSET_UNIUTF8,
552                         p, (UKBYTE *)replace,
553                         &inLen, &maxOutLen);
554         if (ret != 0)
555             continue;
556
557         gtk_list_store_append(liststore, &iter);
558         gtk_list_store_set(liststore, &iter, COL_KEY, key, COL_REPLACE, replace, -1);
559     }
560
561     on_end_macro_table(liststore);
562     return liststore;
563 }
564
565 static void on_key_edited (GtkCellRendererText *celltext, const gchar *string_path, const gchar *new_text, gpointer data)
566 {
567     GtkTreeModel    *model;
568     GtkTreeIter     iter;
569     gchar           *curkey, *oldkey, *oldreplace;
570     bool            b;
571
572     model = GTK_TREE_MODEL (data);
573
574     if (strlen(new_text) <= 0 || strcmp(new_text, "...") == 0)
575     {
576         return;
577     }
578     else if (strlen(new_text) >= MAX_MACRO_KEY_LEN)
579     {
580         curkey = (gchar*)new_text;
581         curkey[MAX_MACRO_KEY_LEN-1] = '\0';
582     }
583
584     b = gtk_tree_model_get_iter_first(model, &iter);
585     while (b)
586     {
587         gtk_tree_model_get(model, &iter, COL_KEY, &curkey, -1);
588         if (strcasecmp(curkey, new_text) == 0)
589             return;
590
591         b = gtk_tree_model_iter_next(model, &iter);
592     }
593
594     gtk_tree_model_get_iter_from_string(model, &iter, string_path);
595     gtk_tree_model_get(model, &iter, COL_KEY, &oldkey, COL_REPLACE, &oldreplace, -1);
596
597     gtk_list_store_set(GTK_LIST_STORE(model), &iter, COL_KEY, new_text, -1);
598     if (!strcmp(oldkey, "..."))
599     {
600         gtk_list_store_set(GTK_LIST_STORE(model), &iter, COL_REPLACE, _("(replace text)"));
601     }
602
603     on_end_macro_table(GTK_LIST_STORE(model));
604 }
605
606 static void on_replace_edited (GtkCellRendererText *celltext, const gchar *string_path, const gchar *new_text, gpointer data)
607 {
608     GtkTreeModel    *model;
609     GtkTreeIter     iter;
610     gchar           *oldkey, *tmp;
611
612     model = GTK_TREE_MODEL (data);
613     gtk_tree_model_get_iter_from_string(model, &iter, string_path);
614
615     gtk_tree_model_get(model, &iter, COL_KEY, &oldkey, -1);
616
617     if (strlen(new_text) >= MAX_MACRO_TEXT_LEN)
618     {
619         tmp = (gchar*)new_text;
620         tmp[MAX_MACRO_TEXT_LEN-1] = '\0';
621     }
622
623     if (strcmp(oldkey, "...") != 0)
624     {
625         gtk_list_store_set(GTK_LIST_STORE(model), &iter, COL_REPLACE, new_text, -1);
626     }
627 }
628
629 static gboolean iter_2_macro(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
630 {
631     gchar   *key, *replace;
632     GtkTreeIter c;
633
634     c = *iter;
635
636     if (!gtk_tree_model_iter_next(model, &c))
637         return true;
638     gtk_tree_model_get(model, iter, COL_KEY, &key, COL_REPLACE, &replace, -1);
639
640     __macStore.addItem(key, replace, CONV_CHARSET_XUTF8);
641
642     return false;
643 }
644
645 static void on_hotkey_button_clicked (GtkButton *button, gpointer data)
646 {
647     GtkWidget *wid = (GtkWidget*)data;
648
649     GtkWidget *dialog = scim_key_selection_dialog_new("Edit hotkey");
650     gint r;
651     const gchar *hotkeys = gtk_entry_get_text(GTK_ENTRY(wid));
652     
653     if (hotkeys)
654     {
655         scim_key_selection_dialog_set_keys(
656             SCIM_KEY_SELECTION_DIALOG(dialog), hotkeys);
657     }
658
659     r = gtk_dialog_run(GTK_DIALOG(dialog));
660
661     if (r == GTK_RESPONSE_OK)
662     {
663         const gchar *newkeys = scim_key_selection_dialog_get_keys(SCIM_KEY_SELECTION_DIALOG(dialog));
664         gtk_entry_set_text(GTK_ENTRY(wid), newkeys?newkeys:"");
665         __have_changed = true;
666     }
667
668     gtk_widget_destroy(dialog);
669 }