Tizen 2.1 base
[framework/uifw/ise-engine-anthy.git] / src / scim_anthy_key2kana.cpp
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  *  Copyright (C) 2004 Hiroyuki Ikezoe
4  *  Copyright (C) 2004 Takuro Ashie
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2, or (at your option)
9  *  any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  */
20
21 #include "scim_anthy_key2kana.h"
22 #include "scim_anthy_factory.h"
23 #include "scim_anthy_imengine.h"
24 #include "scim_anthy_utils.h"
25
26 using namespace scim_anthy;
27
28 Key2KanaConvertor::Key2KanaConvertor (AnthyInstance    & anthy,
29                                       Key2KanaTableSet & tables)
30     : m_anthy                   (anthy),
31       m_tables                  (tables),
32       m_is_in_pseudo_ascii_mode (false)
33 {
34     set_case_sensitive (false);
35     set_pseudo_ascii_mode (0);
36 }
37
38 Key2KanaConvertor::~Key2KanaConvertor ()
39 {
40 }
41
42 bool
43 Key2KanaConvertor::can_append (const KeyEvent & key,
44                                bool             ignore_space)
45 {
46     // ignore key release.
47     if (key.is_key_release ())
48         return false;
49
50     // ignore short cut keys of apllication.
51     if (key.mask & SCIM_KEY_ControlMask ||
52         key.mask & SCIM_KEY_AltMask)
53     {
54         return false;
55     }
56
57     if (isprint(key.get_ascii_code ()) &&
58         (ignore_space || !isspace(key.get_ascii_code ())))
59         return true;
60
61     if (util_key_is_keypad (key))
62         return true;
63
64     return false;
65 }
66
67 bool
68 Key2KanaConvertor::append (const KeyEvent & key,
69                            WideString & result,
70                            WideString & pending,
71                            String &raw)
72 {
73     if (!can_append (key))
74         return false;
75
76     m_last_key = key;
77
78     util_keypad_to_string (raw, key);
79
80     if (util_key_is_keypad (key)) {
81         bool retval = false;
82         WideString wide;
83         String ten_key_type = m_anthy.get_factory()->m_ten_key_type;
84
85         // convert key pad string to wide
86         if ((ten_key_type == "FollowMode" &&
87              (m_anthy.get_input_mode () == SCIM_ANTHY_MODE_LATIN ||
88               m_anthy.get_input_mode () == SCIM_ANTHY_MODE_HALF_KATAKANA)) ||
89             ten_key_type == "Half")
90         {
91             wide = utf8_mbstowcs (raw);
92         } else {
93             util_convert_to_wide (wide, raw);
94         }
95
96         // join to previous string
97         if (!m_exact_match.is_empty()) {
98             if (!m_exact_match.get_result(0).empty() &&
99                 m_exact_match.get_result(1).empty())
100             {
101                 result = utf8_mbstowcs (m_exact_match.get_result(0));
102             } else {
103                 retval = true; /* commit prev pending */
104             }
105             result += wide;
106         } else {
107             if (m_pending.length () > 0)
108                 retval = true; /* commit prev pending */
109             result = wide;
110         }
111
112         m_pending.clear ();
113         m_exact_match.clear ();
114
115         return retval;
116
117     } else {
118         // the key isn't keypad
119         return append (raw, result, pending);
120     }
121 }
122
123 bool
124 Key2KanaConvertor::append (const String & str,
125                            WideString & result, WideString & pending)
126 {
127     WideString widestr = utf8_mbstowcs (str);
128     WideString matching_str = m_pending + widestr;
129     Key2KanaRule exact_match;
130     bool has_partial_match = false;
131     bool retval = false;
132
133     if (m_pseudo_ascii_mode != 0 && process_pseudo_ascii_mode (widestr)) {
134         m_pending += widestr;
135         pending = m_pending;
136         return false;
137     }
138     if (!m_case_sensitive) {
139         String half = utf8_wcstombs (matching_str);
140         for (unsigned int i = 0; i < half.length (); i++)
141             half[i] = tolower (half[i]);
142         matching_str = utf8_mbstowcs (half);
143     }
144
145     /* find matched table */
146     if ((m_anthy.get_typing_method () == SCIM_ANTHY_TYPING_METHOD_KANA) &&
147         (m_last_key.mask & /*SCIM_KEY_QuirkKanaRoMask*/ (1<<14)) &&
148         (m_anthy.get_factory()->m_kana_layout_ro_key.length () > 0))
149     {
150         // Special treatment for Kana "Ro" key.
151         // This code is a temporary solution. It doesn't care some minor cases.
152         std::vector<String> kana_ro_result;
153         scim_split_string_list (kana_ro_result,
154                                 m_anthy.get_factory()->m_kana_layout_ro_key);
155         Key2KanaRule kana_ro_rule("\\", kana_ro_result);
156         result = utf8_mbstowcs (kana_ro_rule.get_result (0));
157         m_pending.clear ();
158         m_exact_match.clear ();
159         if (matching_str == utf8_mbstowcs ("\\")) {
160             return false;
161         } else {
162             return true;
163         }
164
165     } else {
166         std::vector<Key2KanaTable*> &tables = m_tables.get_tables();
167         for (unsigned int j = 0; j < tables.size(); j++) {
168             if (!tables[j])
169                 continue;
170
171             Key2KanaRules &rules = tables[j]->get_table ();
172
173             for (unsigned int i = 0; i < rules.size(); i++) {
174                 /* matching */
175                 String seq = rules[i].get_sequence ();
176                 if (!m_case_sensitive) {
177                     for (unsigned int j = 0; j < seq.length (); j++)
178                         seq[j] = tolower (seq[j]);
179                 }
180                 WideString romaji = utf8_mbstowcs(seq);
181                 if (romaji.find (matching_str) == 0) {
182                     if (romaji.length () == matching_str.length ()) {
183                         /* exact match */
184                         exact_match = rules[i];
185                     } else {
186                         /* partial match */
187                         has_partial_match = true;
188                     }
189                 }
190             }
191         }
192     }
193
194     /* return result */
195     if (has_partial_match) {
196         m_exact_match = exact_match;
197         result.clear ();
198         m_pending += widestr;
199         pending   =  m_pending;
200
201     } else if (!exact_match.is_empty()) {
202         if (!exact_match.get_result(1).empty())
203             m_exact_match = exact_match;
204         else
205             m_exact_match.clear ();
206         m_pending = utf8_mbstowcs (exact_match.get_result (1));
207         result    = utf8_mbstowcs (exact_match.get_result (0));
208         pending   = m_pending;
209
210     } else {
211         if (!m_exact_match.is_empty()) {
212             if (!m_exact_match.get_result(0).empty() &&
213                 m_exact_match.get_result(1).empty())
214             {
215                 result = utf8_mbstowcs (m_exact_match.get_result(0));
216             } else {
217                 retval = true; /* commit prev pending */
218             }
219             m_pending.clear ();
220             m_exact_match.clear ();
221
222             WideString tmp_result;
223             append(str, tmp_result, pending);
224             result += tmp_result;
225
226         } else {
227             if (m_pending.length () > 0) {
228                 retval     = true; /* commit prev pending */
229                 m_pending  = widestr;
230                 pending    = m_pending;
231
232             } else {
233                 result     = widestr;
234                 pending.clear();
235                 m_pending.clear ();
236             }
237         }
238     }
239
240     return retval;
241 }
242
243 void
244 Key2KanaConvertor::clear (void)
245 {
246     m_pending.clear ();
247     m_exact_match.clear ();
248     m_last_key = KeyEvent ();
249     reset_pseudo_ascii_mode();
250 }
251
252 bool
253 Key2KanaConvertor::is_pending (void)
254 {
255     if (m_pending.length () > 0)
256         return true;
257     else
258         return false;
259 }
260
261 WideString
262 Key2KanaConvertor::get_pending (void)
263 {
264     return m_pending;
265 }
266
267 WideString
268 Key2KanaConvertor::flush_pending (void)
269 {
270     WideString result;
271     if (!m_exact_match.is_empty ()) {
272         if (!m_exact_match.get_result(0).empty() &&
273             m_exact_match.get_result(1).empty())
274         {
275             result = utf8_mbstowcs (m_exact_match.get_result(0));
276         } else if (!m_exact_match.get_result(1).empty()) {
277             result += utf8_mbstowcs (m_exact_match.get_result(1));
278         } else if (m_pending.length () > 0) {
279             result += m_pending;
280         }
281     }
282     clear ();
283     return result;
284 }
285
286 void
287 Key2KanaConvertor::reset_pending (const WideString &result, const String &raw)
288 {
289     m_last_key = KeyEvent ();
290
291     for (unsigned int i = 0; i < raw.length (); i++) {
292         WideString res, pend;
293         append (raw.substr(i, 1), res, pend);
294     }
295 }
296
297 bool
298 Key2KanaConvertor::process_pseudo_ascii_mode (const WideString & wstr)
299 {
300     for (unsigned int i = 0; i < wstr.length (); i++) {
301         if ((wstr[i] >= 'A' && wstr[i] <= 'Z') ||
302             iswspace(wstr[i]))
303         {
304             m_is_in_pseudo_ascii_mode = true;
305         } else if (wstr[i] >= 0x80) {
306             m_is_in_pseudo_ascii_mode = false;
307         }
308     }
309
310     return m_is_in_pseudo_ascii_mode;
311 }
312
313 void
314 Key2KanaConvertor::reset_pseudo_ascii_mode (void)
315 {
316     if (m_is_in_pseudo_ascii_mode)
317         m_pending.clear();
318     m_is_in_pseudo_ascii_mode = false;
319 }
320
321 /*
322 vi:ts=4:nowrap:ai:expandtab
323 */