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