1 /* vim:set et ts=4 sts=4:
3 * ibus-libpinyin - Intelligent Pinyin engine based on libpinyin for IBus
5 * Copyright (c) 2011 Peng Wu <alexepico@gmail.com>
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)
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.
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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include "PYLibPinyin.h"
26 #include "PYPConfig.h"
28 #define LIBPINYIN_SAVE_TIMEOUT (5 * 60)
32 std::unique_ptr<LibPinyinBackEnd> LibPinyinBackEnd::m_instance;
34 static LibPinyinBackEnd libpinyin_backend;
36 LibPinyinBackEnd::LibPinyinBackEnd () {
38 m_timer = g_timer_new();
39 m_pinyin_context = NULL;
40 m_chewing_context = NULL;
43 LibPinyinBackEnd::~LibPinyinBackEnd () {
44 g_timer_destroy (m_timer);
45 if (m_timeout_id != 0) {
47 g_source_remove (m_timeout_id);
51 pinyin_fini(m_pinyin_context);
52 m_pinyin_context = NULL;
53 if (m_chewing_context)
54 pinyin_fini(m_chewing_context);
55 m_chewing_context = NULL;
59 LibPinyinBackEnd::initPinyinContext (Config *config)
61 pinyin_context_t * context = NULL;
63 gchar * userdir = g_build_filename (g_get_user_cache_dir (),
64 "ibus", "libpinyin", NULL);
65 int retval = g_mkdir_with_parents (userdir, 0700);
67 g_free(userdir); userdir = NULL;
69 context = pinyin_init (LIBPINYIN_DATADIR, userdir);
72 const char *dicts = config->dictionaries ().c_str ();
73 gchar ** indices = g_strsplit_set (dicts, ";", -1);
74 for (size_t i = 0; i < g_strv_length(indices); ++i) {
75 int index = atoi (indices [i]);
79 pinyin_load_phrase_library (context, index);
83 /* load user phrase library. */
84 pinyin_load_phrase_library (context, USER_DICTIONARY);
90 LibPinyinBackEnd::allocPinyinInstance ()
92 Config * config = &LibPinyinPinyinConfig::instance ();
93 if (NULL == m_pinyin_context) {
94 m_pinyin_context = initPinyinContext (config);
97 setPinyinOptions (config);
98 return pinyin_alloc_instance (m_pinyin_context);
102 LibPinyinBackEnd::freePinyinInstance (pinyin_instance_t *instance)
104 pinyin_free_instance (instance);
108 LibPinyinBackEnd::initChewingContext (Config *config)
110 pinyin_context_t * context = NULL;
112 gchar * userdir = g_build_filename (g_get_user_cache_dir (),
113 "ibus", "libbopomofo", NULL);
114 int retval = g_mkdir_with_parents (userdir, 0700);
116 g_free(userdir); userdir = NULL;
118 context = pinyin_init (LIBPINYIN_DATADIR, userdir);
121 const char *dicts = config->dictionaries ().c_str ();
122 gchar ** indices = g_strsplit_set (dicts, ";", -1);
123 for (size_t i = 0; i < g_strv_length(indices); ++i) {
124 int index = atoi (indices [i]);
128 pinyin_load_phrase_library (context, index);
130 g_strfreev (indices);
136 LibPinyinBackEnd::allocChewingInstance ()
138 Config *config = &LibPinyinBopomofoConfig::instance ();
139 if (NULL == m_chewing_context) {
140 m_chewing_context = initChewingContext (config);
143 setChewingOptions (config);
144 return pinyin_alloc_instance (m_chewing_context);
148 LibPinyinBackEnd::freeChewingInstance (pinyin_instance_t *instance)
150 pinyin_free_instance (instance);
154 LibPinyinBackEnd::init (void) {
155 g_assert (NULL == m_instance.get ());
156 LibPinyinBackEnd * backend = new LibPinyinBackEnd;
157 m_instance.reset (backend);
161 LibPinyinBackEnd::finalize (void) {
165 /* Here are the double pinyin keyboard scheme mapping table. */
167 gint double_pinyin_keyboard;
168 DoublePinyinScheme scheme;
169 } double_pinyin_options [] = {
170 {0, DOUBLE_PINYIN_MS},
171 {1, DOUBLE_PINYIN_ZRM},
172 {2, DOUBLE_PINYIN_ABC},
173 {3, DOUBLE_PINYIN_ZIGUANG},
174 {4, DOUBLE_PINYIN_PYJJ},
175 {5, DOUBLE_PINYIN_XHE}
179 LibPinyinBackEnd::setPinyinOptions (Config *config)
181 if (NULL == m_pinyin_context)
184 const gint map = config->doublePinyinSchema ();
185 for (guint i = 0; i < G_N_ELEMENTS (double_pinyin_options); i++) {
186 if (map == double_pinyin_options[i].double_pinyin_keyboard) {
187 /* set double pinyin scheme. */
188 DoublePinyinScheme scheme = double_pinyin_options[i].scheme;
189 pinyin_set_double_pinyin_scheme (m_pinyin_context, scheme);
193 pinyin_option_t options = config->option()
194 | USE_RESPLIT_TABLE | USE_DIVIDED_TABLE;
195 pinyin_set_options (m_pinyin_context, options);
199 /* Here are the chewing keyboard scheme mapping table. */
200 static const struct {
201 gint bopomofo_keyboard;
202 ChewingScheme scheme;
203 } chewing_options [] = {
204 {0, CHEWING_STANDARD},
205 {1, CHEWING_GINYIEH},
212 LibPinyinBackEnd::setChewingOptions (Config *config)
214 if (NULL == m_chewing_context)
217 const gint map = config->bopomofoKeyboardMapping ();
218 for (guint i = 0; i < G_N_ELEMENTS (chewing_options); i++) {
219 if (map == chewing_options[i].bopomofo_keyboard) {
220 /* TODO: set chewing scheme. */
221 ChewingScheme scheme = chewing_options[i].scheme;
222 pinyin_set_chewing_scheme (m_chewing_context, scheme);
226 pinyin_option_t options = config->option() | USE_TONE;
227 pinyin_set_options(m_chewing_context, options);
232 LibPinyinBackEnd::modified (void)
234 /* Restart the timer */
235 g_timer_start (m_timer);
237 if (m_timeout_id != 0)
240 m_timeout_id = g_timeout_add_seconds (LIBPINYIN_SAVE_TIMEOUT,
241 LibPinyinBackEnd::timeoutCallback,
242 static_cast<gpointer> (this));
246 LibPinyinBackEnd::importPinyinDictionary (const char * filename)
248 /* user phrase library should be already loaded here. */
249 FILE * dictfile = fopen (filename, "r");
250 if (NULL == dictfile)
253 import_iterator_t * iter = pinyin_begin_add_phrases
254 (m_pinyin_context, 15);
259 char* linebuf = NULL; size_t size = 0; ssize_t read;
260 while ((read = getline (&linebuf, &size, dictfile)) != -1) {
261 if (0 == strlen (linebuf))
264 if ( '\n' == linebuf[strlen (linebuf) - 1] ) {
265 linebuf[strlen (linebuf) - 1] = '\0';
268 gchar ** items = g_strsplit_set (linebuf, " \t", 3);
269 guint len = g_strv_length (items);
271 gchar * phrase = NULL, * pinyin = NULL;
273 if (2 == len || 3 == len) {
277 count = atoi (items[2]);
281 pinyin_iterator_add_phrase (iter, phrase, pinyin, count);
284 pinyin_end_add_phrases (iter);
287 pinyin_save (m_pinyin_context);
292 LibPinyinBackEnd::clearPinyinUserData (const char * target)
294 if (0 == strcmp ("all", target))
295 pinyin_mask_out (m_pinyin_context, 0x0, 0x0);
296 else if (0 == strcmp ("user", target))
297 pinyin_mask_out (m_pinyin_context, PHRASE_INDEX_LIBRARY_MASK,
298 PHRASE_INDEX_MAKE_TOKEN (15, null_token));
300 g_warning ("unknown clear target: %s.\n", target);
302 pinyin_save (m_pinyin_context);
307 LibPinyinBackEnd::timeoutCallback (gpointer data)
309 LibPinyinBackEnd *self = static_cast<LibPinyinBackEnd *> (data);
311 /* Get the elapsed time since last modification of database. */
312 guint elapsed = (guint)g_timer_elapsed (self->m_timer, NULL);
314 if (elapsed >= LIBPINYIN_SAVE_TIMEOUT &&
315 self->saveUserDB ()) {
316 self->m_timeout_id = 0;
324 LibPinyinBackEnd::saveUserDB (void)
326 if (m_pinyin_context)
327 pinyin_save (m_pinyin_context);
328 if (m_chewing_context)
329 pinyin_save (m_chewing_context);