Tizen 2.1 base
[platform/core/uifw/ise-engine-sunpinyin.git] / wrapper / xim / sunpinyin_preedit.cc
1 /*
2  * Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
3  *
4  * The contents of this file are subject to the terms of either the GNU Lesser
5  * General Public License Version 2.1 only ("LGPL") or the Common Development and
6  * Distribution License ("CDDL")(collectively, the "License"). You may not use this
7  * file except in compliance with the License. You can obtain a copy of the CDDL at
8  * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
9  * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
10  * specific language governing permissions and limitations under the License. When
11  * distributing the software, include this License Header Notice in each file and
12  * include the full text of the License in the License file as well as the
13  * following notice:
14  *
15  * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
16  * (CDDL)
17  * For Covered Software in this distribution, this License shall be governed by the
18  * laws of the State of California (excluding conflict-of-law provisions).
19  * Any litigation relating to this License shall be subject to the jurisdiction of
20  * the Federal Courts of the Northern District of California and the state courts
21  * of the State of California, with venue lying in Santa Clara County, California.
22  *
23  * Contributor(s):
24  *
25  * If you wish your version of this file to be governed by only the CDDL or only
26  * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
27  * include this software in this distribution under the [CDDL or LGPL Version 2.1]
28  * license." If you don't indicate a single choice of license, a recipient has the
29  * option to distribute your version of this file under either the CDDL or the LGPL
30  * Version 2.1, or to extend the choice of license to its licensees as provided
31  * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
32  * Version 2 license, then the option applies only if the new code is made subject
33  * to such option by the copyright holder.
34  */
35 #include <locale.h>
36
37 #include <sunpinyin.h>
38 #include <ime-core/imi_glibHandler.h>
39
40 #include "xim.h"
41 #include "common.h"
42 #include "settings.h"
43 #include "sunpinyin_preedit_ui.h"
44
45 #define BUF_SIZE 4096
46
47 class WindowHandler : public CIMIGlibHandler
48 {
49 protected:
50     virtual void updatePreedit(const IPreeditString* ppd);
51     virtual void updateCandidates(const ICandidateList* pcl);
52     virtual void updateStatus(int key, int value);
53     virtual void commit(const TWCHAR* str);
54
55 private:
56     PreeditUI* ui_impl_;
57
58 public:
59
60     WindowHandler();
61     virtual ~WindowHandler();
62
63     PreeditUI* preedit_ui_impl() { return ui_impl_; }
64     void       set_preedit_ui_impl(PreeditUI* ui_impl) {
65         ui_impl_ = ui_impl;
66     }
67
68     void set_xim_handle(XIMHandle* handle) {
69         handle_ = handle;
70     }
71
72     bool status() {
73         return status_;
74     }
75
76     void update_preedit_ui(const IPreeditString* ppd, const char* utf_str);
77     void update_candidates_ui(const ICandidateList* pcl, const char* utf_str);
78
79     void pause();
80     void move(int x, int y);
81     void go_on();
82     void reload_ui();
83
84 private:
85     XIMHandle* handle_;
86
87     char* preedit_str_;
88     char* candidate_str_;
89
90     bool status_;
91     bool pause_;
92
93     int  x_, y_;
94 };
95
96 WindowHandler::WindowHandler()
97 {
98     preedit_str_ = new char[BUF_SIZE];
99     candidate_str_ = new char[BUF_SIZE];
100     status_ = false;
101     pause_ = false;
102     ui_impl_ = NULL;
103     handle_ = NULL;
104     x_ = y_ = 0;
105 }
106
107 WindowHandler::~WindowHandler()
108 {
109     delete [] preedit_str_;
110     delete [] candidate_str_;
111 }
112
113 void
114 WindowHandler::reload_ui()
115 {
116     ui_impl_->reload();
117     ui_impl_->update_preedit_string(preedit_str_);
118     ui_impl_->update_candidates_string(candidate_str_);
119     if (status_) {
120         ui_impl_->show();
121         ui_impl_->move(x_, y_);
122     } else {
123         ui_impl_->hide();
124     }
125 }
126
127 void
128 WindowHandler::pause()
129 {
130     if (status_) {
131         ui_impl_->hide();
132         status_ = false;
133         pause_ = true;
134     }
135 }
136
137 void
138 WindowHandler::move(int x, int y)
139 {
140     x_ = x;
141     y_ = y;
142     if (ui_impl_) {
143         ui_impl_->move(x, y);
144     }
145 }
146
147 void
148 WindowHandler::go_on()
149 {
150     if (!status_ && pause_) {
151         ui_impl_->show();
152         status_ = true;
153         pause_ = false;
154     }
155 }
156
157 void
158 WindowHandler::update_candidates_ui(const ICandidateList* pcl, const char* utf_str)
159 {
160     ui_impl_->update_candidates_string(utf_str);
161     if (status_) {
162         ui_impl_->show();
163     } else {
164         ui_impl_->hide();
165     }
166 }
167
168 void
169 WindowHandler::update_preedit_ui(const IPreeditString* ppd, const char* utf_str)
170 {
171     ui_impl_->update_preedit_string(utf_str);
172     if (ppd->size() == 0) {
173         status_ = false;
174     } else {
175         status_ = true;
176     }
177 }
178
179 void
180 WindowHandler::updatePreedit(const IPreeditString* ppd)
181 {
182     TIConvSrcPtr src = (TIConvSrcPtr) (ppd->string());
183     TWCHAR* front_src = new TWCHAR[BUF_SIZE];
184     TWCHAR* end_src = new TWCHAR[BUF_SIZE];
185
186     memset(front_src, 0, BUF_SIZE * sizeof(TWCHAR));
187     memset(end_src, 0, BUF_SIZE * sizeof(TWCHAR));
188
189     memcpy(front_src, src, ppd->caret() * sizeof(TWCHAR));
190     memcpy(end_src, src + ppd->caret() * sizeof(TWCHAR),
191            (ppd->size() - ppd->caret() + 1) * sizeof(TWCHAR));
192
193     memset(preedit_str_, 0, BUF_SIZE);
194
195     WCSTOMBS(preedit_str_, front_src, BUF_SIZE - 1);
196     preedit_str_[strlen(preedit_str_)] = '|';
197     WCSTOMBS(&preedit_str_[strlen(preedit_str_)], end_src, BUF_SIZE - 1);
198
199     // update within the ui provider
200     update_preedit_ui(ppd, preedit_str_);
201
202     delete [] front_src;
203     delete [] end_src;
204 }
205
206 void
207 WindowHandler::updateCandidates(const ICandidateList* pcl)
208 {
209     wstring cand_str;
210     for (int i = 0, sz = pcl->size(); i < sz; i++) {
211         const TWCHAR* pcand = pcl->candiString(i);
212         if (pcand == NULL) break;
213         cand_str += (i == 9) ? '0' : TWCHAR('1' + i);
214         cand_str += TWCHAR('.');
215         cand_str += pcand;
216         cand_str += TWCHAR(' ');
217     }
218
219     TIConvSrcPtr src = (TIConvSrcPtr)(cand_str.c_str());
220     WCSTOMBS(candidate_str_, (const TWCHAR*) src, BUF_SIZE - 1);
221
222     // update within the ui provider
223     update_candidates_ui(pcl, candidate_str_);
224 }
225
226 void
227 WindowHandler::updateStatus(int key, int value)
228 {}
229
230 void
231 WindowHandler::commit(const TWCHAR* str)
232 {
233     char* buf = new char[BUF_SIZE];
234     memset(buf, 0, BUF_SIZE);
235     WCSTOMBS(buf, str, BUF_SIZE - 1);
236     if (handle_ != NULL) {
237         xim_commit_preedit(handle_, buf);
238     }
239     delete [] buf;
240 }
241
242
243 static PreeditUI* ui_impl = NULL;
244 static WindowHandler* instance = NULL;
245 static CIMIView* view = NULL;
246
247 __EXPORT_API void
248 preedit_init()
249 {
250     CSunpinyinSessionFactory& fac = CSunpinyinSessionFactory::getFactory();
251     if (settings_get_int(SHUANGPIN)) {
252         fac.setPinyinScheme(CSunpinyinSessionFactory::SHUANGPIN);
253         // shuangpin schemes
254         varchar scheme;
255         settings_get(SHUANGPIN_SCHEME, scheme);
256         if (strcmp(scheme, "MS2003") == 0) {
257             AShuangpinSchemePolicy::instance().setShuangpinType(MS2003);
258         } else if (strcmp(scheme, "ABC") == 0) {
259             AShuangpinSchemePolicy::instance().setShuangpinType(ABC);
260         } else if (strcmp(scheme, "ZiRanMa") == 0) {
261             AShuangpinSchemePolicy::instance().setShuangpinType(ZIRANMA);
262         } else if (strcmp(scheme, "PinYin++") == 0) {
263             AShuangpinSchemePolicy::instance().setShuangpinType(PINYINJIAJIA);
264         } else if (strcmp(scheme, "ZiGuang") == 0) {
265             AShuangpinSchemePolicy::instance().setShuangpinType(ZIGUANG);
266         } else if (strcmp(scheme, "XiaoHe") == 0) {
267             AShuangpinSchemePolicy::instance().setShuangpinType(XIAOHE);
268         }
269     } else {
270         fac.setPinyinScheme(CSunpinyinSessionFactory::QUANPIN);
271     }
272     view = fac.createSession();
273
274     varchar skin_name;
275     settings_get(SKIN_NAME, skin_name);
276     ui_impl = create_preedit_ui(skin_name);
277
278     instance = new WindowHandler();
279     instance->set_preedit_ui_impl(ui_impl);
280     view->getIC()->setCharsetLevel(1);// GBK
281     view->attachWinHandler(instance);
282 }
283
284 __EXPORT_API void
285 preedit_finalize(void)
286 {
287     LOG("preedit_finalizing...");
288     CSunpinyinSessionFactory& fac = CSunpinyinSessionFactory::getFactory();
289     fac.destroySession(view);
290
291     delete ui_impl;
292     delete instance;
293 }
294
295 __EXPORT_API void
296 preedit_reload(void)
297 {
298     // number of candidates
299     view->setCandiWindowSize(settings_get_int(CANDIDATES_SIZE));
300
301     // page up/down key
302     CHotkeyProfile* prof = view->getHotkeyProfile();
303     prof->clear();
304     if (settings_get_int(PAGE_MINUS_PLUS)) {
305         prof->addPageUpKey(CKeyEvent(IM_VK_MINUS));
306         prof->addPageDownKey(CKeyEvent(IM_VK_EQUALS));
307     }
308     if (settings_get_int(PAGE_COMMA_PERIOD)) {
309         prof->addPageUpKey(CKeyEvent(IM_VK_COMMA));
310         prof->addPageDownKey(CKeyEvent(IM_VK_PERIOD));
311     }
312     if (settings_get_int(PAGE_PAREN)) {
313         prof->addPageUpKey(CKeyEvent('['));
314         prof->addPageDownKey(CKeyEvent(']'));
315     }
316
317     // fuzzy segmentation
318     bool enable_fuzzy = settings_get_int(FUZZY_SEGMENTATION);
319     bool enable_inner = settings_get_int(FUZZY_INNER_SEGMENTATION);
320     AQuanpinSchemePolicy::instance().setFuzzySegmentation(enable_fuzzy);
321     AQuanpinSchemePolicy::instance().setInnerFuzzySegmentation(enable_inner);
322
323     // cancel last selection on backspace
324     view->setCancelOnBackspace(settings_get_int(CANCEL_ON_BACKSPACE));
325
326     // do we need to change the skin?
327     varchar skin_name;
328     settings_get(SKIN_NAME, skin_name);
329     if (ui_impl->name() != skin_name) {
330         delete ui_impl;
331         ui_impl = create_preedit_ui(skin_name);
332         instance->set_preedit_ui_impl(ui_impl);
333     }
334
335     instance->reload_ui();
336 }
337
338 __EXPORT_API void
339 preedit_set_handle(XIMHandle* handle)
340 {
341     instance->set_xim_handle(handle);
342 }
343
344 __EXPORT_API void
345 preedit_move(int x, int y)
346 {
347     instance->move(x, y);
348 }
349
350 __EXPORT_API void
351 preedit_pause(void)
352 {
353     instance->pause();
354 }
355
356 __EXPORT_API void
357 preedit_go_on(void)
358 {
359     instance->go_on();
360 }
361
362 __EXPORT_API void
363 preedit_on_key(XIMHandle* handle, unsigned int keycode, unsigned int state)
364 {
365     if (keycode < 0x20 && keycode > 0x7E)
366         keycode = 0;
367     view->onKeyEvent(CKeyEvent(keycode, keycode, state));
368 }
369
370 __EXPORT_API bool
371 preedit_status(void)
372 {
373     return instance->status();
374 }
375
376 __EXPORT_API void
377 preedit_set_full(bool full)
378 {
379     view->setStatusAttrValue(CIMIWinHandler::STATUS_ID_FULLSYMBOL, full);
380 }
381
382 __EXPORT_API void
383 preedit_set_chinese_punc(bool chn_punc)
384 {
385     view->setStatusAttrValue(CIMIWinHandler::STATUS_ID_FULLPUNC, chn_punc);
386 }
387
388 __EXPORT_API void
389 preedit_omit_next_punct()
390 {
391     view->getIC()->omitNextPunct();
392 }
393