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