1 /* vim:set et ts=4 sts=4:
2  *
3  * ibus-pinyin - The Chinese PinYin engine for IBus
4  *
5  * Copyright (c) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20  */
21 #include "PYConfig.h"
22 
23 #include "PYBus.h"
24 #include "PYTypes.h"
25 
26 namespace PY {
27 
28 const gchar * const CONFIG_CORRECT_PINYIN            = "CorrectPinyin";
29 const gchar * const CONFIG_FUZZY_PINYIN              = "FuzzyPinyin";
30 const gchar * const CONFIG_ORIENTATION               = "LookupTableOrientation";
31 const gchar * const CONFIG_PAGE_SIZE                 = "LookupTablePageSize";
32 const gchar * const CONFIG_SHIFT_SELECT_CANDIDATE    = "ShiftSelectCandidate";
33 const gchar * const CONFIG_MINUS_EQUAL_PAGE          = "MinusEqualPage";
34 const gchar * const CONFIG_COMMA_PERIOD_PAGE         = "CommaPeriodPage";
35 const gchar * const CONFIG_AUTO_COMMIT               = "AutoCommit";
36 const gchar * const CONFIG_DOUBLE_PINYIN             = "DoublePinyin";
37 const gchar * const CONFIG_DOUBLE_PINYIN_SCHEMA      = "DoublePinyinSchema";
38 const gchar * const CONFIG_DOUBLE_PINYIN_SHOW_RAW    = "DoublePinyinShowRaw";
39 const gchar * const CONFIG_INIT_CHINESE              = "InitChinese";
40 const gchar * const CONFIG_INIT_FULL                 = "InitFull";
41 const gchar * const CONFIG_INIT_FULL_PUNCT           = "InitFullPunct";
42 const gchar * const CONFIG_INIT_SIMP_CHINESE         = "InitSimplifiedChinese";
43 const gchar * const CONFIG_SPECIAL_PHRASES           = "SpecialPhrases";
44 const gchar * const CONFIG_BOPOMOFO_KEYBOARD_MAPPING = "BopomofoKeyboardMapping";
45 const gchar * const CONFIG_SELECT_KEYS               = "SelectKeys";
46 const gchar * const CONFIG_GUIDE_KEY                 = "GuideKey";
47 const gchar * const CONFIG_AUXILIARY_SELECT_KEY_F    = "AuxiliarySelectKey_F";
48 const gchar * const CONFIG_AUXILIARY_SELECT_KEY_KP   = "AuxiliarySelectKey_KP";
49 const gchar * const CONFIG_ENTER_KEY                 = "EnterKey";
50 
51 const guint PINYIN_DEFAULT_OPTION =
52         PINYIN_INCOMPLETE_PINYIN |
53         PINYIN_FUZZY_C_CH |
54         // PINYIN_FUZZY_CH_C |
55         PINYIN_FUZZY_Z_ZH |
56         // PINYIN_FUZZY_ZH_Z |
57         PINYIN_FUZZY_S_SH |
58         // PINYIN_FUZZY_SH_S |
59         PINYIN_FUZZY_L_N |
60         // PINYIN_FUZZY_N_L |
61         PINYIN_FUZZY_F_H |
62         // PINYIN_FUZZY_H_F |
63         // PINYIN_FUZZY_L_R |
64         // PINYIN_FUZZY_R_L |
65         PINYIN_FUZZY_K_G |
66         PINYIN_FUZZY_G_K |
67         PINYIN_FUZZY_AN_ANG |
68         PINYIN_FUZZY_ANG_AN |
69         PINYIN_FUZZY_EN_ENG |
70         PINYIN_FUZZY_ENG_EN |
71         PINYIN_FUZZY_IN_ING |
72         PINYIN_FUZZY_ING_IN |
73         // PINYIN_FUZZY_IAN_IANG |
74         // PINYIN_FUZZY_IANG_IAN |
75         // PINYIN_FUZZY_UAN_UANG |
76         // PINYIN_FUZZY_UANG_UAN |
77         0;
78 
79 std::unique_ptr<PinyinConfig> PinyinConfig::m_instance;
80 std::unique_ptr<BopomofoConfig> BopomofoConfig::m_instance;
81 
Config(Bus & bus,const std::string & name)82 Config::Config (Bus & bus, const std::string & name)
83     : Object (ibus_bus_get_config (bus)),
84       m_section ("engine/" + name)
85 {
86     initDefaultValues ();
87     g_signal_connect (get<IBusConfig> (),
88                       "value-changed",
89                       G_CALLBACK (valueChangedCallback),
90                       this);
91 }
92 
~Config(void)93 Config::~Config (void)
94 {
95 }
96 
97 void
initDefaultValues(void)98 Config::initDefaultValues (void)
99 {
100     m_option = PINYIN_DEFAULT_OPTION;
101     m_option_mask = PINYIN_INCOMPLETE_PINYIN | PINYIN_CORRECT_ALL;
102     updateContext (PyZy::InputContext::PROPERTY_CONVERSION_OPTION,
103                    PyZy::Variant::fromUnsignedInt (option ()));
104 
105     m_orientation = IBUS_ORIENTATION_HORIZONTAL;
106     m_page_size = 5;
107     m_shift_select_candidate = FALSE;
108     m_minus_equal_page = TRUE;
109     m_comma_period_page = TRUE;
110     m_auto_commit = FALSE;
111 
112     m_init_chinese = TRUE;
113     m_init_full = FALSE;
114     m_init_full_punct = TRUE;
115     m_init_simp_chinese = TRUE;
116     m_special_phrases = TRUE;
117     m_double_pinyin = FALSE;
118     updateContext (PyZy::InputContext::PROPERTY_SPECIAL_PHRASE,
119                    PyZy::Variant::fromBool (m_special_phrases));
120 }
121 
122 static const struct {
123     const gchar * const name;
124     guint option;
125 } options [] = {
126     { "IncompletePinyin",       PINYIN_INCOMPLETE_PINYIN},
127     /* fuzzy pinyin */
128     { "FuzzyPinyin_C_CH",       PINYIN_FUZZY_C_CH      },
129     { "FuzzyPinyin_CH_C",       PINYIN_FUZZY_CH_C      },
130     { "FuzzyPinyin_Z_ZH",       PINYIN_FUZZY_Z_ZH      },
131     { "FuzzyPinyin_ZH_Z",       PINYIN_FUZZY_ZH_Z      },
132     { "FuzzyPinyin_S_SH",       PINYIN_FUZZY_S_SH      },
133     { "FuzzyPinyin_SH_S",       PINYIN_FUZZY_SH_S      },
134     { "FuzzyPinyin_L_N",        PINYIN_FUZZY_L_N       },
135     { "FuzzyPinyin_N_L",        PINYIN_FUZZY_N_L       },
136     { "FuzzyPinyin_F_H",        PINYIN_FUZZY_F_H       },
137     { "FuzzyPinyin_H_F",        PINYIN_FUZZY_H_F       },
138     { "FuzzyPinyin_L_R",        PINYIN_FUZZY_L_R       },
139     { "FuzzyPinyin_R_L",        PINYIN_FUZZY_R_L       },
140     { "FuzzyPinyin_K_G",        PINYIN_FUZZY_K_G       },
141     { "FuzzyPinyin_G_K",        PINYIN_FUZZY_G_K       },
142     { "FuzzyPinyin_AN_ANG",     PINYIN_FUZZY_AN_ANG    },
143     { "FuzzyPinyin_ANG_AN",     PINYIN_FUZZY_ANG_AN    },
144     { "FuzzyPinyin_EN_ENG",     PINYIN_FUZZY_EN_ENG    },
145     { "FuzzyPinyin_ENG_EN",     PINYIN_FUZZY_ENG_EN    },
146     { "FuzzyPinyin_IN_ING",     PINYIN_FUZZY_IN_ING    },
147     { "FuzzyPinyin_ING_IN",     PINYIN_FUZZY_ING_IN    },
148 #if 0
149     { "FuzzyPinyin_IAN_IANG",   PINYIN_FUZZY_IAN_IANG  },
150     { "FuzzyPinyin_IANG_IAN",   PINYIN_FUZZY_IANG_IAN  },
151     { "FuzzyPinyin_UAN_UANG",   PINYIN_FUZZY_UAN_UANG  },
152     { "FuzzyPinyin_UANG_UAN",   PINYIN_FUZZY_UANG_UAN  },
153 #endif
154 };
155 
156 void
readDefaultValues(void)157 Config::readDefaultValues (void)
158 {
159 #if defined(HAVE_IBUS_CONFIG_GET_VALUES)
160     /* read all values together */
161     initDefaultValues ();
162     GVariant *values =
163             ibus_config_get_values (get<IBusConfig> (), m_section.c_str ());
164     g_return_if_fail (values != NULL);
165 
166     GVariantIter iter;
167     gchar *name;
168     GVariant *value;
169     g_variant_iter_init (&iter, values);
170     while (g_variant_iter_next (&iter, "{sv}", &name, &value)) {
171         valueChanged (m_section, name, value);
172         g_free (name);
173         g_variant_unref (value);
174     }
175     g_variant_unref (values);
176 #else
177     /* others */
178     m_orientation = read (CONFIG_ORIENTATION, 0);
179     if (m_orientation != IBUS_ORIENTATION_VERTICAL &&
180         m_orientation != IBUS_ORIENTATION_HORIZONTAL) {
181         m_orientation = IBUS_ORIENTATION_HORIZONTAL;
182         g_warn_if_reached ();
183     }
184     m_page_size = read (CONFIG_PAGE_SIZE, 5);
185     if (m_page_size > 10) {
186         m_page_size = 5;
187         g_warn_if_reached ();
188     }
189 
190     /* fuzzy pinyin */
191     if (read (CONFIG_FUZZY_PINYIN, false))
192         m_option_mask |= PINYIN_FUZZY_ALL;
193     else
194         m_option_mask &= ~PINYIN_FUZZY_ALL;
195 
196     /* read values */
197     for (guint i = 0; i < G_N_ELEMENTS (options); i++) {
198         if (read (options[i].name,
199                   (options[i].option & PINYIN_DEFAULT_OPTION) != 0)) {
200             m_option |= options[i].option;
201         }
202         else {
203             m_option &= ~options[i].option;
204         }
205     }
206     updateContext (PyZy::InputContext::PROPERTY_CONVERSION_OPTION,
207                    PyZy::Variant::fromUnsignedInt (option ()));
208 #endif
209 }
210 
211 inline bool
read(const gchar * name,bool defval)212 Config::read (const gchar * name,
213               bool          defval)
214 {
215     GVariant *value = NULL;
216     if ((value = ibus_config_get_value (get<IBusConfig> (), m_section.c_str (), name)) != NULL) {
217         if (g_variant_classify (value) == G_VARIANT_CLASS_BOOLEAN)
218             return g_variant_get_boolean (value);
219     }
220 
221     // write default value to config
222     value = g_variant_new ("b", defval);
223     ibus_config_set_value (get<IBusConfig> (), m_section.c_str (), name, value);
224 
225     return defval;
226 }
227 
228 inline gint
read(const gchar * name,gint defval)229 Config::read (const gchar * name,
230               gint          defval)
231 {
232     GVariant *value = NULL;
233     if ((value = ibus_config_get_value (get<IBusConfig> (), m_section.c_str (), name)) != NULL) {
234         if (g_variant_classify (value) == G_VARIANT_CLASS_INT32)
235             return g_variant_get_int32 (value);
236     }
237 
238     // write default value to config
239     value = g_variant_new ("i", defval);
240     ibus_config_set_value (get<IBusConfig> (), m_section.c_str (), name, value);
241 
242     return defval;
243 }
244 
245 inline std::string
read(const gchar * name,const gchar * defval)246 Config::read (const gchar * name,
247               const gchar * defval)
248 {
249     GVariant *value = NULL;
250     if ((value = ibus_config_get_value (get<IBusConfig> (), m_section.c_str (), name)) != NULL) {
251         if (g_variant_classify (value) == G_VARIANT_CLASS_STRING)
252             return g_variant_get_string (value, NULL);
253     }
254 
255     // write default value to config
256     value = g_variant_new ("s", defval);
257     ibus_config_set_value (get<IBusConfig> (), m_section.c_str (), name, value);
258 
259     return defval;
260 }
261 
262 static inline bool
normalizeGVariant(GVariant * value,bool defval)263 normalizeGVariant (GVariant *value, bool defval)
264 {
265     if (value == NULL || g_variant_classify (value) != G_VARIANT_CLASS_BOOLEAN)
266         return defval;
267     return g_variant_get_boolean (value);
268 }
269 
270 static inline gint
normalizeGVariant(GVariant * value,gint defval)271 normalizeGVariant (GVariant *value, gint defval)
272 {
273     if (value == NULL || g_variant_classify (value) != G_VARIANT_CLASS_INT32)
274         return defval;
275     return g_variant_get_int32 (value);
276 }
277 
278 static inline std::string
normalizeGVariant(GVariant * value,const std::string & defval)279 normalizeGVariant (GVariant *value, const std::string &defval)
280 {
281     if (value == NULL || g_variant_classify (value) != G_VARIANT_CLASS_STRING)
282         return defval;
283     return g_variant_get_string (value, NULL);
284 }
285 
286 gboolean
valueChanged(const std::string & section,const std::string & name,GVariant * value)287 Config::valueChanged (const std::string &section,
288                       const std::string &name,
289                       GVariant          *value)
290 {
291     if (m_section != section)
292         return FALSE;
293 
294     /* lookup table page size */
295     if (CONFIG_ORIENTATION == name) {
296         m_orientation = normalizeGVariant (value, IBUS_ORIENTATION_HORIZONTAL);
297         if (m_orientation != IBUS_ORIENTATION_VERTICAL &&
298             m_orientation != IBUS_ORIENTATION_HORIZONTAL) {
299             m_orientation = IBUS_ORIENTATION_HORIZONTAL;
300             g_warn_if_reached ();
301         }
302     }
303     else if (CONFIG_PAGE_SIZE == name) {
304         m_page_size = normalizeGVariant (value, 5);
305         if (m_page_size > 10) {
306             m_page_size = 5;
307             g_warn_if_reached ();
308         }
309     }
310     /* fuzzy pinyin */
311     else if (CONFIG_FUZZY_PINYIN == name) {
312         if (normalizeGVariant (value, false))
313             m_option_mask |= PINYIN_FUZZY_ALL;
314         else
315             m_option_mask &= ~PINYIN_FUZZY_ALL;
316         updateContext (PyZy::InputContext::PROPERTY_CONVERSION_OPTION,
317                        PyZy::Variant::fromUnsignedInt (option ()));
318     }
319     else {
320         for (guint i = 0; i < G_N_ELEMENTS (options); i++) {
321             if (G_LIKELY (options[i].name != name))
322                 continue;
323             if (normalizeGVariant (value,
324                     (options[i].option & PINYIN_DEFAULT_OPTION) != 0))
325                 m_option |= options[i].option;
326             else
327                 m_option &= ~options[i].option;
328             updateContext (PyZy::InputContext::PROPERTY_CONVERSION_OPTION,
329                            PyZy::Variant::fromUnsignedInt (option ()));
330             return TRUE;
331         }
332         return FALSE;
333     }
334     return TRUE;
335 }
336 
337 void
valueChangedCallback(IBusConfig * config,const gchar * section,const gchar * name,GVariant * value,Config * self)338 Config::valueChangedCallback (IBusConfig  *config,
339                               const gchar *section,
340                               const gchar *name,
341                               GVariant    *value,
342                               Config      *self)
343 {
344     self->valueChanged (section, name, value);
345 }
346 
347 void
addContext(PyZy::InputContext * context)348 Config::addContext (PyZy::InputContext *context)
349 {
350     context->setProperty (PyZy::InputContext::PROPERTY_CONVERSION_OPTION,
351                           PyZy::Variant::fromUnsignedInt (option ()));
352     context->setProperty (PyZy::InputContext::PROPERTY_SPECIAL_PHRASE,
353                           PyZy::Variant::fromBool (m_special_phrases));
354 
355     m_contexts.insert (context);
356 }
357 
358 bool
removeContext(PyZy::InputContext * context)359 Config::removeContext (PyZy::InputContext *context)
360 {
361     return m_contexts.erase (context);
362 }
363 
364 void
updateContext(PyZy::InputContext::PropertyName name,const PyZy::Variant & variant)365 Config::updateContext (PyZy::InputContext::PropertyName name,
366                        const PyZy::Variant & variant)
367 {
368     for (std::set<PyZy::InputContext *>::iterator it = m_contexts.begin ();
369          it != m_contexts.end(); ++it) {
370         (*it)->setProperty (name, variant);
371     }
372 }
373 
374 static const struct {
375     const gchar * const name;
376     guint option;
377 } pinyin_options [] = {
378     /* correct */
379     { "CorrectPinyin_GN_NG",    PINYIN_CORRECT_GN_TO_NG    },
380     { "CorrectPinyin_GN_NG",    PINYIN_CORRECT_GN_TO_NG    },
381     { "CorrectPinyin_MG_NG",    PINYIN_CORRECT_MG_TO_NG    },
382     { "CorrectPinyin_IOU_IU",   PINYIN_CORRECT_IOU_TO_IU   },
383     { "CorrectPinyin_UEI_UI",   PINYIN_CORRECT_UEI_TO_UI   },
384     { "CorrectPinyin_UEN_UN",   PINYIN_CORRECT_UEN_TO_UN   },
385     { "CorrectPinyin_UE_VE",    PINYIN_CORRECT_UE_TO_VE    },
386     { "CorrectPinyin_V_U",      PINYIN_CORRECT_V_TO_U      },
387     { "CorrectPinyin_VE_UE",    PINYIN_CORRECT_V_TO_U      },
388     { "CorrectPinyin_ON_ONG",   PINYIN_CORRECT_ON_TO_ONG   },
389 };
390 
PinyinConfig(Bus & bus)391 PinyinConfig::PinyinConfig (Bus & bus)
392     : Config (bus, "Pinyin")
393 {
394 }
395 
396 void
init(Bus & bus)397 PinyinConfig::init (Bus & bus)
398 {
399     if (m_instance.get () == NULL) {
400         m_instance.reset (new PinyinConfig (bus));
401         m_instance->readDefaultValues ();
402     }
403 }
404 
405 void
readDefaultValues(void)406 PinyinConfig::readDefaultValues (void)
407 {
408     Config::readDefaultValues ();
409 #if !defined(HAVE_IBUS_CONFIG_GET_VALUES)
410     /* double pinyin */
411     m_double_pinyin = read (CONFIG_DOUBLE_PINYIN, false);
412     m_double_pinyin_schema = read (CONFIG_DOUBLE_PINYIN_SCHEMA, 0);
413     if (m_double_pinyin_schema >= DOUBLE_PINYIN_KEYBOARD_LAST) {
414         m_double_pinyin_schema = 0;
415         g_warn_if_reached ();
416     }
417     updateContext (PyZy::InputContext::PROPERTY_DOUBLE_PINYIN_SCHEMA,
418                    PyZy::Variant::fromUnsignedInt (m_double_pinyin_schema));
419     m_double_pinyin_show_raw = read (CONFIG_DOUBLE_PINYIN_SHOW_RAW, false);
420 
421     /* init states */
422     m_init_chinese = read (CONFIG_INIT_CHINESE, true);
423     m_init_full = read (CONFIG_INIT_FULL, false);
424     m_init_full_punct = read (CONFIG_INIT_FULL_PUNCT, true);
425     m_init_simp_chinese = read (CONFIG_INIT_SIMP_CHINESE, true);
426 
427     m_special_phrases = read (CONFIG_SPECIAL_PHRASES, true);
428     updateContext (PyZy::InputContext::PROPERTY_SPECIAL_PHRASE,
429                    PyZy::Variant::fromBool (m_special_phrases));
430 
431     /* other */
432     m_shift_select_candidate = read (CONFIG_SHIFT_SELECT_CANDIDATE, false);
433     m_minus_equal_page = read (CONFIG_MINUS_EQUAL_PAGE, true);
434     m_comma_period_page = read (CONFIG_COMMA_PERIOD_PAGE, true);
435     m_auto_commit = read (CONFIG_AUTO_COMMIT, false);
436 
437     /* correct pinyin */
438     if (read (CONFIG_CORRECT_PINYIN, true))
439         m_option_mask |= PINYIN_CORRECT_ALL;
440     else
441         m_option_mask &= ~PINYIN_CORRECT_ALL;
442 
443     /* read values */
444     for (guint i = 0; i < G_N_ELEMENTS (pinyin_options); i++) {
445         if (read (pinyin_options[i].name,
446                 (pinyin_options[i].option & PINYIN_DEFAULT_OPTION) != 0))
447             m_option |= pinyin_options[i].option;
448         else
449             m_option &= ~pinyin_options[i].option;
450     }
451     updateContext (PyZy::InputContext::PROPERTY_CONVERSION_OPTION,
452                    PyZy::Variant::fromUnsignedInt (option ()));
453 #endif
454 }
455 
456 gboolean
valueChanged(const std::string & section,const std::string & name,GVariant * value)457 PinyinConfig::valueChanged (const std::string &section,
458                             const std::string &name,
459                             GVariant          *value)
460 {
461     if (m_section != section)
462         return FALSE;
463 
464     if (Config::valueChanged (section, name, value))
465         return TRUE;
466 
467     /* double pinyin */
468     if (CONFIG_DOUBLE_PINYIN == name)
469         m_double_pinyin = normalizeGVariant (value, false);
470     else if (CONFIG_DOUBLE_PINYIN_SCHEMA == name) {
471         m_double_pinyin_schema = normalizeGVariant (value, 0);
472         if (m_double_pinyin_schema >= DOUBLE_PINYIN_KEYBOARD_LAST) {
473             m_double_pinyin_schema = 0;
474             g_warn_if_reached ();
475         }
476         updateContext (PyZy::InputContext::PROPERTY_DOUBLE_PINYIN_SCHEMA,
477                        PyZy::Variant::fromUnsignedInt (m_double_pinyin_schema));
478     }
479     else if (CONFIG_DOUBLE_PINYIN_SHOW_RAW == name)
480         m_double_pinyin_show_raw = normalizeGVariant (value, false);
481     /* init states */
482     else if (CONFIG_INIT_CHINESE == name)
483         m_init_chinese = normalizeGVariant (value, true);
484     else if (CONFIG_INIT_FULL == name)
485         m_init_full = normalizeGVariant (value, true);
486     else if (CONFIG_INIT_FULL_PUNCT == name)
487         m_init_full_punct = normalizeGVariant (value, true);
488     else if (CONFIG_INIT_SIMP_CHINESE == name)
489         m_init_simp_chinese = normalizeGVariant (value, true);
490     else if (CONFIG_SPECIAL_PHRASES == name) {
491         m_special_phrases = normalizeGVariant (value, true);
492         updateContext (PyZy::InputContext::PROPERTY_SPECIAL_PHRASE,
493                        PyZy::Variant::fromBool (m_special_phrases));
494     }
495     /* others */
496     else if (CONFIG_SHIFT_SELECT_CANDIDATE == name)
497         m_shift_select_candidate = normalizeGVariant (value, false);
498     else if (CONFIG_MINUS_EQUAL_PAGE == name)
499         m_minus_equal_page = normalizeGVariant (value, true);
500     else if (CONFIG_COMMA_PERIOD_PAGE == name)
501         m_comma_period_page = normalizeGVariant (value, true);
502     else if (CONFIG_AUTO_COMMIT == name)
503         m_auto_commit = normalizeGVariant (value, false);
504     /* correct pinyin */
505     else if (CONFIG_CORRECT_PINYIN == name) {
506         if (normalizeGVariant (value, true))
507             m_option_mask |= PINYIN_CORRECT_ALL;
508         else
509             m_option_mask &= ~PINYIN_CORRECT_ALL;
510         updateContext (PyZy::InputContext::PROPERTY_CONVERSION_OPTION,
511                        PyZy::Variant::fromUnsignedInt (option ()));
512     }
513     else {
514         for (guint i = 0; i < G_N_ELEMENTS (pinyin_options); i++) {
515             if (G_LIKELY (pinyin_options[i].name != name))
516                 continue;
517             if (normalizeGVariant (value,
518                     (pinyin_options[i].option & PINYIN_DEFAULT_OPTION) != 0))
519                 m_option |= pinyin_options[i].option;
520             else
521                 m_option &= ~pinyin_options[i].option;
522             updateContext (PyZy::InputContext::PROPERTY_CONVERSION_OPTION,
523                            PyZy::Variant::fromUnsignedInt (option ()));
524             return TRUE;
525         }
526         return FALSE;
527     }
528     return TRUE;
529 }
530 
531 void
addContext(PyZy::InputContext * context)532 PinyinConfig::addContext (PyZy::InputContext *context)
533 {
534     context->setProperty (
535         PyZy::InputContext::PROPERTY_DOUBLE_PINYIN_SCHEMA,
536         PyZy::Variant::fromUnsignedInt (m_double_pinyin_schema));
537 
538     Config::addContext (context);
539 }
540 
BopomofoConfig(Bus & bus)541 BopomofoConfig::BopomofoConfig (Bus & bus)
542     : Config (bus, "Bopomofo")
543 {
544 }
545 
546 void
init(Bus & bus)547 BopomofoConfig::init (Bus & bus)
548 {
549     if (m_instance.get () == NULL) {
550         m_instance.reset (new BopomofoConfig (bus));
551         m_instance->readDefaultValues ();
552     }
553 }
554 
555 void
readDefaultValues(void)556 BopomofoConfig::readDefaultValues (void)
557 {
558     Config::readDefaultValues ();
559 #if !defined(HAVE_IBUS_CONFIG_GET_VALUES)
560     /* init states */
561     m_init_chinese = read (CONFIG_INIT_CHINESE, true);
562     m_init_full = read (CONFIG_INIT_FULL, false);
563     m_init_full_punct = read (CONFIG_INIT_FULL_PUNCT, true);
564     m_init_simp_chinese = read (CONFIG_INIT_SIMP_CHINESE, false);
565 
566     m_special_phrases = read (CONFIG_SPECIAL_PHRASES, false);
567     updateContext (PyZy::InputContext::PROPERTY_SPECIAL_PHRASE,
568                    PyZy::Variant::fromBool (m_special_phrases));
569 
570     m_bopomofo_keyboard_mapping = read (CONFIG_BOPOMOFO_KEYBOARD_MAPPING, 0);
571     updateContext (PyZy::InputContext::PROPERTY_BOPOMOFO_SCHEMA,
572                    PyZy::Variant::fromUnsignedInt (m_bopomofo_keyboard_mapping));
573 
574     m_select_keys = read (CONFIG_SELECT_KEYS, 0);
575     if (m_select_keys >= 9) m_select_keys = 0;
576     m_guide_key = read (CONFIG_GUIDE_KEY, true);
577     m_auxiliary_select_key_f = read (CONFIG_AUXILIARY_SELECT_KEY_F, true);
578     m_auxiliary_select_key_kp = read (CONFIG_AUXILIARY_SELECT_KEY_KP, true);
579     m_enter_key = read (CONFIG_ENTER_KEY, true);
580 #endif
581 }
582 
583 gboolean
valueChanged(const std::string & section,const std::string & name,GVariant * value)584 BopomofoConfig::valueChanged (const std::string &section,
585                               const std::string &name,
586                               GVariant          *value)
587 {
588     if (m_section != section)
589         return FALSE;
590 
591     if (Config::valueChanged (section, name, value))
592         return TRUE;
593 
594     /* init states */
595     if (CONFIG_INIT_CHINESE == name)
596         m_init_chinese = normalizeGVariant (value, true);
597     else if (CONFIG_INIT_FULL == name)
598         m_init_full = normalizeGVariant (value, true);
599     else if (CONFIG_INIT_FULL_PUNCT == name)
600         m_init_full_punct = normalizeGVariant (value, true);
601     else if (CONFIG_INIT_SIMP_CHINESE == name)
602         m_init_simp_chinese = normalizeGVariant (value, false);
603     else if (CONFIG_SPECIAL_PHRASES == name) {
604         m_special_phrases = normalizeGVariant (value, false);
605         updateContext (PyZy::InputContext::PROPERTY_SPECIAL_PHRASE,
606                        PyZy::Variant::fromBool (m_special_phrases));
607     }
608     else if (CONFIG_BOPOMOFO_KEYBOARD_MAPPING == name) {
609         m_bopomofo_keyboard_mapping = normalizeGVariant (value, 0);
610         updateContext (PyZy::InputContext::PROPERTY_BOPOMOFO_SCHEMA,
611                        PyZy::Variant::fromUnsignedInt (m_bopomofo_keyboard_mapping));
612     }
613     else if (CONFIG_SELECT_KEYS == name) {
614         m_select_keys = normalizeGVariant (value, 0);
615         if (m_select_keys >= 9) m_select_keys = 0;
616     }
617     else if (CONFIG_GUIDE_KEY == name)
618         m_guide_key = normalizeGVariant (value, true);
619     else if (CONFIG_AUXILIARY_SELECT_KEY_F == name)
620         m_auxiliary_select_key_f = normalizeGVariant (value, true);
621     else if (CONFIG_AUXILIARY_SELECT_KEY_KP == name)
622         m_auxiliary_select_key_kp = normalizeGVariant (value, true);
623     else if (CONFIG_ENTER_KEY == name)
624         m_enter_key = normalizeGVariant (value, true);
625     else
626         return FALSE;
627     return TRUE;
628 
629 }
630 
631 void
addContext(PyZy::InputContext * context)632 BopomofoConfig::addContext (PyZy::InputContext *context)
633 {
634     context->setProperty (
635         PyZy::InputContext::PROPERTY_BOPOMOFO_SCHEMA,
636         PyZy::Variant::fromUnsignedInt (m_bopomofo_keyboard_mapping));
637 
638     Config::addContext (context);
639 }
640 };
641