fixes compile
[platform/upstream/ibus-libpinyin.git] / src / PYPPinyinEditor.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 "PYPPinyinEditor.h"
23 #include "PYConfig.h"
24 #include "PYPinyinProperties.h"
25 #include "PYSimpTradConverter.h"
26 #include "PYHalfFullConverter.h"
27 #include "PYLibPinyin.h"
28
29 using namespace PY;
30
31 /* init static members*/
32 LibPinyinPinyinEditor::LibPinyinPinyinEditor (PinyinProperties & props,
33                                               Config & config)
34     : LibPinyinPhoneticEditor (props, config)
35 {
36 }
37
38
39 /**
40  * process pinyin
41  */
42 inline gboolean
43 LibPinyinPinyinEditor::processPinyin (guint keyval, guint keycode,
44                                       guint modifiers)
45 {
46     if (G_UNLIKELY (cmshm_filter (modifiers) != 0))
47         return m_text ? TRUE : FALSE;
48
49     return insert (keyval);
50 }
51
52 /**
53  * process numbers
54  */
55 inline gboolean
56 LibPinyinPinyinEditor::processNumber (guint keyval, guint keycode,
57                                       guint modifiers)
58 {
59     guint i;
60
61     if (m_text.empty ())
62         return FALSE;
63
64     switch (keyval) {
65     case IBUS_0:
66     case IBUS_KP_0:
67         i = 9;
68         break;
69     case IBUS_1 ... IBUS_9:
70         i = keyval - IBUS_1;
71         break;
72     case IBUS_KP_1 ... IBUS_KP_9:
73         i = keyval - IBUS_KP_1;
74         break;
75     default:
76         g_return_val_if_reached (FALSE);
77     }
78
79     if (modifiers == 0)
80         selectCandidateInPage (i);
81
82     update ();
83     return TRUE;
84 }
85
86 inline gboolean
87 LibPinyinPinyinEditor::processPunct (guint keyval, guint keycode,
88                                      guint modifiers)
89 {
90     if (m_text.empty ())
91         return FALSE;
92
93     if (cmshm_filter (modifiers) != 0)
94         return TRUE;
95
96     switch (keyval) {
97     case IBUS_apostrophe:
98         return insert (keyval);
99     case IBUS_comma:
100         if (m_config.commaPeriodPage ()) {
101             pageUp ();
102             return TRUE;
103         }
104         break;
105     case IBUS_minus:
106         if (m_config.minusEqualPage ()) {
107             pageUp ();
108             return TRUE;
109         }
110         break;
111     case IBUS_period:
112         if (m_config.commaPeriodPage ()) {
113             pageDown ();
114             return TRUE;
115         }
116         break;
117     case IBUS_equal:
118         if (m_config.minusEqualPage ()) {
119             pageDown ();
120             return TRUE;
121         }
122         break;
123     }
124
125 #if 0
126     if (m_config.autoCommit ()) {
127         if (m_lookup_table.size ()) {
128             /* TODO: check here. */
129             selectCandidate (m_lookup_table.cursorPos ());
130         }
131         commit ();
132         return FALSE;
133     }
134 #endif
135
136     return TRUE;
137 }
138
139 inline gboolean
140 LibPinyinPinyinEditor::processFunctionKey (guint keyval, guint keycode,
141                                            guint modifiers)
142 {
143     if (m_text.empty ())
144         return FALSE;
145
146     /* ignore numlock */
147     modifiers = cmshm_filter (modifiers);
148
149     if (modifiers != 0 && modifiers != IBUS_CONTROL_MASK)
150         return TRUE;
151
152     /* process some cursor control keys */
153     if (modifiers == 0) { /* no modifiers. */
154         switch (keyval) {
155         case IBUS_Shift_L:
156             if (!m_config.shiftSelectCandidate ())
157                 return FALSE;
158             selectCandidateInPage (1);
159             return TRUE;
160
161         case IBUS_Shift_R:
162             if (!m_config.shiftSelectCandidate ())
163                 return FALSE;
164             selectCandidateInPage (2);
165             return TRUE;
166         }
167     }
168
169     return LibPinyinPhoneticEditor::processFunctionKey (keyval, keycode,
170                                                         modifiers);
171 }
172
173 gboolean
174 LibPinyinPinyinEditor::processKeyEvent (guint keyval, guint keycode,
175                                         guint modifiers)
176 {
177     modifiers &= (IBUS_SHIFT_MASK |
178                   IBUS_CONTROL_MASK |
179                   IBUS_MOD1_MASK |
180                   IBUS_SUPER_MASK |
181                   IBUS_HYPER_MASK |
182                   IBUS_META_MASK |
183                   IBUS_LOCK_MASK);
184
185     switch (keyval) {
186     /* letters */
187     case IBUS_a ... IBUS_z:
188         return processPinyin (keyval, keycode, modifiers);
189     case IBUS_0 ... IBUS_9:
190     case IBUS_KP_0 ... IBUS_KP_9:
191         return processNumber (keyval, keycode, modifiers);
192     case IBUS_exclam ... IBUS_slash:
193     case IBUS_colon ... IBUS_at:
194     case IBUS_bracketleft ... IBUS_quoteleft:
195     case IBUS_braceleft ... IBUS_asciitilde:
196         return processPunct (keyval, keycode, modifiers);
197     case IBUS_space:
198         return processSpace (keyval, keycode, modifiers);
199     default:
200         return processFunctionKey (keyval, keycode, modifiers);
201     }
202 }
203
204 void
205 LibPinyinPinyinEditor::commit ()
206 {
207     if (G_UNLIKELY (m_text.empty ()))
208         return;
209
210     m_buffer.clear ();
211
212     /* sentence candidate */
213     char *tmp = NULL;
214     pinyin_get_sentence (m_instance, &tmp);
215     if (tmp) {
216         if (m_props.modeSimp ()) {
217             m_buffer << tmp;
218         } else {
219             SimpTradConverter::simpToTrad (tmp, m_buffer);
220         }
221         g_free (tmp);
222     }
223
224     /* text after pinyin */
225     const gchar *p = m_text.c_str() + m_pinyin_len;
226     if (G_UNLIKELY (m_props.modeFull ())) {
227         while (*p != '\0') {
228             m_buffer.appendUnichar (HalfFullConverter::toFull (*p++));
229         }
230     } else {
231         m_buffer << p;
232     }
233
234     pinyin_train (m_instance);
235     LibPinyinBackEnd::instance ().modified ();
236     LibPinyinPhoneticEditor::commit ((const gchar *)m_buffer);
237     reset();
238 }
239
240 void
241 LibPinyinPinyinEditor::updatePreeditText ()
242 {
243     /* preedit text = guessed sentence + un-parsed pinyin text */
244     if (G_UNLIKELY (m_text.empty ())) {
245         hidePreeditText ();
246         return;
247     }
248
249     m_buffer.clear ();
250     char *tmp = NULL;
251     pinyin_get_sentence (m_instance, &tmp);
252     if (tmp) {
253         if (m_props.modeSimp ()) {
254             m_buffer<<tmp;
255         } else {
256             SimpTradConverter::simpToTrad (tmp, m_buffer);
257         }
258         g_free (tmp);
259         tmp = NULL;
260     }
261
262     /* append rest text */
263     const gchar *p = m_text.c_str () + m_pinyin_len;
264     m_buffer << p;
265
266     StaticText preedit_text (m_buffer);
267     /* underline */
268     preedit_text.appendAttribute (IBUS_ATTR_TYPE_UNDERLINE, IBUS_ATTR_UNDERLINE_SINGLE, 0, -1);
269
270     guint pinyin_cursor = getPinyinCursor ();
271     Editor::updatePreeditText (preedit_text, pinyin_cursor, TRUE);
272 }
273
274 void
275 LibPinyinPinyinEditor::updateAuxiliaryText ()
276 {
277     if (G_UNLIKELY (m_text.empty ())) {
278         hideAuxiliaryText ();
279         return;
280     }
281
282     m_buffer.clear ();
283
284     /* Note: cursor handling is defered to full/double pinyin editors. */
285
286     guint len = 0;
287     pinyin_get_n_pinyin (m_instance, &len);
288
289     for (guint i = 0; i < len; ++i) {
290         if (G_LIKELY (i))
291             m_buffer << ' ';
292
293         PinyinKey *key = NULL;
294         pinyin_get_pinyin_key (m_instance, i, &key);
295
296         gchar * str = NULL;
297         pinyin_get_pinyin_string (m_instance, key, &str);
298
299         m_buffer << str;
300         g_free (str);
301     }
302
303     /* append rest text */
304     const gchar *p = m_text.c_str() + m_pinyin_len;
305     m_buffer << p;
306
307     StaticText aux_text (m_buffer);
308     Editor::updateAuxiliaryText (aux_text, TRUE);
309 }
310
311 void
312 LibPinyinPinyinEditor::updateLookupTable ()
313 {
314     m_lookup_table.setPageSize (m_config.pageSize ());
315     m_lookup_table.setOrientation (m_config.orientation ());
316     LibPinyinPhoneticEditor::updateLookupTable ();
317 }
318