uses pinyin_load_phrase_library
[platform/upstream/ibus-libpinyin.git] / src / PYLibPinyin.cc
1 /* vim:set et ts=4 sts=4:
2  *
3  * ibus-libpinyin - Intelligent Pinyin engine based on libpinyin for IBus
4  *
5  * Copyright (c) 2011 Peng Wu <alexepico@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 Street, Fifth Floor, Boston, MA  02110-1301, USA.
20  */
21
22 #include "PYLibPinyin.h"
23 #include <pinyin.h>
24 #include "PYPConfig.h"
25
26 #define LIBPINYIN_SAVE_TIMEOUT   (5 * 60)
27
28 using namespace PY;
29
30 std::unique_ptr<LibPinyinBackEnd> LibPinyinBackEnd::m_instance;
31
32 static LibPinyinBackEnd libpinyin_backend;
33
34 LibPinyinBackEnd::LibPinyinBackEnd () {
35     m_timeout_id = 0;
36     m_timer = g_timer_new();
37     m_pinyin_context = NULL;
38     m_chewing_context = NULL;
39 }
40
41 LibPinyinBackEnd::~LibPinyinBackEnd () {
42     g_timer_destroy (m_timer);
43     if (m_timeout_id != 0) {
44         saveUserDB ();
45         g_source_remove (m_timeout_id);
46     }
47
48     if (m_pinyin_context)
49         pinyin_fini(m_pinyin_context);
50     m_pinyin_context = NULL;
51     if (m_chewing_context)
52         pinyin_fini(m_chewing_context);
53     m_chewing_context = NULL;
54 }
55
56 pinyin_instance_t *
57 LibPinyinBackEnd::allocPinyinInstance ()
58 {
59     if (NULL == m_pinyin_context) {
60         gchar * userdir = g_build_filename (g_get_home_dir(), ".cache",
61                                             "ibus", "libpinyin", NULL);
62         int retval = g_mkdir_with_parents (userdir, 0700);
63         if (retval) {
64             g_free(userdir); userdir = NULL;
65         }
66         m_pinyin_context = pinyin_init ("/usr/share/libpinyin/data", userdir);
67         pinyin_load_phrase_library(m_pinyin_context, 2);
68         g_free(userdir);
69     }
70
71     setPinyinOptions (&LibPinyinPinyinConfig::instance ());
72     return pinyin_alloc_instance (m_pinyin_context);
73 }
74
75 void
76 LibPinyinBackEnd::freePinyinInstance (pinyin_instance_t *instance)
77 {
78     pinyin_free_instance (instance);
79 }
80
81 pinyin_instance_t *
82 LibPinyinBackEnd::allocChewingInstance ()
83 {
84     if (NULL == m_chewing_context) {
85         gchar * userdir = g_build_filename (g_get_home_dir(), ".cache",
86                                             "ibus", "libbopomofo", NULL);
87         int retval = g_mkdir_with_parents (userdir, 0700);
88         if (retval) {
89             g_free(userdir); userdir = NULL;
90         }
91         m_chewing_context = pinyin_init ("/usr/share/libpinyin/data", userdir);
92         pinyin_load_phrase_library(m_chewing_context, 2);
93         g_free(userdir);
94     }
95
96     setChewingOptions (&LibPinyinBopomofoConfig::instance ());
97     return pinyin_alloc_instance (m_chewing_context);
98 }
99
100 void
101 LibPinyinBackEnd::freeChewingInstance (pinyin_instance_t *instance)
102 {
103     pinyin_free_instance (instance);
104 }
105
106 void
107 LibPinyinBackEnd::init (void) {
108     g_assert (NULL == m_instance.get ());
109     LibPinyinBackEnd * backend = new LibPinyinBackEnd;
110     m_instance.reset (backend);
111 }
112
113 void
114 LibPinyinBackEnd::finalize (void) {
115     m_instance.reset ();
116 }
117
118 /* Here are the double pinyin keyboard scheme mapping table. */
119 static const struct{
120     gint double_pinyin_keyboard;
121     DoublePinyinScheme scheme;
122 } double_pinyin_options [] = {
123     {0, DOUBLE_PINYIN_MS},
124     {1, DOUBLE_PINYIN_ZRM},
125     {2, DOUBLE_PINYIN_ABC},
126     {3, DOUBLE_PINYIN_ZIGUANG},
127     {4, DOUBLE_PINYIN_PYJJ},
128     {5, DOUBLE_PINYIN_XHE}
129 };
130
131 gboolean
132 LibPinyinBackEnd::setPinyinOptions (Config *config)
133 {
134     if (NULL == m_pinyin_context)
135         return FALSE;
136
137     const gint map = config->doublePinyinSchema ();
138     for (guint i = 0; i < G_N_ELEMENTS (double_pinyin_options); i++) {
139         if (map == double_pinyin_options[i].double_pinyin_keyboard) {
140             /* set double pinyin scheme. */
141             DoublePinyinScheme scheme = double_pinyin_options[i].scheme;
142             pinyin_set_double_pinyin_scheme (m_pinyin_context, scheme);
143         }
144     }
145
146     pinyin_option_t options = config->option() | USE_RESPLIT_TABLE;
147     pinyin_set_options (m_pinyin_context, options);
148     return TRUE;
149 }
150
151 /* Here are the chewing keyboard scheme mapping table. */
152 static const struct {
153     gint bopomofo_keyboard;
154     ChewingScheme scheme;
155 } chewing_options [] = {
156     {0, CHEWING_STANDARD},
157     {1, CHEWING_GINYIEH},
158     {2, CHEWING_ETEN},
159     {3, CHEWING_IBM}
160 };
161
162
163 gboolean
164 LibPinyinBackEnd::setChewingOptions (Config *config)
165 {
166     if (NULL == m_chewing_context)
167         return FALSE;
168
169     const gint map = config->bopomofoKeyboardMapping ();
170     for (guint i = 0; i < G_N_ELEMENTS (chewing_options); i++) {
171         if (map == chewing_options[i].bopomofo_keyboard) {
172             /* TODO: set chewing scheme. */
173             ChewingScheme scheme = chewing_options[i].scheme;
174             pinyin_set_chewing_scheme (m_chewing_context, scheme);
175         }
176     }
177
178     pinyin_option_t options = config->option() | USE_TONE;
179     pinyin_set_options(m_chewing_context, options);
180     return TRUE;
181 }
182
183 void
184 LibPinyinBackEnd::modified (void)
185 {
186     /* Restart the timer */
187     g_timer_start (m_timer);
188
189     if (m_timeout_id != 0)
190         return;
191
192     m_timeout_id = g_timeout_add_seconds (LIBPINYIN_SAVE_TIMEOUT,
193                                           LibPinyinBackEnd::timeoutCallback,
194                                           static_cast<gpointer> (this));
195 }
196
197 gboolean
198 LibPinyinBackEnd::timeoutCallback (gpointer data)
199 {
200     LibPinyinBackEnd *self = static_cast<LibPinyinBackEnd *> (data);
201
202     /* Get the elapsed time since last modification of database. */
203     guint elapsed = (guint)g_timer_elapsed (self->m_timer, NULL);
204
205     if (elapsed >= LIBPINYIN_SAVE_TIMEOUT &&
206         self->saveUserDB ()) {
207         self->m_timeout_id = 0;
208         return FALSE;
209     }
210
211     return TRUE;
212 }
213
214 gboolean
215 LibPinyinBackEnd::saveUserDB (void)
216 {
217     if (m_pinyin_context)
218         pinyin_save (m_pinyin_context);
219     if (m_chewing_context)
220         pinyin_save (m_chewing_context);
221     return TRUE;
222 }