add Simple Telex 2
[platform/core/uifw/ise-engine-unikey.git] / src / scim_unikey_imengine.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 #define Uses_SCIM_IMENGINE
11 #define Uses_SCIM_ICONV
12 #define Uses_SCIM_CONFIG_BASE
13 #define Uses_SCIM_CONFIG_PATH
14
15 #include <libintl.h>
16 #define _(String) dgettext(PACKAGE_NAME,String)
17
18 #include <scim.h>
19 #include "scim_unikey_const.h"
20 #include "scim_unikey_utils.h"
21 #include "scim_unikey_imengine.h"
22
23 #include <string.h>
24 #include "unikey.h"
25 #include "vnconv.h"
26
27 #define scim_module_init                            unikey_LTX_scim_module_init
28 #define scim_module_exit                            unikey_LTX_scim_module_exit
29 #define scim_imengine_module_init                   unikey_LTX_scim_imengine_module_init
30 #define scim_imengine_module_create_factory         unikey_LTX_scim_imengine_module_create_factory
31
32 static unsigned char WordBreakSyms[] =
33 {
34     ',', ';', ':', '.', '\"', '\'', '!', '?', ' ',
35     '<', '>', '=', '+', '-', '*', '/', '\\',
36     '_', '~', '`', '@', '#', '$', '%', '^', '&', '(', ')', '{', '}', '[', ']',
37     '|'
38 };
39
40 static unsigned char WordAutoCommit[] =
41 {
42     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
43     'b', 'c', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n',
44     'p', 'q', 'r', 's', 't', 'v', 'x', 'z',
45     'B', 'C', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N',
46     'P', 'Q', 'R', 'S', 'T', 'V', 'X', 'Z'
47 };
48
49 const String          Unikey_IMNames[]    = {"Telex", "Vni", "STelex", "STelex2"};
50 const UkInputMethod   Unikey_IM[]         = {UkTelex, UkVni, UkSimpleTelex, UkSimpleTelex2};
51 const unsigned int    NUM_INPUTMETHOD     = sizeof(Unikey_IM)/sizeof(Unikey_IM[0]);
52
53 const String          Unikey_OCNames[]    = {"Unicode",
54                                              "TCVN3",
55                                              "VNI Win",
56                                              "VIQR",
57                                              "CString",
58                                              "NCR Decimal",
59                                              "NCR Hex"};
60
61 const unsigned int    Unikey_OC[]         = {CONV_CHARSET_XUTF8,
62                                              CONV_CHARSET_TCVN3,
63                                              CONV_CHARSET_VNIWIN,
64                                              CONV_CHARSET_VIQR,
65                                              CONV_CHARSET_UNI_CSTRING,
66                                              CONV_CHARSET_UNIREF,
67                                              CONV_CHARSET_UNIREF_HEX};
68 const unsigned int    NUM_OUTPUTCHARSET   = sizeof(Unikey_OC)/sizeof(Unikey_OC[0]);
69
70 ConfigPointer   __config;
71
72 using namespace scim;
73
74 extern "C"
75 {
76     void scim_module_init(void)
77     {
78         UnikeySetup();
79     }
80
81     void scim_module_exit(void)
82     {
83         UnikeyCleanup();
84     }
85
86     unsigned int scim_imengine_module_init(ConfigPointer &config)
87     {
88         if (config.null())
89             return 0;
90         __config = config;
91
92         return 1;
93     }
94
95     IMEngineFactoryPointer scim_imengine_module_create_factory(unsigned int index)
96     {
97         return new UnikeyFactory();
98     }
99 }
100
101 UnikeyFactory::UnikeyFactory()
102 {
103     set_languages("vi_VN");
104 }
105 UnikeyFactory::~UnikeyFactory()
106 {
107 }
108 WideString UnikeyFactory::get_name() const
109 {
110     return utf8_mbstowcs("Unikey");
111 }
112 String UnikeyFactory::get_uuid() const
113 {
114     return String(String("16ef5139-de02-494f-8d98-ddfcd60bbae1"));
115 }
116 WideString UnikeyFactory::get_authors() const
117 {
118     return utf8_mbstowcs("Le Quoc Tuan <mr.lequoctuan@gmail.com>");
119 }
120 WideString UnikeyFactory::get_credits() const
121 {
122     return utf8_mbstowcs(String("Scim-Unikey Input Method\n"
123                                 "Version: " SCIM_UNIKEY_VERSION "\n"
124                                 "Copyright © 2008-2009 Ubuntu-VN\n"
125                                 "http://www.ubuntu-vn.org\n\n"
126                                 "Thanks to Pham Kim Long for ukengine")
127         );
128 }
129 WideString UnikeyFactory::get_help() const
130 {
131     return utf8_mbstowcs(_("This IME work best when environment variable are\n"
132                            "- GTK_IM_MODULE=scim-bridge\n"
133                            "- QT_IM_MODULE=xim\n"
134                            " If you use preedit, you don't not need that\n\n"
135                            
136                            "Some time, in some application, you \"must\"\n"
137                            "enable Preedit to type best\n\n"
138
139                            "In some application, scim can't enable,\n"
140                            "this is not a bug of scim-unikey.\n"
141                            "You can try this in terminal: app_name | scim\n\n"
142
143                            "This IME come into being not intend to\n"
144                            "replace scim-m17n, just a choose, I recommend\n"
145                            "use this combine with scim-m17n\n\n"
146
147                            "For other support goto:\n"
148                            "  http://forum.ubuntu-vn.org/viewforum.php?f=85"));
149 }
150 String UnikeyFactory::get_icon_file() const
151 {
152     return String(SCIM_ICONDIR SCIM_UNIKEY_ICON_FILENAME);
153 }
154
155 IMEngineInstancePointer UnikeyFactory::create_instance(const String & encoding, int id)
156 {
157     return new UnikeyInstance(this, encoding, id);
158 }
159
160 UnikeyInstance::UnikeyInstance(UnikeyFactory *factory, const String &encoding, int id)
161     :IMEngineInstanceBase(factory, encoding, id),
162      m_auto_commit(false)
163 {
164     static bool t, o;  //temp variable
165
166     m_preeditstring.clear();
167
168     CreateDefaultUnikeyOptions(&m_ukopt);
169
170     /* Read config
171        if can't read config, set it to default value*/
172
173     t = __config->read(SCIM_IMENGINE_UNIKEY_INPUTMETHOD, &m_im);
174     if (!t) m_im = 0;
175
176     t = __config->read(SCIM_IMENGINE_UNIKEY_OUTPUTCHARSET, &m_oc);
177     if (!t) m_oc = 0;
178
179     t = __config->read(SCIM_IMENGINE_UNIKEY_PREEDIT, &m_preedit);
180     if (!t) m_preedit = SCIM_IMENGINE_UNIKEY_PREEDIT_DEF;
181
182     // read preedit switch key
183     m_preeditskey.clear();
184     String s;
185     int i = 0, j;
186     t = __config->read(SCIM_IMENGINE_UNIKEY_PREEDIT_SWITCH_KEY, &s);
187     if (!t) s=SCIM_IMENGINE_UNIKEY_PREEDIT_SWITCH_KEY_DEF;
188     if (s.length())
189     {
190         while (true)
191         {
192             j=s.find(',', i);
193             if (j!=String::npos)
194                 m_preeditskey.push_back(KeyEvent(s.substr(i, j-i)));
195             else
196                 break;
197             i = j+1;
198         }
199         m_preeditskey.push_back(KeyEvent(s.substr(i)));
200     } // end read preedit switch key
201
202     t = __config->read(SCIM_IMENGINE_UNIKEY_PROCESSWATWORDBEGIN, &o);
203     m_process_w_AtBeginWord = t?o:SCIM_IMENGINE_UNIKEY_PROCESSWATWORDBEGIN_DEF;
204
205     t = __config->read(SCIM_IMENGINE_UNIKEY_CODERTELEX, &o);
206     m_codertelex = t?o:SCIM_IMENGINE_UNIKEY_CODERTELEX_DEF;
207
208 // Unikey Options
209     t = __config->read(SCIM_IMENGINE_UNIKEY_FREEMARKING, &o);
210     m_ukopt.freeMarking = t?o:SCIM_IMENGINE_UNIKEY_FREEMARKING_DEF;
211
212     t = __config->read(SCIM_IMENGINE_UNIKEY_MODERNSTYLE, &o);
213     m_ukopt.modernStyle = t?o:SCIM_IMENGINE_UNIKEY_MODERNSTYLE_DEF;
214
215     t = __config->read(SCIM_IMENGINE_UNIKEY_MACROENABLED, &o);
216     m_ukopt.macroEnabled = t?o:SCIM_IMENGINE_UNIKEY_MACROENABLED_DEF;
217
218     t = __config->read(SCIM_IMENGINE_UNIKEY_SPELLCHECKENABLED, &o);
219     m_ukopt.spellCheckEnabled = t?o:SCIM_IMENGINE_UNIKEY_SPELLCHECKENABLED_DEF;
220
221     t = __config->read(SCIM_IMENGINE_UNIKEY_AUTONONVNRESTORE, &o);
222     m_ukopt.autoNonVnRestore = t?o:SCIM_IMENGINE_UNIKEY_AUTONONVNRESTORE_DEF;
223
224     UnikeySetOptions(&m_ukopt);
225
226     if (m_ukopt.macroEnabled)
227     {
228         UnikeyLoadMacroTable(getMacroFile());
229     }
230
231     reset();
232 }
233
234 UnikeyInstance::~UnikeyInstance()
235 {
236 }
237
238 void UnikeyInstance::focus_in()
239 {
240     register_properties(CreatePropertyList());
241
242     UnikeySetInputMethod(Unikey_IM[m_im]);
243     UnikeySetOutputCharset(Unikey_OC[m_oc]);
244     UnikeySetOptions(&m_ukopt);
245 }
246
247 void UnikeyInstance::focus_out()
248 {
249     reset();
250 }
251
252 void UnikeyInstance::reset()
253 {
254     UnikeyResetBuf();
255
256     m_lastkey_with_shift = false;
257
258     if (m_preedit)
259     {
260         if (m_preeditstring.length())
261         {
262             commit_string(m_preeditstring);
263             hide_preedit_string();
264             m_preeditstring.clear();
265         }
266         m_auto_commit = false;
267     }
268 }
269
270 void UnikeyInstance::Unikey_send_backspace(int nBackspace)
271 {
272     static WideString ws;
273     static int n;
274
275     //  if surrounding text was provided, use it instead of send backspace
276     if (get_surrounding_text(ws, n, nBackspace, 0))
277     {
278         // for type in Auto Complete in OpenOffice
279         // Hope this not rise bugs in others application
280         // not use SCIM_KEY_NullKey, because GTK application crash when GTK_IM_MODULE=scim
281
282         forward_key_event(SCIM_KEY_VoidSymbol);
283
284         delete_surrounding_text(-ws.length(), ws.length());
285     }
286     else
287     {
288         for (int i=0; i < nBackspace; i++)
289             forward_key_event(SCIM_KEY_BackSpace);
290     }
291 }
292
293 void UnikeyInstance::Unikey_update_preedit_string(const WideString s, const bool visible)
294 {
295     AttributeList list;
296     Attribute att;
297
298     // underline preedit string
299     att = Attribute(0, s.length(), SCIM_ATTR_DECORATE, SCIM_ATTR_DECORATE_UNDERLINE);
300     list.push_back(att);
301
302     if (m_ukopt.spellCheckEnabled==1 && UnikeyLastWordIsNonVn())
303     {
304         // red preedit string
305         att = Attribute(0, s.length(), SCIM_ATTR_FOREGROUND, 0xff0000);
306         list.push_back(att);
307     }
308
309     update_preedit_string(s, list);
310     update_preedit_caret(s.length());
311
312     if (visible == true)
313     {
314         show_preedit_string();
315     }
316     else
317     {
318         hide_preedit_string();
319     }
320 }
321
322 bool UnikeyInstance::process_key_event(const KeyEvent& key)
323 {
324     bool tmp;
325
326     for (int i = 0; i<m_preeditskey.size(); i++)
327     {
328         if (key==m_preeditskey.at(i))
329         {
330             reset();
331             m_preedit=!m_preedit;
332             register_properties(CreatePropertyList());
333             return true;
334         }
335     }
336
337     tmp = m_preedit?Unikey_process_key_event_preedit(key)
338         :Unikey_process_key_event_direct(key);
339
340     if ((key.code >= SCIM_KEY_space && key.code <= SCIM_KEY_asciitilde)
341         || (key.code >= SCIM_KEY_KP_Multiply && key.code <= SCIM_KEY_KP_9))
342     {
343         m_lastkey_with_shift = key.is_shift_down();
344     }
345     else
346     {
347         m_lastkey_with_shift = false;
348     }
349
350     return tmp;
351 }
352
353 /** This method not use preedit string */
354 bool UnikeyInstance::Unikey_process_key_event_direct(const KeyEvent& key)
355 {
356     if (key.is_key_release())
357     {
358         return false;
359     }
360
361     if (key.is_control_down() || key.mask & SCIM_KEY_AltMask)
362     {
363         reset();
364         return false;
365     }
366
367     if (key.code >= SCIM_KEY_Shift_L && key.code <= SCIM_KEY_Hyper_R)
368     {
369         return false;
370     }
371
372     if (key.code == SCIM_KEY_BackSpace)
373     {
374         UnikeyBackspacePress();     // xu ly phim backspace
375         if (UnikeyBackspaces==0)    // neu ukengine bao khong can xoa ky tu nao,
376             return false;  // thi tra lai backspace cho chuong trinh khach
377         else
378         {
379             Unikey_send_backspace(UnikeyBackspaces);
380
381             // append key that need change tone pos after press backspace
382             if (UnikeyBufChars)
383             {
384                 if (Unikey_OC[m_oc] == CONV_CHARSET_XUTF8)
385                     commit_string(utf8_mbstowcs((const char*)UnikeyBuf, UnikeyBufChars));  // send the solved string to client
386                 else
387                 {
388                     static unsigned char buf[1024];
389                     int bufSize=sizeof(buf)/sizeof(buf[0]);
390
391                     latinToUtf(buf, UnikeyBuf, UnikeyBufChars, &bufSize);
392                     commit_string(utf8_mbstowcs((const char*)buf, sizeof(buf)/sizeof(buf[0]) - bufSize));
393                 }
394             }
395
396             return true;
397         }
398     }
399
400     if (   (key.code >= SCIM_KEY_space && key.code <= SCIM_KEY_asciitilde)
401            || (key.code >= SCIM_KEY_KP_Multiply && key.code <= SCIM_KEY_KP_9)
402         )
403     {
404         UnikeySetCapsState(key.mask & SCIM_KEY_ShiftMask,
405                            key.mask & SCIM_KEY_CapsLockMask);
406
407         // shift + space to restore keystroke
408         if (m_lastkey_with_shift == false
409             && key.mask & SCIM_KEY_ShiftMask
410             && key.code == SCIM_KEY_space
411             && !UnikeyAtWordBeginning())
412         {
413             UnikeyRestoreKeyStrokes();
414         }
415
416         else if ((key.code >= SCIM_KEY_KP_0 &&
417                   key.code <= SCIM_KEY_KP_9))
418         {
419             UnikeyPutChar(key.code);
420         }
421
422         else if (!m_process_w_AtBeginWord &&
423                  (key.code == SCIM_KEY_w || key.code == SCIM_KEY_W) &&
424                  UnikeyAtWordBeginning())
425         {
426             UnikeyPutChar(key.code);
427         }
428
429         else if (m_codertelex && Unikey_IM[m_im] == UkTelex
430                  && (key.code == SCIM_KEY_bracketleft || key.code == SCIM_KEY_bracketright
431                      || key.code == SCIM_KEY_braceleft || key.code == SCIM_KEY_braceright)
432             )
433         {
434             UnikeyPutChar(key.code);
435         }
436         else
437         {
438             UnikeyFilter(key.code);
439         }
440
441         if (UnikeyBackspaces)
442         {
443             Unikey_send_backspace(UnikeyBackspaces);
444         }
445
446         if (UnikeyBufChars)
447         {
448             if (Unikey_OC[m_oc] == CONV_CHARSET_XUTF8)
449             {
450                 commit_string(utf8_mbstowcs((const char*)UnikeyBuf, UnikeyBufChars));  // send the solved string to client
451             }
452             else
453             {
454                 static unsigned char buf[1024];
455                 int bufSize=sizeof(buf)/sizeof(buf[0]);
456
457                 latinToUtf(buf, UnikeyBuf, UnikeyBufChars, &bufSize);
458                 commit_string(utf8_mbstowcs((const char*)buf, sizeof(buf)/sizeof(buf[0]) - bufSize));
459             }
460         }
461         else
462         {
463             forward_key_event(key);
464             return true;
465         }
466
467         return true;
468     }
469
470     // else
471     reset();
472     return false;
473 }
474
475 /** This method use preedit string */
476 bool UnikeyInstance::Unikey_process_key_event_preedit(const KeyEvent& key)
477 {
478     static int i;
479
480     if (key.code == SCIM_KEY_Tab
481         || key.mask & SCIM_KEY_ControlMask
482         || key.mask & SCIM_KEY_AltMask)
483     {
484         if (m_preeditstring.length())
485         {
486             commit_string(m_preeditstring);
487             hide_preedit_string();
488             m_preeditstring.clear();
489         }
490         reset();
491         return false;
492     }
493
494     if (key.is_key_release())
495         return false;
496
497     if (key.code >= SCIM_KEY_Shift_L && key.code <= SCIM_KEY_Hyper_R)
498         return false;
499
500     else if (key.code == SCIM_KEY_Tab || key.code == SCIM_KEY_Return
501              || key.code == SCIM_KEY_Delete || key.code == SCIM_KEY_KP_Enter
502              || (key.code >= SCIM_KEY_Home && key.code <= SCIM_KEY_Insert)
503              || (key.code >= SCIM_KEY_KP_Home && key.code <= SCIM_KEY_KP_Delete)
504         )
505     {
506         if (m_preeditstring.length())
507         {
508             commit_string(m_preeditstring);
509             hide_preedit_string();
510             m_preeditstring.clear();
511         }
512
513         reset();
514         return false;
515     }
516
517     else if (key.code == SCIM_KEY_BackSpace)
518     {
519         UnikeyBackspacePress();     // process Backspace
520
521         if (UnikeyBackspaces==0 || m_preeditstring.empty())    // if Unikey tell no Backspace
522         {
523             reset();
524             return false;  // Return Backspace to client
525         }
526         else
527         {
528             static int len;
529
530             len = m_preeditstring.length();
531             if (len <= UnikeyBackspaces)
532             {
533                 m_preeditstring.clear();
534                 hide_preedit_string();
535                 m_auto_commit = true;
536             }
537             else
538             {
539                 m_preeditstring.erase(len - UnikeyBackspaces, UnikeyBackspaces);
540                 Unikey_update_preedit_string(m_preeditstring, true);
541             }
542
543             // append key that need change tone pos after press backspace
544             if (UnikeyBufChars)
545             {
546                 if (Unikey_OC[m_oc] == CONV_CHARSET_XUTF8)
547                     m_preeditstring.append(utf8_mbstowcs((const char*)UnikeyBuf, UnikeyBufChars));
548                 else
549                 {
550                     static unsigned char buf[1024];
551                     int bufSize=sizeof(buf)/sizeof(buf[0]);
552
553                     latinToUtf(buf, UnikeyBuf, UnikeyBufChars, &bufSize);
554                     m_preeditstring.append(utf8_mbstowcs((const char*)buf, sizeof(buf)/sizeof(buf[0])-bufSize));
555                 }
556
557                 m_auto_commit = false;
558                 Unikey_update_preedit_string(m_preeditstring, true);
559             }
560         }
561
562         return true;
563     }
564
565     else if (   (key.code >= SCIM_KEY_space && key.code <= SCIM_KEY_asciitilde)
566                 || (key.code >= SCIM_KEY_KP_Multiply && key.code <= SCIM_KEY_KP_9)
567         )
568     {
569         UnikeySetCapsState(key.mask & SCIM_KEY_ShiftMask, key.mask & SCIM_KEY_CapsLockMask);
570
571         // auto commit char: commit char that never change later in preedit string
572         // if macro enabled, then not auto commit. Because macro may change any word
573         if (m_ukopt.macroEnabled==0 && (UnikeyAtWordBeginning() || m_auto_commit))
574         {
575             for (i = 0; i < sizeof(WordAutoCommit); i++)
576                 if (key.code == WordAutoCommit[i])
577                 {
578                     UnikeyPutChar(key.code);
579                     m_auto_commit = true;
580                     forward_key_event(key); // forward keyevent instead of return false
581                     return true;
582                 }
583         } // end auto commit char
584
585         if (!m_process_w_AtBeginWord && (key.code == SCIM_KEY_w || key.code == SCIM_KEY_W) && UnikeyAtWordBeginning())
586         {
587             UnikeyPutChar(key.code);
588             m_auto_commit = true;
589             return false;
590         }
591
592         m_auto_commit = false;
593
594         if (m_lastkey_with_shift == false
595             && key.mask & SCIM_KEY_ShiftMask
596             && key.code == SCIM_KEY_space
597             && !UnikeyAtWordBeginning())
598         {
599             UnikeyRestoreKeyStrokes();
600         }
601         else if (key.code >= SCIM_KEY_KP_Multiply && key.code <= SCIM_KEY_KP_9)
602             UnikeyPutChar(key.code);
603         else if (m_codertelex && Unikey_IM[m_im] == UkTelex
604                  && (key.code == SCIM_KEY_bracketleft || key.code == SCIM_KEY_bracketright
605                      || key.code == SCIM_KEY_braceleft || key.code == SCIM_KEY_braceright)
606             )
607             UnikeyPutChar(key.code);
608         else
609             UnikeyFilter(key.code);
610
611         if (UnikeyBackspaces > 0)
612         {
613             static int len;
614
615             len = m_preeditstring.length();
616
617             if (len <= UnikeyBackspaces)
618                 m_preeditstring.clear();
619             else
620                 m_preeditstring.erase(len - UnikeyBackspaces, UnikeyBackspaces);
621         }
622
623         if (UnikeyBufChars > 0)
624         {
625             if (Unikey_OC[m_oc] == CONV_CHARSET_XUTF8)
626                 m_preeditstring.append(utf8_mbstowcs((const char*)UnikeyBuf, UnikeyBufChars));
627             else
628             {
629                 static unsigned char buf[1024];
630                 int bufSize=sizeof(buf)/sizeof(buf[0]);
631
632                 latinToUtf(buf, UnikeyBuf, UnikeyBufChars, &bufSize);
633                 m_preeditstring.append(utf8_mbstowcs((const char*)buf, sizeof(buf)/sizeof(buf[0])-bufSize));
634             }
635         }
636         else
637         {    
638             m_preeditstring.push_back(key.get_unicode_code());
639         }
640
641         if (m_preeditstring.length())
642         {
643             if (key.code >= SCIM_KEY_KP_Multiply && key.code <= SCIM_KEY_KP_9)
644             {
645                 commit_string(m_preeditstring);
646                 hide_preedit_string();
647                 m_preeditstring.clear();
648                 reset();
649                 return true;
650             }
651             else
652             {
653                 for (i=0; i < sizeof(WordBreakSyms); i++)
654                     if (WordBreakSyms[i] == m_preeditstring[m_preeditstring.length()-1] && key.code == WordBreakSyms[i])
655                     {
656                         commit_string(m_preeditstring);
657                         hide_preedit_string();
658                         m_preeditstring.clear();
659                         reset();
660                         return true;
661                     }
662             }
663         }
664
665         Unikey_update_preedit_string(m_preeditstring, true);
666         return true;
667     }
668
669     // else (key non process)
670     reset();
671     return false;
672 }
673
674 PropertyList UnikeyInstance::CreatePropertyList()
675 {
676     PropertyList props;
677     int i;
678
679     Property prop("", "", "", "");
680
681 // input method
682     prop.set_key("/Unikey/InputMethod");
683     prop.set_label(Unikey_IMNames[m_im]);
684     prop.set_icon("");
685     prop.set_tip(_("Choose input method"));
686     props.push_back(prop);
687
688     for (i=0; i<NUM_INPUTMETHOD; i++)
689     {
690         prop.set_key(String("/Unikey/InputMethod/") + Unikey_IMNames[i] + String(m_im==i?"-Checked":""));
691         prop.set_label(Unikey_IMNames[i]);
692         prop.set_icon(m_im==i?SCIM_ICONDIR SCIM_UNIKEY_ICON_CHECK:"");
693         prop.set_tip("");
694         props.push_back(prop);
695     }
696
697 // output charset
698
699     prop.set_key("/Unikey/OutputCharset");
700     prop.set_label(Unikey_OCNames[m_oc]);
701     prop.set_icon("");
702     prop.set_tip(_("Choose output charset"));
703     props.push_back(prop);
704
705     for (i=0; i<NUM_OUTPUTCHARSET; i++)
706     {
707         prop.set_key(String("/Unikey/OutputCharset/") + Unikey_OCNames[i] + String(m_oc==i?"-Checked":""));
708         prop.set_label(Unikey_OCNames[i]);
709         prop.set_icon(m_oc==i?SCIM_ICONDIR SCIM_UNIKEY_ICON_CHECK:"");
710         prop.set_tip("");
711         props.push_back(prop);
712     }
713
714 // unikey options
715     // menu
716     prop.set_key("/Unikey/Options");
717     prop.set_label(_("Options"));
718     prop.set_icon(SCIM_ICONDIR SCIM_UNIKEY_ICON_CONFIGURE);
719     prop.set_tip(_("Configure Unikey here"));
720     props.push_back(prop);
721
722     // spellcheck
723     prop.set_key(m_ukopt.spellCheckEnabled?
724                  "/Unikey/Options/SpellCheck/Disable":"/Unikey/Options/SpellCheck/Enable");
725     prop.set_label(_("Enable spell check"));
726     prop.set_icon(m_ukopt.spellCheckEnabled?SCIM_ICONDIR SCIM_UNIKEY_ICON_CHECK:"");
727     prop.set_tip(_("If enable, you can decrease mistake when typing"));
728     props.push_back(prop);
729     
730     // auto restore keystroke
731     prop.set_key(m_ukopt.autoNonVnRestore?
732                  "/Unikey/Options/AutoRestoreKeys/Disable":"/Unikey/Options/AutoRestoreKeys/Enable");
733     prop.set_label(_("Auto restore keys with invalid words"));
734     prop.set_icon(m_ukopt.autoNonVnRestore?SCIM_ICONDIR SCIM_UNIKEY_ICON_CHECK:"");
735     prop.set_tip(_("When typing a word not in Vietnamese,\n"
736                    "it will auto restore keystroke into orginal"));
737     props.push_back(prop);
738
739     // modern style
740     prop.set_key(m_ukopt.modernStyle?
741                  "/Unikey/Options/ModernStyle/Disable":"/Unikey/Options/ModernStyle/Enable");
742     prop.set_label(_("Use oà, uý (instead of òa, úy)"));
743     prop.set_icon(m_ukopt.modernStyle?SCIM_ICONDIR SCIM_UNIKEY_ICON_CHECK:"");
744     prop.set_tip("");
745     props.push_back(prop);
746
747     // freeMarking
748     prop.set_key(m_ukopt.freeMarking?
749                  "/Unikey/Options/FreeMarking/Disable":"/Unikey/Options/FreeMarking/Enable");
750     prop.set_label(_("Allow type with more freedom"));
751     prop.set_icon(m_ukopt.freeMarking?SCIM_ICONDIR SCIM_UNIKEY_ICON_CHECK:"");
752     prop.set_tip("");
753     props.push_back(prop);
754
755     // macro
756     prop.set_key(m_ukopt.macroEnabled?
757                  "/Unikey/Options/EnabledMacro/Disable":"/Unikey/Options/EnabledMacro/Enable");
758     prop.set_label(_("Enable Macro"));
759     prop.set_icon(m_ukopt.macroEnabled?SCIM_ICONDIR SCIM_UNIKEY_ICON_CHECK:"");
760     prop.set_tip("");
761     props.push_back(prop);
762
763     // preedit
764     prop.set_key(m_preedit?"/Unikey/Options/Preedit/Disable":"/Unikey/Options/Preedit/Enable");
765     prop.set_label(_("Enable PreEdit"));
766     prop.set_icon(m_preedit?SCIM_ICONDIR SCIM_UNIKEY_ICON_CHECK:"");
767     prop.set_tip(_("This option is best for most application\n"
768                    "But you may don't like it because it have an underline when typing"));
769     props.push_back(prop);
770
771     // process w at begin
772     prop.set_key(m_process_w_AtBeginWord?
773                  "/Unikey/Options/ProcessWAtBegin/Disable":"/Unikey/Options/ProcessWAtBegin/Enable");
774     prop.set_label(_("Process W at word begin"));
775     prop.set_icon(m_process_w_AtBeginWord?SCIM_ICONDIR SCIM_UNIKEY_ICON_CHECK:"");
776     prop.set_tip(_("If enable, type W at begin\n"
777                    "of word will change to Ư."));
778     props.push_back(prop);
779
780     // coder telex [,],{,}
781     prop.set_key(m_codertelex?
782                  "/Unikey/Options/CoderTelex/Disable":"/Unikey/Options/CoderTelex/Enable");
783     prop.set_label(_("Not use [,],{,} on Telex"));
784     prop.set_icon(m_codertelex?SCIM_ICONDIR SCIM_UNIKEY_ICON_CHECK:"");
785     prop.set_tip(_("Not use [,],{,} for map on Telex"));
786     props.push_back(prop);
787
788
789     return props;
790 }
791
792 void UnikeyInstance::trigger_property(const String &property)
793 {
794     bool change = false;
795     int i;
796
797 // input method
798     if (!property.compare(0, strlen("/Unikey/InputMethod/"), "/Unikey/InputMethod/"))
799     {
800         for (i=0; i<NUM_INPUTMETHOD; i++)
801             if (!property.compare(strlen("/Unikey/InputMethod/"),
802                                   property.length() - strlen("/Unikey/InputMethod/"),
803                                   Unikey_IMNames[i]))
804             {
805                 m_im = i;
806                 __config->write(SCIM_IMENGINE_UNIKEY_INPUTMETHOD, m_im);
807                 change = true;
808                 break;
809             }
810     }
811
812 // output charset
813     else if (!property.compare(0, strlen("/Unikey/OutputCharset/"), "/Unikey/OutputCharset/"))
814     {
815         for (i=0; i<NUM_OUTPUTCHARSET; i++)
816             if (!property.compare(strlen("/Unikey/OutputCharset/"),
817                                   property.length() - strlen("/Unikey/OutputCharset/"),
818                                   Unikey_OCNames[i]))
819             {
820                 m_oc = i;
821                 __config->write(SCIM_IMENGINE_UNIKEY_OUTPUTCHARSET, m_oc);
822                 change = true;
823                 break;
824             }
825     }
826
827 // spellcheck
828     else if (property == "/Unikey/Options/SpellCheck/Enable")
829     {
830         m_ukopt.spellCheckEnabled = true;
831         __config->write(SCIM_IMENGINE_UNIKEY_SPELLCHECKENABLED, true);
832         change = true;
833     }
834     else if (property == "/Unikey/Options/SpellCheck/Disable")
835     {
836         m_ukopt.spellCheckEnabled = false;
837         __config->write(SCIM_IMENGINE_UNIKEY_SPELLCHECKENABLED, false);
838         change = true;
839     }
840
841 // auto restore keystroke
842     else if (property == "/Unikey/Options/AutoRestoreKeys/Enable")
843     {
844         m_ukopt.autoNonVnRestore = true;
845         __config->write(SCIM_IMENGINE_UNIKEY_AUTONONVNRESTORE, true);
846         change = true;
847     }
848     else if (property == "/Unikey/Options/AutoRestoreKeys/Disable")
849     {
850         m_ukopt.autoNonVnRestore = false;
851         __config->write(SCIM_IMENGINE_UNIKEY_AUTONONVNRESTORE, false);
852         change = true;
853     }
854
855 // modern style
856     else if (property == "/Unikey/Options/ModernStyle/Enable")
857     {
858         m_ukopt.modernStyle = true;
859         __config->write(SCIM_IMENGINE_UNIKEY_MODERNSTYLE, true);
860         change = true;
861     }
862     else if (property == "/Unikey/Options/ModernStyle/Disable")
863     {
864         m_ukopt.modernStyle = false;
865         __config->write(SCIM_IMENGINE_UNIKEY_MODERNSTYLE, false);
866         change = true;
867     }
868
869 // free Marking
870     else if (property == "/Unikey/Options/FreeMarking/Enable")
871     {
872         m_ukopt.freeMarking = true;
873         __config->write(SCIM_IMENGINE_UNIKEY_FREEMARKING, true);
874         change = true;
875     }
876     else if (property == "/Unikey/Options/FreeMarking/Disable")
877     {
878         m_ukopt.freeMarking = false;
879         __config->write(SCIM_IMENGINE_UNIKEY_FREEMARKING, false);
880         change = true;
881     }
882 // macro 
883     else if (property == "/Unikey/Options/EnabledMacro/Enable")
884     {
885         m_ukopt.macroEnabled = true;
886         UnikeyLoadMacroTable(getMacroFile());
887         __config->write(SCIM_IMENGINE_UNIKEY_MACROENABLED, true);
888         change = true;
889     }
890     else if (property == "/Unikey/Options/EnabledMacro/Disable")
891     {
892         m_ukopt.macroEnabled = false;
893         __config->write(SCIM_IMENGINE_UNIKEY_MACROENABLED, false);
894         change = true;
895     }
896
897 // preedit
898     else if (property == "/Unikey/Options/Preedit/Enable")
899     {
900         m_preedit = true;
901         __config->write(SCIM_IMENGINE_UNIKEY_PREEDIT, true);
902         change = true;
903     }
904     else if (property == "/Unikey/Options/Preedit/Disable")
905     {
906         m_preedit = false;
907         __config->write(SCIM_IMENGINE_UNIKEY_PREEDIT, false);
908         change = true;
909     }
910
911 // process w at begin
912     else if (property == "/Unikey/Options/ProcessWAtBegin/Enable")
913     {
914         m_process_w_AtBeginWord = true;
915         __config->write(SCIM_IMENGINE_UNIKEY_PROCESSWATWORDBEGIN, true);
916         change = true;
917     }
918     else if (property == "/Unikey/Options/ProcessWAtBegin/Disable")
919     {
920         m_process_w_AtBeginWord = false;
921         __config->write(SCIM_IMENGINE_UNIKEY_PROCESSWATWORDBEGIN, false);
922         change = true;
923     }
924
925 // coder telex
926     else if (property == "/Unikey/Options/CoderTelex/Enable")
927     {
928         m_codertelex = true;
929         __config->write(SCIM_IMENGINE_UNIKEY_CODERTELEX, true);
930         change = true;
931     }
932     else if (property == "/Unikey/Options/CoderTelex/Disable")
933     {
934         m_codertelex = false;
935         __config->write(SCIM_IMENGINE_UNIKEY_CODERTELEX, false);
936         change = true;
937     }
938
939     if (change)
940     {
941         __config->flush();
942         focus_out();
943         focus_in();
944     }
945 }