1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  *  Copyright (C) 2004 - 2005 Hiroyuki Ikezoe <poincare@ikezoe.net>
4  *  Copyright (C) 2004 - 2005 Takuro Ashie <ashie@homa.ne.jp>
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 /*
22  * The original code is scim_uim_imengine.cpp in scim-uim-0.1.3.
23  * Copyright (C) 2004 James Su <suzhe@tsinghua.org.cn>
24  */
25 
26 #define Uses_SCIM_UTILITY
27 #define Uses_SCIM_IMENGINE
28 #define Uses_SCIM_LOOKUP_TABLE
29 #define Uses_SCIM_CONFIG_BASE
30 
31 #ifdef HAVE_CONFIG_H
32   #include <config.h>
33 #endif
34 
35 #include <stdio.h>
36 #include <unistd.h>
37 #include <sys/types.h>
38 
39 #include <scim.h>
40 #include "scim_anthy_factory.h"
41 #include "scim_anthy_imengine.h"
42 #include "scim_anthy_prefs.h"
43 #include "scim_anthy_intl.h"
44 #include "scim_anthy_utils.h"
45 #include "scim_anthy_helper.h"
46 
47 #define SCIM_PROP_PREFIX                     "/IMEngine/Anthy"
48 #define SCIM_PROP_INPUT_MODE                 "/IMEngine/Anthy/InputMode"
49 #define SCIM_PROP_INPUT_MODE_HIRAGANA        "/IMEngine/Anthy/InputMode/Hiragana"
50 #define SCIM_PROP_INPUT_MODE_KATAKANA        "/IMEngine/Anthy/InputMode/Katakana"
51 #define SCIM_PROP_INPUT_MODE_HALF_KATAKANA   "/IMEngine/Anthy/InputMode/HalfKatakana"
52 #define SCIM_PROP_INPUT_MODE_LATIN           "/IMEngine/Anthy/InputMode/Latin"
53 #define SCIM_PROP_INPUT_MODE_WIDE_LATIN      "/IMEngine/Anthy/InputMode/WideLatin"
54 
55 #define SCIM_PROP_CONV_MODE                  "/IMEngine/Anthy/ConvMode"
56 #define SCIM_PROP_CONV_MODE_MULTI_SEG        "/IMEngine/Anthy/ConvMode/MultiSegment"
57 #define SCIM_PROP_CONV_MODE_SINGLE_SEG       "/IMEngine/Anthy/ConvMode/SingleSegment"
58 #define SCIM_PROP_CONV_MODE_MULTI_REAL_TIME  "/IMEngine/Anthy/ConvMode/MultiRealTime"
59 #define SCIM_PROP_CONV_MODE_SINGLE_REAL_TIME "/IMEngine/Anthy/ConvMode/SingleRealTime"
60 
61 #define SCIM_PROP_TYPING_METHOD              "/IMEngine/Anthy/TypingMethod"
62 #define SCIM_PROP_TYPING_METHOD_ROMAJI       "/IMEngine/Anthy/TypingMethod/RomaKana"
63 #define SCIM_PROP_TYPING_METHOD_KANA         "/IMEngine/Anthy/TypingMethod/Kana"
64 #define SCIM_PROP_TYPING_METHOD_NICOLA       "/IMEngine/Anthy/TypingMethod/NICOLA"
65 
66 #define SCIM_PROP_PERIOD_STYLE               "/IMEngine/Anthy/PeriodType"
67 #define SCIM_PROP_PERIOD_STYLE_JAPANESE      "/IMEngine/Anthy/PeriodType/Japanese"
68 #define SCIM_PROP_PERIOD_STYLE_WIDE_LATIN    "/IMEngine/Anthy/PeriodType/WideRatin"
69 #define SCIM_PROP_PERIOD_STYLE_LATIN         "/IMEngine/Anthy/PeriodType/Ratin"
70 #define SCIM_PROP_PERIOD_STYLE_WIDE_LATIN_JAPANESE \
71                                              "/IMEngine/Anthy/PeriodType/WideRatin_Japanese"
72 
73 #define SCIM_PROP_SYMBOL_STYLE               "/IMEngine/Anthy/SymbolType"
74 #define SCIM_PROP_SYMBOL_STYLE_JAPANESE      "/IMEngine/Anthy/SymbolType/Japanese"
75 #define SCIM_PROP_SYMBOL_STYLE_BRACKET_SLASH "/IMEngine/Anthy/SymbolType/WideBracket_WideSlash"
76 #define SCIM_PROP_SYMBOL_STYLE_CORNER_BRACKET_SLASH \
77                                              "/IMEngine/Anthy/SymbolType/CornerBracket_WideSlash"
78 #define SCIM_PROP_SYMBOL_STYLE_BRACKET_MIDDLE_DOT \
79                                              "/IMEngine/Anthy/SymbolType/WideBracket_MiddleDot"
80 
81 #define SCIM_PROP_DICT                       "/IMEngine/Anthy/Dictionary"
82 #define SCIM_PROP_DICT_ADD_WORD              "/IMEngine/Anthy/Dictionary/AddWord"
83 #define SCIM_PROP_DICT_LAUNCH_ADMIN_TOOL     "/IMEngine/Anthy/Dictionary/LaunchAdminTool"
84 
85 #define UTF8_BRACKET_CORNER_BEGIN "\xE3\x80\x8C"
86 #define UTF8_BRACKET_CORNER_END   "\xE3\x80\x8D"
87 #define UTF8_BRACKET_WIDE_BEGIN   "\xEF\xBC\xBB"
88 #define UTF8_BRACKET_WIDE_END     "\xEF\xBC\xBD"
89 #define UTF8_MIDDLE_DOT           "\xE3\x83\xBB"
90 #define UTF8_SLASH_WIDE           "\xEF\xBC\x8F"
91 
AnthyInstance(AnthyFactory * factory,const String & encoding,int id)92 AnthyInstance::AnthyInstance (AnthyFactory   *factory,
93                               const String   &encoding,
94                               int             id)
95     : IMEngineInstanceBase     (factory, encoding, id),
96       m_factory                (factory),
97       m_on_init                (true),
98       m_preedit                (*this),
99       m_preedit_string_visible (false),
100       m_lookup_table_visible   (false),
101       m_n_conv_key_pressed     (0),
102       m_prev_input_mode        (SCIM_ANTHY_MODE_HIRAGANA),
103       m_conv_mode              (SCIM_ANTHY_CONVERSION_MULTI_SEGMENT),
104       m_helper_started         (false),
105       m_timeout_id_seq         (0)
106 {
107     SCIM_DEBUG_IMENGINE(1) << "Create Anthy Instance : ";
108 
109     reload_config (m_factory->m_config);
110     m_factory->append_config_listener (this);
111     m_on_init = false;
112 }
113 
~AnthyInstance()114 AnthyInstance::~AnthyInstance ()
115 {
116     if (m_helper_started)
117         stop_helper (String (SCIM_ANTHY_HELPER_UUID));
118 
119     m_factory->remove_config_listener (this);
120 }
121 
122 // FIXME!
123 bool
is_nicola_thumb_shift_key(const KeyEvent & key)124 AnthyInstance::is_nicola_thumb_shift_key (const KeyEvent &key)
125 {
126     if (get_typing_method () != SCIM_ANTHY_TYPING_METHOD_NICOLA)
127         return false;
128 
129     if (util_match_key_event (m_factory->m_left_thumb_keys, key, 0xFFFF) ||
130         util_match_key_event (m_factory->m_right_thumb_keys, key, 0xFFFF))
131     {
132         return true;
133     }
134 
135     return false;
136 }
137 
138 bool
process_key_event_input(const KeyEvent & key)139 AnthyInstance::process_key_event_input (const KeyEvent &key)
140 {
141     // prediction while typing
142     if (m_factory->m_predict_on_input && key.is_key_release () &&
143         m_preedit.is_preediting () && !m_preedit.is_converting ())
144     {
145         CommonLookupTable table;
146         m_preedit.predict ();
147         m_preedit.get_candidates (table);
148         if (table.number_of_candidates () > 0) {
149             table.show_cursor (false);
150             update_lookup_table (table);
151             show_lookup_table ();
152         } else {
153             hide_lookup_table ();
154         }
155     }
156 
157     if (!m_preedit.can_process_key_event (key)) {
158         return false;
159     }
160 
161     if (m_preedit.is_converting ()) {
162         if (is_realtime_conversion ()) {
163             action_revert ();
164         } else if (!is_nicola_thumb_shift_key (key)) {
165             action_commit (m_factory->m_learn_on_auto_commit);
166         }
167     }
168 
169     bool need_commit = m_preedit.process_key_event (key);
170 
171     if (need_commit) {
172         if (is_realtime_conversion () &&
173             get_input_mode () != SCIM_ANTHY_MODE_LATIN &&
174             get_input_mode () != SCIM_ANTHY_MODE_WIDE_LATIN)
175         {
176             m_preedit.convert (SCIM_ANTHY_CANDIDATE_DEFAULT,
177                                is_single_segment ());
178         }
179         action_commit (m_factory->m_learn_on_auto_commit);
180     } else {
181         if (is_realtime_conversion ()) {
182             m_preedit.convert (SCIM_ANTHY_CANDIDATE_DEFAULT,
183                                is_single_segment ());
184             m_preedit.select_segment (-1);
185         }
186         show_preedit_string ();
187         m_preedit_string_visible = true;
188         set_preedition ();
189     }
190 
191     return true;
192 }
193 
194 bool
process_key_event_lookup_keybind(const KeyEvent & key)195 AnthyInstance::process_key_event_lookup_keybind (const KeyEvent& key)
196 {
197     std::vector<Action>::iterator it;
198 
199     m_last_key = key;
200 
201     /* try to find a "insert a blank" action to be not stolen a blank key
202      * when entering the pseudo ascii mode.
203      */
204     if (get_pseudo_ascii_mode () != 0 &&
205         m_factory->m_romaji_pseudo_ascii_blank_behavior &&
206         m_preedit.is_pseudo_ascii_mode ()) {
207         for (it  = m_factory->m_actions.begin();
208              it != m_factory->m_actions.end();
209              it++) {
210             if (it->match_action_name ("INSERT_SPACE") &&
211                 it->perform (this, key)) {
212                 return true;
213             }
214         }
215     }
216     for (it  = m_factory->m_actions.begin();
217          it != m_factory->m_actions.end();
218          it++)
219     {
220         if (it->perform (this, key)) {
221             m_last_key = KeyEvent ();
222             return true;
223         }
224     }
225 
226     m_last_key = KeyEvent ();
227 
228     return false;
229 }
230 
231 bool
process_key_event_latin_mode(const KeyEvent & key)232 AnthyInstance::process_key_event_latin_mode (const KeyEvent &key)
233 {
234     if (key.is_key_release ())
235         return false;
236 
237     if (util_key_is_keypad (key)) {
238         String str;
239         WideString wide;
240         util_keypad_to_string (str, key);
241         if (m_factory->m_ten_key_type == "Wide")
242             util_convert_to_wide (wide, str);
243         else
244             wide = utf8_mbstowcs (str);
245         if (wide.length () > 0) {
246             commit_string (wide);
247             return true;
248         } else {
249             return false;
250         }
251     } else {
252         // for Multi/Dead key
253         return false;
254     }
255 }
256 
257 bool
process_key_event_wide_latin_mode(const KeyEvent & key)258 AnthyInstance::process_key_event_wide_latin_mode (const KeyEvent &key)
259 {
260     if (key.is_key_release ())
261         return false;
262 
263     String str;
264     WideString wide;
265     util_keypad_to_string (str, key);
266     if (util_key_is_keypad (key) && m_factory->m_ten_key_type == "Half")
267         wide = utf8_mbstowcs (str);
268     else
269         util_convert_to_wide (wide, str);
270     if (wide.length () > 0) {
271         commit_string (wide);
272         return true;
273     }
274 
275     return false;
276 }
277 
278 bool
process_key_event(const KeyEvent & key)279 AnthyInstance::process_key_event (const KeyEvent& key)
280 {
281     SCIM_DEBUG_IMENGINE(2) << "process_key_event.\n";
282 
283     // FIXME!
284     // for NICOLA thumb shift key
285     if (get_typing_method () == SCIM_ANTHY_TYPING_METHOD_NICOLA &&
286         is_nicola_thumb_shift_key (key))
287     {
288         if (process_key_event_input (key))
289             return true;
290     }
291 
292     // lookup user defined key bindings
293     if (process_key_event_lookup_keybind (key))
294         return true;
295 
296     // for Latin mode
297     if (m_preedit.get_input_mode () == SCIM_ANTHY_MODE_LATIN)
298         return process_key_event_latin_mode (key);
299 
300     // for wide Latin mode
301     if (m_preedit.get_input_mode () == SCIM_ANTHY_MODE_WIDE_LATIN)
302         return process_key_event_wide_latin_mode (key);
303 
304     // for other mode
305     if (get_typing_method () != SCIM_ANTHY_TYPING_METHOD_NICOLA ||
306         !is_nicola_thumb_shift_key (key))
307     {
308         if (process_key_event_input (key))
309             return true;
310     }
311 
312     if (m_preedit.is_preediting ())
313         return true;
314     else
315         return false;
316 }
317 
318 void
move_preedit_caret(unsigned int pos)319 AnthyInstance::move_preedit_caret (unsigned int pos)
320 {
321     m_preedit.set_caret_pos (pos);
322     update_preedit_caret (m_preedit.get_caret_pos());
323 }
324 
325 void
select_candidate_no_direct(unsigned int item)326 AnthyInstance::select_candidate_no_direct (unsigned int item)
327 {
328     SCIM_DEBUG_IMENGINE(2) << "select_candidate_no_direct.\n";
329 
330     if (m_preedit.is_predicting () && !m_preedit.is_converting ())
331         action_predict ();
332 
333     if (!is_selecting_candidates ())
334         return;
335 
336     // update lookup table
337     m_lookup_table.set_cursor_pos_in_current_page (item);
338     update_lookup_table (m_lookup_table);
339 
340     // update preedit
341     m_preedit.select_candidate (m_lookup_table.get_cursor_pos ());
342     set_preedition ();
343 
344     // update aux string
345     if (m_factory->m_show_candidates_label)
346         set_aux_string ();
347 }
348 
349 void
select_candidate(unsigned int item)350 AnthyInstance::select_candidate (unsigned int item)
351 {
352     SCIM_DEBUG_IMENGINE(2) << "select_candidate.\n";
353 
354     select_candidate_no_direct (item);
355 
356     if (m_factory->m_close_cand_win_on_select) {
357         unset_lookup_table ();
358         action_select_next_segment();
359     }
360 }
361 
362 void
update_lookup_table_page_size(unsigned int page_size)363 AnthyInstance::update_lookup_table_page_size (unsigned int page_size)
364 {
365     SCIM_DEBUG_IMENGINE(2) << "update_lookup_table_page_size.\n";
366 
367     m_lookup_table.set_page_size (page_size);
368 }
369 
370 void
lookup_table_page_up()371 AnthyInstance::lookup_table_page_up ()
372 {
373     if (!is_selecting_candidates () ||
374         !m_lookup_table.get_current_page_start ())
375     {
376         return;
377     }
378 
379     SCIM_DEBUG_IMENGINE(2) << "lookup_table_page_up.\n";
380 
381     m_lookup_table.page_up ();
382 
383     update_lookup_table (m_lookup_table);
384 }
385 
386 void
lookup_table_page_down()387 AnthyInstance::lookup_table_page_down ()
388 {
389     int page_start = m_lookup_table.get_current_page_start ();
390     int page_size = m_lookup_table.get_current_page_size ();
391     int num = m_lookup_table.number_of_candidates ();
392 
393     if (!is_selecting_candidates () || page_start + page_size >= num)
394         return;
395 
396     SCIM_DEBUG_IMENGINE(2) << "lookup_table_page_down.\n";
397 
398     m_lookup_table.page_down ();
399 
400     update_lookup_table (m_lookup_table);
401 }
402 
403 void
reset()404 AnthyInstance::reset ()
405 {
406     SCIM_DEBUG_IMENGINE(2) << "reset.\n";
407 
408     m_preedit.clear ();
409     m_lookup_table.clear ();
410     unset_lookup_table ();
411 
412     hide_preedit_string ();
413     m_preedit_string_visible = false;
414     set_preedition ();
415 }
416 
417 void
focus_in()418 AnthyInstance::focus_in ()
419 {
420     SCIM_DEBUG_IMENGINE(2) << "focus_in.\n";
421 
422     if (m_preedit_string_visible) {
423         set_preedition ();
424         show_preedit_string ();
425     } else {
426         hide_preedit_string ();
427     }
428 
429     if (m_lookup_table_visible && is_selecting_candidates ()) {
430         if (m_factory->m_show_candidates_label &&
431             m_lookup_table.number_of_candidates() > 0)
432         {
433             set_aux_string ();
434             show_aux_string ();
435         } else {
436             hide_aux_string ();
437         }
438         update_lookup_table (m_lookup_table);
439         show_lookup_table ();
440     } else {
441         hide_aux_string ();
442         hide_lookup_table ();
443     }
444 
445     install_properties ();
446 
447     if (!m_helper_started)
448         start_helper (String (SCIM_ANTHY_HELPER_UUID));
449 
450     Transaction send;
451     send.put_command (SCIM_TRANS_CMD_REQUEST);
452     send.put_command (SCIM_TRANS_CMD_FOCUS_IN);
453     send_helper_event (String (SCIM_ANTHY_HELPER_UUID), send);
454 }
455 
456 void
focus_out()457 AnthyInstance::focus_out ()
458 {
459     SCIM_DEBUG_IMENGINE(2) << "focus_out.\n";
460 
461     if (m_preedit.is_preediting ()) {
462         if (m_factory->m_behavior_on_focus_out == "Clear")
463             reset ();
464         else if (m_factory->m_behavior_on_focus_out == "Commit")
465             action_commit (m_factory->m_learn_on_auto_commit);
466         else
467             action_commit (m_factory->m_learn_on_auto_commit);
468     }
469 
470     Transaction send;
471     send.put_command (SCIM_TRANS_CMD_REQUEST);
472     send.put_command (SCIM_TRANS_CMD_FOCUS_OUT);
473     send_helper_event (String (SCIM_ANTHY_HELPER_UUID), send);
474 }
475 
476 void
set_preedition(void)477 AnthyInstance::set_preedition (void)
478 {
479     update_preedit_string (m_preedit.get_string (),
480                            m_preedit.get_attribute_list ());
481     update_preedit_caret (m_preedit.get_caret_pos());
482 }
483 
484 void
set_aux_string(void)485 AnthyInstance::set_aux_string (void)
486 {
487     char buf[256];
488     sprintf (buf, _("Candidates (%d/%d)"),
489              m_lookup_table.get_cursor_pos () + 1,
490              m_lookup_table.number_of_candidates ());
491     update_aux_string (utf8_mbstowcs (buf));
492 }
493 
494 void
set_lookup_table(void)495 AnthyInstance::set_lookup_table (void)
496 {
497     m_n_conv_key_pressed++;
498 
499     if (!is_selecting_candidates ()) {
500         if (is_realtime_conversion () &&
501             m_preedit.get_selected_segment () < 0)
502         {
503             // select latest segment
504             int n = m_preedit.get_nr_segments ();
505             if (n < 1)
506                 return;
507             m_preedit.select_segment (n - 1);
508         }
509 
510         // prepare candidates
511         m_preedit.get_candidates (m_lookup_table);
512 
513         if (m_lookup_table.number_of_candidates () == 0)
514             return;
515 
516         // set position
517         update_lookup_table (m_lookup_table);
518 
519         // update preedit
520         m_preedit.select_candidate (m_lookup_table.get_cursor_pos ());
521         set_preedition ();
522 
523     }
524 
525     bool beyond_threshold =
526         m_factory->m_n_triggers_to_show_cand_win > 0 &&
527         (int) m_n_conv_key_pressed >= m_factory->m_n_triggers_to_show_cand_win;
528 
529     if (!m_lookup_table_visible &&
530         (m_preedit.is_predicting () || beyond_threshold))
531     {
532         show_lookup_table ();
533         m_lookup_table_visible = true;
534         m_n_conv_key_pressed = 0;
535 
536         if (m_factory->m_show_candidates_label) {
537             set_aux_string ();
538             show_aux_string ();
539         }
540     } else if (!m_lookup_table_visible) {
541         hide_lookup_table ();
542     }
543 }
544 
545 void
unset_lookup_table(void)546 AnthyInstance::unset_lookup_table (void)
547 {
548     m_lookup_table.clear ();
549     hide_lookup_table ();
550     m_lookup_table_visible = false;
551     m_n_conv_key_pressed = 0;
552 
553     update_aux_string (utf8_mbstowcs (""));
554     hide_aux_string ();
555 }
556 
557 void
install_properties(void)558 AnthyInstance::install_properties (void)
559 {
560     if (m_properties.size () <= 0) {
561         Property prop;
562 
563         if (m_factory->m_show_input_mode_label) {
564             prop = Property (SCIM_PROP_INPUT_MODE,
565                              "\xE3\x81\x82", String (""), _("Input mode"));
566             m_properties.push_back (prop);
567 
568             prop = Property (SCIM_PROP_INPUT_MODE_HIRAGANA,
569                              _("Hiragana"), String (""), _("Hiragana"));
570             m_properties.push_back (prop);
571 
572             prop = Property (SCIM_PROP_INPUT_MODE_KATAKANA,
573                              _("Katakana"), String (""), _("Katakana"));
574             m_properties.push_back (prop);
575 
576             prop = Property (SCIM_PROP_INPUT_MODE_HALF_KATAKANA,
577                              _("Half width katakana"), String (""),
578                              _("Half width katakana"));
579             m_properties.push_back (prop);
580 
581             prop = Property (SCIM_PROP_INPUT_MODE_LATIN,
582                              _("Latin"), String (""), _("Direct input"));
583             m_properties.push_back (prop);
584 
585             prop = Property (SCIM_PROP_INPUT_MODE_WIDE_LATIN,
586                              _("Wide latin"), String (""), _("Wide latin"));
587             m_properties.push_back (prop);
588         }
589 
590         if (m_factory->m_show_typing_method_label) {
591             prop = Property (SCIM_PROP_TYPING_METHOD,
592                              "\xEF\xBC\xB2", String (""), _("Typing method"));
593             m_properties.push_back (prop);
594 
595             prop = Property (SCIM_PROP_TYPING_METHOD_ROMAJI,
596                              _("Romaji"), String (""), _("Romaji"));
597             m_properties.push_back (prop);
598 
599             prop = Property (SCIM_PROP_TYPING_METHOD_KANA,
600                              _("Kana"), String (""), _("Kana"));
601             m_properties.push_back (prop);
602 
603             prop = Property (SCIM_PROP_TYPING_METHOD_NICOLA,
604                              _("Thumb shift"), String (""), _("Thumb shift"));
605             m_properties.push_back (prop);
606         }
607 
608         if (m_factory->m_show_conv_mode_label) {
609             prop = Property (SCIM_PROP_CONV_MODE,
610                              "\xE9\x80\xA3", String (""),
611                              _("Conversion mode"));
612             m_properties.push_back (prop);
613 
614             prop = Property (SCIM_PROP_CONV_MODE_MULTI_SEG,
615                              _("Multi segment"), String (""),
616                              _("Multi segment"));
617             m_properties.push_back (prop);
618 
619             prop = Property (SCIM_PROP_CONV_MODE_SINGLE_SEG,
620                              _("Single segment"), String (""),
621                              _("Single segment"));
622             m_properties.push_back (prop);
623 
624             prop = Property (SCIM_PROP_CONV_MODE_MULTI_REAL_TIME,
625                              _("Convert as you type (Multi segment)"),
626                              String (""),
627                              _("Convert as you type (Multi segment)"));
628             m_properties.push_back (prop);
629 
630             prop = Property (SCIM_PROP_CONV_MODE_SINGLE_REAL_TIME,
631                              _("Convert as you type (Single segment)"),
632                              String (""),
633                              _("Convert as you type (Single segment)"));
634             m_properties.push_back (prop);
635         }
636 
637         if (m_factory->m_show_period_style_label) {
638             prop = Property (SCIM_PROP_PERIOD_STYLE,
639                              "\xE3\x80\x81\xE3\x80\x82", String (""),
640                              _("Period style"));
641             m_properties.push_back (prop);
642 
643             prop = Property (SCIM_PROP_PERIOD_STYLE_JAPANESE,
644                              "\xE3\x80\x81\xE3\x80\x82", String (""),
645                              "\xE3\x80\x81\xE3\x80\x82");
646             m_properties.push_back (prop);
647 
648             prop = Property (SCIM_PROP_PERIOD_STYLE_WIDE_LATIN_JAPANESE,
649                              "\xEF\xBC\x8C\xE3\x80\x82", String (""),
650                              "\xEF\xBC\x8C\xE3\x80\x82");
651             m_properties.push_back (prop);
652 
653             prop = Property (SCIM_PROP_PERIOD_STYLE_WIDE_LATIN,
654                              "\xEF\xBC\x8C\xEF\xBC\x8E", String (""),
655                              "\xEF\xBC\x8C\xEF\xBC\x8E");
656             m_properties.push_back (prop);
657 
658             prop = Property (SCIM_PROP_PERIOD_STYLE_LATIN,
659                              ",.", String (""), ",.");
660             m_properties.push_back (prop);
661         }
662 
663         if (m_factory->m_show_symbol_style_label) {
664             prop = Property (SCIM_PROP_SYMBOL_STYLE,
665                              UTF8_BRACKET_CORNER_BEGIN
666                              UTF8_BRACKET_CORNER_END
667                              UTF8_MIDDLE_DOT,
668                              String (""),
669                              _("Symbol style"));
670             m_properties.push_back (prop);
671 
672             prop = Property (SCIM_PROP_SYMBOL_STYLE_JAPANESE,
673                              UTF8_BRACKET_CORNER_BEGIN
674                              UTF8_BRACKET_CORNER_END
675                              UTF8_MIDDLE_DOT,
676                              String (""),
677                              UTF8_BRACKET_CORNER_BEGIN
678                              UTF8_BRACKET_CORNER_END
679                              UTF8_MIDDLE_DOT);
680             m_properties.push_back (prop);
681 
682             prop = Property (SCIM_PROP_SYMBOL_STYLE_CORNER_BRACKET_SLASH,
683                              UTF8_BRACKET_CORNER_BEGIN
684                              UTF8_BRACKET_CORNER_END
685                              UTF8_SLASH_WIDE,
686                              String (""),
687                              UTF8_BRACKET_CORNER_BEGIN
688                              UTF8_BRACKET_CORNER_END
689                              UTF8_SLASH_WIDE);
690             m_properties.push_back (prop);
691 
692             prop = Property (SCIM_PROP_SYMBOL_STYLE_BRACKET_MIDDLE_DOT,
693                              UTF8_BRACKET_WIDE_BEGIN
694                              UTF8_BRACKET_WIDE_END
695                              UTF8_MIDDLE_DOT,
696                              String (""),
697                              UTF8_BRACKET_WIDE_BEGIN
698                              UTF8_BRACKET_WIDE_END
699                              UTF8_MIDDLE_DOT);
700             m_properties.push_back (prop);
701 
702             prop = Property (SCIM_PROP_SYMBOL_STYLE_BRACKET_SLASH,
703                              UTF8_BRACKET_WIDE_BEGIN
704                              UTF8_BRACKET_WIDE_END
705                              UTF8_SLASH_WIDE,
706                              String (""),
707                              UTF8_BRACKET_WIDE_BEGIN
708                              UTF8_BRACKET_WIDE_END
709                              UTF8_SLASH_WIDE);
710             m_properties.push_back (prop);
711         }
712 
713         if (m_factory->m_show_dict_label) {
714             prop = Property (SCIM_PROP_DICT,
715                              String(""), //_("Dictionary"),
716                              String (SCIM_ICONDIR "/" "scim-anthy-dict.png"),
717                              _("Dictionary menu"));
718             m_properties.push_back (prop);
719 
720             if (m_factory->m_show_dict_admin_label) {
721                 prop = Property (SCIM_PROP_DICT_LAUNCH_ADMIN_TOOL,
722                                  _("Edit the dictionary"),
723                                  String (SCIM_ICONDIR "/" "scim-anthy-dict.png"),
724                                  _("Launch the dictionary administration tool."));
725                 m_properties.push_back (prop);
726             }
727 
728             if (m_factory->m_show_add_word_label) {
729                 prop = Property (SCIM_PROP_DICT_ADD_WORD,
730                                  _("Add a word"),
731                                  String (SCIM_ICONDIR "/" "scim-anthy-dict.png"),
732                                  _("Add a word to the dictionary."));
733                 m_properties.push_back (prop);
734             }
735         }
736     }
737 
738     set_input_mode(get_input_mode ());
739     set_conversion_mode (m_conv_mode);
740     set_typing_method (get_typing_method ());
741     set_period_style (m_preedit.get_period_style (),
742                       m_preedit.get_comma_style ());
743     set_symbol_style (m_preedit.get_bracket_style (),
744                       m_preedit.get_slash_style ());
745 
746     register_properties (m_properties);
747 }
748 
749 void
set_input_mode(InputMode mode)750 AnthyInstance::set_input_mode (InputMode mode)
751 {
752     const char *label = "";
753 
754     switch (mode) {
755     case SCIM_ANTHY_MODE_HIRAGANA:
756         label = "\xE3\x81\x82";
757         break;
758     case SCIM_ANTHY_MODE_KATAKANA:
759         label = "\xE3\x82\xA2";
760         break;
761     case SCIM_ANTHY_MODE_HALF_KATAKANA:
762         label = "_\xEF\xBD\xB1";
763         break;
764     case SCIM_ANTHY_MODE_LATIN:
765         label = "_A";
766         break;
767     case SCIM_ANTHY_MODE_WIDE_LATIN:
768         label = "\xEF\xBC\xA1";
769         break;
770     default:
771         break;
772     }
773 
774     if (label && *label && m_factory->m_show_input_mode_label) {
775         PropertyList::iterator it = std::find (m_properties.begin (),
776                                                m_properties.end (),
777                                                SCIM_PROP_INPUT_MODE);
778         if (it != m_properties.end ()) {
779             it->set_label (label);
780             update_property (*it);
781         }
782     }
783 
784     if (mode != get_input_mode ()) {
785         m_preedit.set_input_mode (mode);
786         set_preedition ();
787     }
788 }
789 
790 void
set_conversion_mode(ConversionMode mode)791 AnthyInstance::set_conversion_mode (ConversionMode mode)
792 {
793     const char *label = "";
794 
795     switch (mode) {
796     case SCIM_ANTHY_CONVERSION_MULTI_SEGMENT:
797         label = "\xE9\x80\xA3";
798         break;
799     case SCIM_ANTHY_CONVERSION_SINGLE_SEGMENT:
800         label = "\xE5\x8D\x98";
801         break;
802     case SCIM_ANTHY_CONVERSION_MULTI_SEGMENT_IMMEDIATE:
803         label = "\xE9\x80\x90 \xE9\x80\xA3";
804         break;
805     case SCIM_ANTHY_CONVERSION_SINGLE_SEGMENT_IMMEDIATE:
806         label = "\xE9\x80\x90 \xE5\x8D\x98";
807         break;
808     default:
809         break;
810     }
811 
812     if (label && *label /*&& m_factory->m_show_input_mode_label*/) {
813         PropertyList::iterator it = std::find (m_properties.begin (),
814                                                m_properties.end (),
815                                                SCIM_PROP_CONV_MODE);
816         if (it != m_properties.end ()) {
817             it->set_label (label);
818             update_property (*it);
819         }
820     }
821 
822     m_conv_mode = mode;
823 }
824 
825 void
set_typing_method(TypingMethod method)826 AnthyInstance::set_typing_method (TypingMethod method)
827 {
828     const char *label = "";
829 
830     switch (method) {
831     case SCIM_ANTHY_TYPING_METHOD_ROMAJI:
832         label = "\xEF\xBC\xB2";
833         break;
834     case SCIM_ANTHY_TYPING_METHOD_KANA:
835         label = "\xE3\x81\x8B";
836         break;
837     case SCIM_ANTHY_TYPING_METHOD_NICOLA:
838         label = "\xE8\xA6\xAA";
839         break;
840     default:
841         break;
842     }
843 
844     if (label && *label && m_factory->m_show_typing_method_label) {
845         PropertyList::iterator it = std::find (m_properties.begin (),
846                                                m_properties.end (),
847                                                SCIM_PROP_TYPING_METHOD);
848         if (it != m_properties.end ()) {
849             it->set_label (label);
850             update_property (*it);
851         }
852     }
853 
854     if (method != get_typing_method ()) {
855         Key2KanaTable *fundamental_table = NULL;
856 
857         if (method == SCIM_ANTHY_TYPING_METHOD_ROMAJI) {
858             fundamental_table = m_factory->m_custom_romaji_table;
859         } else if (method == SCIM_ANTHY_TYPING_METHOD_KANA) {
860             fundamental_table = m_factory->m_custom_kana_table;
861         }
862         m_preedit.set_typing_method (method);
863         m_preedit.set_pseudo_ascii_mode (get_pseudo_ascii_mode ());
864     }
865 }
866 
867 void
set_period_style(PeriodStyle period,CommaStyle comma)868 AnthyInstance::set_period_style (PeriodStyle period,
869                                  CommaStyle  comma)
870 {
871     String label;
872 
873     switch (comma) {
874     case SCIM_ANTHY_COMMA_JAPANESE:
875         label = "\xE3\x80\x81";
876         break;
877     case SCIM_ANTHY_COMMA_WIDE:
878         label = "\xEF\xBC\x8C";
879         break;
880     case SCIM_ANTHY_COMMA_HALF:
881         label = ",";
882         break;
883     default:
884         break;
885     }
886 
887     switch (period) {
888     case SCIM_ANTHY_PERIOD_JAPANESE:
889         label += "\xE3\x80\x82";
890         break;
891     case SCIM_ANTHY_PERIOD_WIDE:
892         label += "\xEF\xBC\x8E";
893         break;
894     case SCIM_ANTHY_PERIOD_HALF:
895         label += ".";
896         break;
897     default:
898         break;
899     }
900 
901     if (label.length () > 0) {
902         PropertyList::iterator it = std::find (m_properties.begin (),
903                                                m_properties.end (),
904                                                SCIM_PROP_PERIOD_STYLE);
905         if (it != m_properties.end ()) {
906             it->set_label (label.c_str ());
907             update_property (*it);
908         }
909     }
910 
911     if (period != m_preedit.get_period_style ())
912         m_preedit.set_period_style (period);
913     if (comma != m_preedit.get_comma_style ())
914         m_preedit.set_comma_style (comma);
915 }
916 
917 void
set_symbol_style(BracketStyle bracket,SlashStyle slash)918 AnthyInstance::set_symbol_style (BracketStyle bracket,
919                                  SlashStyle   slash)
920 {
921     String label;
922 
923     switch (bracket) {
924     case SCIM_ANTHY_BRACKET_JAPANESE:
925         label = UTF8_BRACKET_CORNER_BEGIN UTF8_BRACKET_CORNER_END;
926         break;
927     case SCIM_ANTHY_BRACKET_WIDE:
928         label = UTF8_BRACKET_WIDE_BEGIN UTF8_BRACKET_WIDE_END;
929         break;
930     default:
931         break;
932     }
933 
934     switch (slash) {
935     case SCIM_ANTHY_SLASH_JAPANESE:
936         label += UTF8_MIDDLE_DOT;
937         break;
938     case SCIM_ANTHY_SLASH_WIDE:
939         label += UTF8_SLASH_WIDE;
940         break;
941     default:
942         break;
943     }
944 
945     if (label.length () > 0) {
946         PropertyList::iterator it = std::find (m_properties.begin (),
947                                                m_properties.end (),
948                                                SCIM_PROP_SYMBOL_STYLE);
949         if (it != m_properties.end ()) {
950             it->set_label (label.c_str ());
951             update_property (*it);
952         }
953     }
954 
955     if (bracket != m_preedit.get_bracket_style ())
956         m_preedit.set_bracket_style (bracket);
957     if (slash != m_preedit.get_slash_style ())
958         m_preedit.set_slash_style (slash);
959 }
960 
961 bool
is_selecting_candidates(void)962 AnthyInstance::is_selecting_candidates (void)
963 {
964     if (m_lookup_table.number_of_candidates ())
965         return true;
966     else
967         return false;
968 }
969 
970 bool
action_do_nothing(void)971 AnthyInstance::action_do_nothing (void)
972 {
973     return true;
974 }
975 
976 bool
action_convert(void)977 AnthyInstance::action_convert (void)
978 {
979     if (!m_preedit.is_preediting ())
980         return false;
981 
982     if (!m_preedit.is_converting ()) {
983         // show conversion string
984         m_preedit.finish ();
985         m_preedit.convert (SCIM_ANTHY_CANDIDATE_DEFAULT,
986                            is_single_segment ());
987         set_preedition ();
988         set_lookup_table ();
989         return true;
990     }
991 
992     return false;
993 }
994 
995 bool
action_predict(void)996 AnthyInstance::action_predict (void)
997 {
998     if (!m_preedit.is_preediting ())
999         return false;
1000 
1001     if (m_preedit.is_converting ())
1002         return false;
1003 
1004     if (!m_preedit.is_predicting ())
1005         m_preedit.predict ();
1006 
1007     m_preedit.select_candidate (0);
1008     set_preedition ();
1009     set_lookup_table ();
1010     select_candidate_no_direct (0);
1011 
1012     return true;
1013 }
1014 
1015 
1016 bool
action_revert(void)1017 AnthyInstance::action_revert (void)
1018 {
1019     if (m_preedit.is_reconverting ()) {
1020         m_preedit.revert ();
1021         commit_string (m_preedit.get_string ());
1022         reset ();
1023         return true;
1024     }
1025 
1026     if (!m_preedit.is_preediting ())
1027         return false;
1028 
1029     if (!m_preedit.is_converting ()) {
1030         reset ();
1031         return true;
1032     }
1033 
1034     if (is_selecting_candidates ()) {
1035         m_lookup_table.clear ();
1036         if (m_lookup_table_visible) {
1037             unset_lookup_table ();
1038             return true;
1039         }
1040     }
1041 
1042     unset_lookup_table ();
1043     m_preedit.revert ();
1044     set_preedition ();
1045 
1046     return true;
1047 }
1048 
1049 bool
action_cancel_all(void)1050 AnthyInstance::action_cancel_all (void)
1051 {
1052     if (!m_preedit.is_preediting ())
1053         return false;
1054 
1055     reset ();
1056     return true;
1057 }
1058 
1059 bool
action_commit(bool learn)1060 AnthyInstance::action_commit (bool learn)
1061 {
1062     if (!m_preedit.is_preediting ())
1063         return false;
1064 
1065     if (m_preedit.is_converting ()) {
1066         commit_string (m_preedit.get_string ());
1067         if (learn)
1068             m_preedit.commit ();
1069     } else {
1070         m_preedit.finish ();
1071         commit_string (m_preedit.get_string ());
1072     }
1073 
1074     reset ();
1075 
1076     return true;
1077 }
1078 
1079 bool
action_commit_follow_preference(void)1080 AnthyInstance::action_commit_follow_preference (void)
1081 {
1082     return action_commit (m_factory->m_learn_on_manual_commit);
1083 }
1084 
1085 bool
action_commit_reverse_preference(void)1086 AnthyInstance::action_commit_reverse_preference (void)
1087 {
1088     return action_commit (!m_factory->m_learn_on_manual_commit);
1089 }
1090 
1091 bool
action_back(void)1092 AnthyInstance::action_back (void)
1093 {
1094     if (!m_preedit.is_preediting ())
1095         return false;
1096 
1097     if (m_preedit.is_converting ()) {
1098         action_revert ();
1099         if (!is_realtime_conversion ())
1100             return true;
1101     }
1102 
1103     m_preedit.erase ();
1104 
1105     if (m_preedit.get_length () > 0) {
1106         if (is_realtime_conversion ()) {
1107             m_preedit.convert (SCIM_ANTHY_CANDIDATE_DEFAULT,
1108                                is_single_segment ());
1109             m_preedit.select_segment (-1);
1110         }
1111         set_preedition ();
1112     } else {
1113         reset ();
1114     }
1115 
1116     return true;
1117 }
1118 
1119 bool
action_delete(void)1120 AnthyInstance::action_delete (void)
1121 {
1122     if (!m_preedit.is_preediting ())
1123         return false;
1124 
1125     if (m_preedit.is_converting ()) {
1126         action_revert ();
1127         if (!is_realtime_conversion ())
1128             return true;
1129     }
1130 
1131     m_preedit.erase (false);
1132 
1133     if (m_preedit.get_length () > 0) {
1134         if (is_realtime_conversion ()) {
1135             m_preedit.convert (SCIM_ANTHY_CANDIDATE_DEFAULT,
1136                                is_single_segment ());
1137             m_preedit.select_segment (-1);
1138         }
1139         set_preedition ();
1140     } else {
1141         reset ();
1142     }
1143 
1144     return true;
1145 }
1146 
1147 bool
action_insert_space(void)1148 AnthyInstance::action_insert_space (void)
1149 {
1150     String str;
1151     bool is_wide = false, retval = false;
1152 
1153     if (m_preedit.is_preediting () && !m_factory->m_romaji_pseudo_ascii_blank_behavior)
1154         return false;
1155 
1156     if (m_factory->m_space_type == "FollowMode") {
1157         InputMode mode = get_input_mode ();
1158         if (mode == SCIM_ANTHY_MODE_LATIN ||
1159             mode == SCIM_ANTHY_MODE_HALF_KATAKANA ||
1160             m_preedit.is_pseudo_ascii_mode ())
1161         {
1162             is_wide = false;
1163         } else {
1164             is_wide = true;
1165         }
1166     } else if (m_factory->m_space_type == "Wide") {
1167         is_wide = true;
1168     }
1169 
1170     if (is_wide) {
1171         str = "\xE3\x80\x80";
1172         retval = true;
1173     } else if (get_typing_method () == SCIM_ANTHY_TYPING_METHOD_NICOLA || // FIXME! it's a ad-hoc solution.
1174                m_preedit.is_pseudo_ascii_mode () ||
1175                (m_last_key.code != SCIM_KEY_space &&
1176                 m_last_key.code != SCIM_KEY_KP_Space))
1177     {
1178         str = " ";
1179         retval = true;
1180     }
1181 
1182     if (retval) {
1183         if (m_preedit.is_pseudo_ascii_mode ()) {
1184             m_preedit.append (m_last_key, str);
1185             show_preedit_string ();
1186             m_preedit_string_visible = true;
1187             set_preedition ();
1188         } else {
1189             commit_string (utf8_mbstowcs (str));
1190         }
1191     }
1192 
1193     return retval;
1194 }
1195 
1196 bool
action_insert_alternative_space(void)1197 AnthyInstance::action_insert_alternative_space (void)
1198 {
1199     bool is_wide = false;
1200 
1201     if (m_preedit.is_preediting ())
1202         return false;
1203 
1204     if (m_factory->m_space_type == "FollowMode") {
1205         InputMode mode = get_input_mode ();
1206         if (mode == SCIM_ANTHY_MODE_LATIN ||
1207             mode == SCIM_ANTHY_MODE_HALF_KATAKANA)
1208         {
1209             is_wide = true;
1210         } else {
1211             is_wide = false;
1212         }
1213     } else if (m_factory->m_space_type != "Wide") {
1214         is_wide = true;
1215     }
1216 
1217     if (is_wide) {
1218         commit_string (utf8_mbstowcs ("\xE3\x80\x80"));
1219         return true;
1220     } else if (get_typing_method () == SCIM_ANTHY_TYPING_METHOD_NICOLA || // FIXME! it's a ad-hoc solution.
1221                (m_last_key.code != SCIM_KEY_space &&
1222                 m_last_key.code != SCIM_KEY_KP_Space))
1223     {
1224         commit_string (utf8_mbstowcs (" "));
1225         return true;
1226     }
1227 
1228     return false;
1229 }
1230 
1231 bool
action_insert_half_space(void)1232 AnthyInstance::action_insert_half_space (void)
1233 {
1234     if (m_preedit.is_preediting ())
1235         return false;
1236 
1237     if (m_last_key.code != SCIM_KEY_space &&
1238         m_last_key.code != SCIM_KEY_KP_Space)
1239     {
1240         commit_string (utf8_mbstowcs (" "));
1241         return true;
1242     }
1243 
1244     return false;
1245 }
1246 
1247 bool
action_insert_wide_space(void)1248 AnthyInstance::action_insert_wide_space (void)
1249 {
1250     if (m_preedit.is_preediting ())
1251         return false;
1252 
1253     commit_string (utf8_mbstowcs ("\xE3\x80\x80"));
1254 
1255     return true;
1256 }
1257 
1258 bool
action_move_caret_backward(void)1259 AnthyInstance::action_move_caret_backward (void)
1260 {
1261     if (!m_preedit.is_preediting ())
1262         return false;
1263     if (m_preedit.is_converting ())
1264         return false;
1265 
1266     m_preedit.move_caret(-1);
1267     set_preedition ();
1268 
1269     return true;
1270 }
1271 
1272 bool
action_move_caret_forward(void)1273 AnthyInstance::action_move_caret_forward (void)
1274 {
1275     if (!m_preedit.is_preediting ())
1276         return false;
1277     if (m_preedit.is_converting ())
1278         return false;
1279 
1280     m_preedit.move_caret(1);
1281     set_preedition ();
1282 
1283     return true;
1284 }
1285 
1286 bool
action_move_caret_first(void)1287 AnthyInstance::action_move_caret_first (void)
1288 {
1289     if (!m_preedit.is_preediting ())
1290         return false;
1291     if (m_preedit.is_converting ())
1292         return false;
1293 
1294     m_preedit.set_caret_pos (0);
1295     set_preedition ();
1296 
1297     return true;
1298 }
1299 
1300 bool
action_move_caret_last(void)1301 AnthyInstance::action_move_caret_last (void)
1302 {
1303     if (!m_preedit.is_preediting ())
1304         return false;
1305     if (m_preedit.is_converting ())
1306         return false;
1307 
1308     m_preedit.set_caret_pos (m_preedit.get_length ());
1309     set_preedition ();
1310 
1311     return true;
1312 }
1313 
1314 bool
action_select_prev_segment(void)1315 AnthyInstance::action_select_prev_segment (void)
1316 {
1317     if (!m_preedit.is_converting ())
1318         return false;
1319 
1320     unset_lookup_table ();
1321 
1322     int idx = m_preedit.get_selected_segment ();
1323     if (idx - 1 < 0) {
1324         int n = m_preedit.get_nr_segments ();
1325         if (n <= 0) return false;
1326         m_preedit.select_segment (n - 1);
1327     } else {
1328         m_preedit.select_segment (idx - 1);
1329     }
1330     set_preedition ();
1331 
1332     return true;
1333 }
1334 
1335 bool
action_select_next_segment(void)1336 AnthyInstance::action_select_next_segment (void)
1337 {
1338     if (!m_preedit.is_converting ())
1339         return false;
1340 
1341     unset_lookup_table ();
1342 
1343     int idx = m_preedit.get_selected_segment ();
1344     if (idx < 0) {
1345         m_preedit.select_segment(0);
1346     } else {
1347         int n = m_preedit.get_nr_segments ();
1348         if (n <= 0)
1349             return false;
1350         if (idx + 1 >= n)
1351             m_preedit.select_segment(0);
1352         else
1353             m_preedit.select_segment(idx + 1);
1354     }
1355     set_preedition ();
1356 
1357     return true;
1358 }
1359 
1360 bool
action_select_first_segment(void)1361 AnthyInstance::action_select_first_segment (void)
1362 {
1363     if (!m_preedit.is_converting ())
1364         return false;
1365 
1366     unset_lookup_table ();
1367 
1368     m_preedit.select_segment(0);
1369     set_preedition ();
1370 
1371     return true;
1372 }
1373 
1374 bool
action_select_last_segment(void)1375 AnthyInstance::action_select_last_segment (void)
1376 {
1377     if (!m_preedit.is_converting ())
1378         return false;
1379 
1380     int n = m_preedit.get_nr_segments ();
1381     if (n <= 0) return false;
1382 
1383     unset_lookup_table ();
1384 
1385     m_preedit.select_segment(n - 1);
1386     set_preedition ();
1387 
1388     return true;
1389 }
1390 
1391 bool
action_shrink_segment(void)1392 AnthyInstance::action_shrink_segment (void)
1393 {
1394     if (!m_preedit.is_converting ())
1395         return false;
1396 
1397     unset_lookup_table ();
1398 
1399     m_preedit.resize_segment (-1);
1400     set_preedition ();
1401 
1402     return true;
1403 }
1404 
1405 bool
action_expand_segment(void)1406 AnthyInstance::action_expand_segment (void)
1407 {
1408     if (!m_preedit.is_converting ())
1409         return false;
1410 
1411     unset_lookup_table ();
1412 
1413     m_preedit.resize_segment (1);
1414     set_preedition ();
1415 
1416     return true;
1417 }
1418 
1419 bool
action_commit_first_segment(void)1420 AnthyInstance::action_commit_first_segment (void)
1421 {
1422     if (!m_preedit.is_converting ()) {
1423         if (m_preedit.is_preediting ()) {
1424             return action_commit (m_factory->m_learn_on_manual_commit);
1425         } else {
1426             return false;
1427         }
1428     }
1429 
1430     unset_lookup_table ();
1431 
1432     commit_string (m_preedit.get_segment_string (0));
1433     if (m_factory->m_learn_on_manual_commit)
1434         m_preedit.commit (0);
1435     else
1436         m_preedit.clear (0);
1437 
1438     set_preedition ();
1439 
1440     return true;
1441 }
1442 
1443 bool
action_commit_selected_segment(void)1444 AnthyInstance::action_commit_selected_segment (void)
1445 {
1446     if (!m_preedit.is_converting ()) {
1447         if (m_preedit.is_preediting ()) {
1448             return action_commit (m_factory->m_learn_on_manual_commit);
1449         } else {
1450             return false;
1451         }
1452     }
1453 
1454     unset_lookup_table ();
1455 
1456     for (int i = 0; i <= m_preedit.get_selected_segment (); i++)
1457         commit_string (m_preedit.get_segment_string (i));
1458     if (m_factory->m_learn_on_manual_commit)
1459         m_preedit.commit (m_preedit.get_selected_segment ());
1460     else
1461         m_preedit.clear (m_preedit.get_selected_segment ());
1462 
1463     set_preedition ();
1464 
1465     return true;
1466 }
1467 
1468 bool
action_commit_first_segment_reverse_preference(void)1469 AnthyInstance::action_commit_first_segment_reverse_preference (void)
1470 {
1471     if (!m_preedit.is_converting ()) {
1472         if (m_preedit.is_preediting ()) {
1473             return action_commit (!m_factory->m_learn_on_manual_commit);
1474         } else {
1475             return false;
1476         }
1477     }
1478 
1479     unset_lookup_table ();
1480 
1481     commit_string (m_preedit.get_segment_string (0));
1482     if (!m_factory->m_learn_on_manual_commit)
1483         m_preedit.commit (0);
1484     else
1485         m_preedit.clear (0);
1486 
1487     set_preedition ();
1488 
1489     return true;
1490 }
1491 
1492 bool
action_commit_selected_segment_reverse_preference(void)1493 AnthyInstance::action_commit_selected_segment_reverse_preference (void)
1494 {
1495     if (!m_preedit.is_converting ()) {
1496         if (m_preedit.is_preediting ()) {
1497             return action_commit (!m_factory->m_learn_on_manual_commit);
1498         } else {
1499             return false;
1500         }
1501     }
1502 
1503     unset_lookup_table ();
1504 
1505     for (int i = 0; i <= m_preedit.get_selected_segment (); i++)
1506         commit_string (m_preedit.get_segment_string (i));
1507     if (!m_factory->m_learn_on_manual_commit)
1508         m_preedit.commit (m_preedit.get_selected_segment ());
1509     else
1510         m_preedit.clear (m_preedit.get_selected_segment ());
1511 
1512     set_preedition ();
1513 
1514     return true;
1515 }
1516 
1517 bool
action_select_next_candidate(void)1518 AnthyInstance::action_select_next_candidate (void)
1519 {
1520     if (!m_preedit.is_converting ())
1521         return false;
1522 
1523     //if (!is_selecting_candidates ())
1524         set_lookup_table ();
1525 
1526     int end = m_lookup_table.number_of_candidates () - 1;
1527     if (m_lookup_table.get_cursor_pos () == end) {
1528         m_lookup_table.set_cursor_pos (0);
1529     } else {
1530         m_lookup_table.cursor_down ();
1531     }
1532 
1533     int pos_in_page = m_lookup_table.get_cursor_pos_in_current_page ();
1534     select_candidate_no_direct (pos_in_page);
1535 
1536     return true;
1537 }
1538 
1539 bool
action_select_prev_candidate(void)1540 AnthyInstance::action_select_prev_candidate (void)
1541 {
1542     if (!m_preedit.is_converting ()) return false;
1543 
1544     //if (!is_selecting_candidates ())
1545         set_lookup_table ();
1546 
1547     int end = m_lookup_table.number_of_candidates () - 1;
1548     if (m_lookup_table.get_cursor_pos () == 0)
1549         m_lookup_table.set_cursor_pos (end);
1550     else
1551         m_lookup_table.cursor_up ();
1552 
1553     int pos_in_page = m_lookup_table.get_cursor_pos_in_current_page ();
1554     select_candidate_no_direct (pos_in_page);
1555 
1556     return true;
1557 }
1558 
1559 bool
action_select_first_candidate(void)1560 AnthyInstance::action_select_first_candidate (void)
1561 {
1562     if (!m_preedit.is_converting ()) return false;
1563     if (!is_selecting_candidates ()) return false;
1564 
1565     m_lookup_table.set_cursor_pos (0);
1566 
1567     int pos_in_page = m_lookup_table.get_cursor_pos_in_current_page ();
1568     select_candidate_no_direct (pos_in_page);
1569 
1570     return true;
1571 }
1572 
1573 bool
action_select_last_candidate(void)1574 AnthyInstance::action_select_last_candidate (void)
1575 {
1576     if (!m_preedit.is_converting ()) return false;
1577     if (!is_selecting_candidates ()) return false;
1578 
1579     int end = m_lookup_table.number_of_candidates () - 1;
1580     m_lookup_table.set_cursor_pos (end);
1581 
1582     int pos_in_page = m_lookup_table.get_cursor_pos_in_current_page ();
1583     select_candidate_no_direct (pos_in_page);
1584 
1585     return true;
1586 }
1587 
1588 bool
action_candidates_page_up(void)1589 AnthyInstance::action_candidates_page_up(void)
1590 {
1591     if (!m_preedit.is_converting ()) return false;
1592     if (!is_selecting_candidates ()) return false;
1593     if (!m_lookup_table_visible) return false;
1594 
1595     m_lookup_table.page_up ();
1596 
1597     int pos_in_page = m_lookup_table.get_cursor_pos_in_current_page ();
1598     select_candidate_no_direct (pos_in_page);
1599 
1600     return true;
1601 }
1602 
1603 bool
action_candidates_page_down(void)1604 AnthyInstance::action_candidates_page_down (void)
1605 {
1606     if (!m_preedit.is_converting ()) return false;
1607     if (!is_selecting_candidates ()) return false;
1608     if (!m_lookup_table_visible) return false;
1609 
1610     m_lookup_table.page_down ();
1611 
1612     int pos_in_page = m_lookup_table.get_cursor_pos_in_current_page ();
1613     select_candidate_no_direct (pos_in_page);
1614 
1615     return true;
1616 }
1617 
1618 bool
action_select_candidate(unsigned int i)1619 AnthyInstance::action_select_candidate (unsigned int i)
1620 {
1621     // FIXME! m_lookup_table_visible should be set as true also on predicting
1622     if (!m_lookup_table_visible && !m_preedit.is_predicting ())
1623         return false;
1624 
1625     if (m_preedit.is_predicting () && !m_preedit.is_converting () &&
1626         m_factory->m_use_direct_key_on_predict)
1627     {
1628         CommonLookupTable table;
1629         m_preedit.get_candidates (table);
1630         if (i < table.number_of_candidates ()) {
1631             select_candidate (i);
1632             return true;
1633         }
1634     } else if (m_preedit.is_converting () && is_selecting_candidates ()) {
1635         select_candidate (i);
1636         return true;
1637     }
1638 
1639     return false;
1640 }
1641 
1642 bool
action_select_candidate_1(void)1643 AnthyInstance::action_select_candidate_1 (void)
1644 {
1645     return action_select_candidate (0);
1646 }
1647 
1648 bool
action_select_candidate_2(void)1649 AnthyInstance::action_select_candidate_2 (void)
1650 {
1651     return action_select_candidate (1);
1652 }
1653 
1654 bool
action_select_candidate_3(void)1655 AnthyInstance::action_select_candidate_3 (void)
1656 {
1657     return action_select_candidate (2);
1658 }
1659 
1660 bool
action_select_candidate_4(void)1661 AnthyInstance::action_select_candidate_4 (void)
1662 {
1663     return action_select_candidate (3);
1664 }
1665 
1666 bool
action_select_candidate_5(void)1667 AnthyInstance::action_select_candidate_5 (void)
1668 {
1669     return action_select_candidate (4);
1670 }
1671 
1672 bool
action_select_candidate_6(void)1673 AnthyInstance::action_select_candidate_6 (void)
1674 {
1675     return action_select_candidate (5);
1676 }
1677 
1678 bool
action_select_candidate_7(void)1679 AnthyInstance::action_select_candidate_7 (void)
1680 {
1681     return action_select_candidate (6);
1682 }
1683 
1684 
1685 bool
action_select_candidate_8(void)1686 AnthyInstance::action_select_candidate_8 (void)
1687 {
1688     return action_select_candidate (7);
1689 }
1690 
1691 bool
action_select_candidate_9(void)1692 AnthyInstance::action_select_candidate_9 (void)
1693 {
1694     return action_select_candidate (8);
1695 }
1696 
1697 bool
action_select_candidate_10(void)1698 AnthyInstance::action_select_candidate_10 (void)
1699 {
1700     return action_select_candidate (9);
1701 }
1702 
1703 bool
action_circle_input_mode(void)1704 AnthyInstance::action_circle_input_mode (void)
1705 {
1706     InputMode mode = get_input_mode ();
1707 
1708     switch (mode) {
1709     case SCIM_ANTHY_MODE_HIRAGANA:
1710         mode = SCIM_ANTHY_MODE_KATAKANA;
1711         break;
1712     case SCIM_ANTHY_MODE_KATAKANA:
1713         mode = SCIM_ANTHY_MODE_HALF_KATAKANA;
1714         break;
1715     case SCIM_ANTHY_MODE_HALF_KATAKANA:
1716         mode = SCIM_ANTHY_MODE_LATIN;
1717         break;
1718     case SCIM_ANTHY_MODE_LATIN:
1719         mode = SCIM_ANTHY_MODE_WIDE_LATIN;
1720         break;
1721     case SCIM_ANTHY_MODE_WIDE_LATIN:
1722         mode = SCIM_ANTHY_MODE_HIRAGANA;
1723         break;
1724     default:
1725         mode = SCIM_ANTHY_MODE_HIRAGANA;
1726         break;
1727     }
1728 
1729     set_input_mode (mode);
1730 
1731     return true;
1732 }
1733 
1734 bool
action_circle_typing_method(void)1735 AnthyInstance::action_circle_typing_method (void)
1736 {
1737     TypingMethod method;
1738 
1739     method = get_typing_method ();
1740     if (method == SCIM_ANTHY_TYPING_METHOD_NICOLA)
1741         method = SCIM_ANTHY_TYPING_METHOD_ROMAJI;
1742     else if (method == SCIM_ANTHY_TYPING_METHOD_KANA)
1743         method = SCIM_ANTHY_TYPING_METHOD_NICOLA;
1744     else
1745         method = SCIM_ANTHY_TYPING_METHOD_KANA;
1746 
1747     set_typing_method (method);
1748 
1749     return true;
1750 }
1751 
1752 bool
action_circle_kana_mode(void)1753 AnthyInstance::action_circle_kana_mode (void)
1754 {
1755     InputMode mode;
1756 
1757     if (get_input_mode () == SCIM_ANTHY_MODE_LATIN ||
1758         get_input_mode () == SCIM_ANTHY_MODE_WIDE_LATIN)
1759     {
1760         mode = SCIM_ANTHY_MODE_HIRAGANA;
1761     } else {
1762         switch (get_input_mode ()) {
1763         case SCIM_ANTHY_MODE_HIRAGANA:
1764             mode = SCIM_ANTHY_MODE_KATAKANA;
1765             break;
1766         case SCIM_ANTHY_MODE_KATAKANA:
1767             mode = SCIM_ANTHY_MODE_HALF_KATAKANA;
1768             break;
1769         case SCIM_ANTHY_MODE_HALF_KATAKANA:
1770         default:
1771             mode = SCIM_ANTHY_MODE_HIRAGANA;
1772             break;
1773         }
1774     }
1775 
1776     set_input_mode (mode);
1777 
1778     return true;
1779 }
1780 
1781 bool
action_on_off(void)1782 AnthyInstance::action_on_off (void)
1783 {
1784     if (get_input_mode () == SCIM_ANTHY_MODE_LATIN ||
1785         get_input_mode () == SCIM_ANTHY_MODE_WIDE_LATIN)
1786     {
1787         set_input_mode (m_prev_input_mode);
1788         m_preedit.set_input_mode (m_prev_input_mode);
1789     } else {
1790         m_prev_input_mode = get_input_mode ();
1791         set_input_mode (SCIM_ANTHY_MODE_LATIN);
1792         m_preedit.set_input_mode (SCIM_ANTHY_MODE_LATIN);
1793     }
1794 
1795     return true;
1796 }
1797 
1798 bool
action_latin_mode(void)1799 AnthyInstance::action_latin_mode (void)
1800 {
1801     set_input_mode (SCIM_ANTHY_MODE_LATIN);
1802     return true;
1803 }
1804 
1805 bool
action_wide_latin_mode(void)1806 AnthyInstance::action_wide_latin_mode (void)
1807 {
1808     set_input_mode (SCIM_ANTHY_MODE_WIDE_LATIN);
1809     return true;
1810 }
1811 
1812 bool
action_hiragana_mode(void)1813 AnthyInstance::action_hiragana_mode (void)
1814 {
1815     set_input_mode (SCIM_ANTHY_MODE_HIRAGANA);
1816     return true;
1817 }
1818 
1819 bool
action_katakana_mode(void)1820 AnthyInstance::action_katakana_mode (void)
1821 {
1822     set_input_mode (SCIM_ANTHY_MODE_KATAKANA);
1823     return true;
1824 }
1825 
1826 bool
action_half_katakana_mode(void)1827 AnthyInstance::action_half_katakana_mode (void)
1828 {
1829     set_input_mode (SCIM_ANTHY_MODE_HALF_KATAKANA);
1830     return true;
1831 }
1832 
1833 bool
action_cancel_pseudo_ascii_mode(void)1834 AnthyInstance::action_cancel_pseudo_ascii_mode (void)
1835 {
1836     if (!m_preedit.is_preediting ())
1837         return false;
1838     if (!m_preedit.is_pseudo_ascii_mode ())
1839         return false;
1840 
1841     m_preedit.reset_pseudo_ascii_mode ();
1842 
1843     return true;
1844 }
1845 
1846 bool
convert_kana(CandidateType type)1847 AnthyInstance::convert_kana (CandidateType type)
1848 {
1849     if (!m_preedit.is_preediting ())
1850         return false;
1851 
1852     if (m_preedit.is_reconverting ())
1853         return false;
1854 
1855     unset_lookup_table ();
1856 
1857     if (m_preedit.is_converting ()) {
1858         int idx = m_preedit.get_selected_segment ();
1859         if (idx < 0) {
1860             action_revert ();
1861             m_preedit.finish ();
1862             m_preedit.convert (type, true);
1863         } else {
1864             m_preedit.select_candidate (type);
1865         }
1866     } else {
1867         m_preedit.finish ();
1868         m_preedit.convert (type, true);
1869     }
1870 
1871     set_preedition ();
1872 
1873     return true;
1874 }
1875 
1876 bool
action_convert_to_hiragana(void)1877 AnthyInstance::action_convert_to_hiragana (void)
1878 {
1879     return convert_kana (SCIM_ANTHY_CANDIDATE_HIRAGANA);
1880 }
1881 
1882 bool
action_convert_to_katakana(void)1883 AnthyInstance::action_convert_to_katakana (void)
1884 {
1885     return convert_kana (SCIM_ANTHY_CANDIDATE_KATAKANA);
1886 }
1887 
1888 bool
action_convert_to_half(void)1889 AnthyInstance::action_convert_to_half (void)
1890 {
1891     return convert_kana (SCIM_ANTHY_CANDIDATE_HALF);
1892 }
1893 
1894 bool
action_convert_to_half_katakana(void)1895 AnthyInstance::action_convert_to_half_katakana (void)
1896 {
1897     return convert_kana (SCIM_ANTHY_CANDIDATE_HALF_KATAKANA);
1898 }
1899 
1900 bool
action_convert_to_latin(void)1901 AnthyInstance::action_convert_to_latin (void)
1902 {
1903     return convert_kana (SCIM_ANTHY_CANDIDATE_LATIN);
1904 }
1905 
1906 bool
action_convert_to_wide_latin(void)1907 AnthyInstance::action_convert_to_wide_latin (void)
1908 {
1909     return convert_kana (SCIM_ANTHY_CANDIDATE_WIDE_LATIN);
1910 }
1911 
1912 bool
action_convert_char_type_forward(void)1913 AnthyInstance::action_convert_char_type_forward (void)
1914 {
1915     if (!m_preedit.is_preediting ())
1916         return false;
1917 
1918     unset_lookup_table ();
1919 
1920     if (m_preedit.is_converting ()) {
1921         int idx = m_preedit.get_selected_segment ();
1922         if (idx < 0) {
1923             action_revert ();
1924             m_preedit.finish ();
1925             m_preedit.convert (SCIM_ANTHY_CANDIDATE_HIRAGANA, true);
1926         } else {
1927             int cand = m_preedit.get_selected_candidate ();
1928             switch (cand)
1929             {
1930             case SCIM_ANTHY_CANDIDATE_HIRAGANA:
1931                 m_preedit.select_candidate (SCIM_ANTHY_CANDIDATE_KATAKANA);
1932                 break;
1933             case SCIM_ANTHY_CANDIDATE_KATAKANA:
1934                 m_preedit.select_candidate (SCIM_ANTHY_CANDIDATE_HALF_KATAKANA);
1935                 break;
1936             case SCIM_ANTHY_CANDIDATE_HALF_KATAKANA:
1937                 m_preedit.select_candidate (SCIM_ANTHY_CANDIDATE_WIDE_LATIN);
1938                 break;
1939             case SCIM_ANTHY_CANDIDATE_WIDE_LATIN:
1940                 m_preedit.select_candidate (SCIM_ANTHY_CANDIDATE_LATIN);
1941                 break;
1942             case SCIM_ANTHY_CANDIDATE_LATIN:
1943                 m_preedit.select_candidate (SCIM_ANTHY_CANDIDATE_HIRAGANA);
1944                 break;
1945             default:
1946                 m_preedit.select_candidate (SCIM_ANTHY_CANDIDATE_HIRAGANA);
1947                 break;
1948             }
1949         }
1950     } else {
1951         m_preedit.finish ();
1952         m_preedit.convert (SCIM_ANTHY_CANDIDATE_HIRAGANA, true);
1953     }
1954 
1955     set_preedition ();
1956 
1957     return true;
1958 }
1959 
1960 bool
action_convert_char_type_backward(void)1961 AnthyInstance::action_convert_char_type_backward (void)
1962 {
1963     if (!m_preedit.is_preediting ())
1964         return false;
1965 
1966     unset_lookup_table ();
1967 
1968     if (m_preedit.is_converting ()) {
1969         int idx = m_preedit.get_selected_segment ();
1970         if (idx < 0) {
1971             action_revert ();
1972             m_preedit.finish ();
1973             m_preedit.convert (SCIM_ANTHY_CANDIDATE_HIRAGANA, true);
1974         } else {
1975             int cand = m_preedit.get_selected_candidate ();
1976             switch (cand)
1977             {
1978             case SCIM_ANTHY_CANDIDATE_HIRAGANA:
1979                 m_preedit.select_candidate (SCIM_ANTHY_CANDIDATE_LATIN);
1980                 break;
1981             case SCIM_ANTHY_CANDIDATE_KATAKANA:
1982                 m_preedit.select_candidate (SCIM_ANTHY_CANDIDATE_HIRAGANA);
1983                 break;
1984             case SCIM_ANTHY_CANDIDATE_HALF_KATAKANA:
1985                 m_preedit.select_candidate (SCIM_ANTHY_CANDIDATE_KATAKANA);
1986                 break;
1987             case SCIM_ANTHY_CANDIDATE_WIDE_LATIN:
1988                 m_preedit.select_candidate (SCIM_ANTHY_CANDIDATE_HALF_KATAKANA);
1989                 break;
1990             case SCIM_ANTHY_CANDIDATE_LATIN:
1991                 m_preedit.select_candidate (SCIM_ANTHY_CANDIDATE_WIDE_LATIN);
1992                 break;
1993             default:
1994                 m_preedit.select_candidate (SCIM_ANTHY_CANDIDATE_HIRAGANA);
1995                 break;
1996             }
1997         }
1998     } else {
1999         m_preedit.finish ();
2000         m_preedit.convert (SCIM_ANTHY_CANDIDATE_HIRAGANA, true);
2001     }
2002 
2003     set_preedition ();
2004 
2005     return true;
2006 }
2007 
2008 bool
action_reconvert(void)2009 AnthyInstance::action_reconvert (void)
2010 {
2011     if (m_preedit.is_preediting ())
2012         return false;
2013 
2014     Transaction send;
2015     send.put_command (SCIM_ANTHY_TRANS_CMD_GET_SELECTION);
2016     send_helper_event (String (SCIM_ANTHY_HELPER_UUID), send);
2017 
2018     return true;
2019 }
2020 
2021 bool
action_add_word(void)2022 AnthyInstance::action_add_word (void)
2023 {
2024     util_launch_program (m_factory->m_add_word_command.c_str ());
2025 
2026     return true;
2027 }
2028 
2029 bool
action_launch_dict_admin_tool(void)2030 AnthyInstance::action_launch_dict_admin_tool (void)
2031 {
2032     util_launch_program (m_factory->m_dict_admin_command.c_str ());
2033 
2034     return true;
2035 }
2036 
2037 #if 0
2038 void
2039 AnthyInstance::action_regist_word (void)
2040 {
2041 }
2042 #endif
2043 
2044 AnthyFactory *
get_factory(void)2045 AnthyInstance::get_factory (void)
2046 {
2047     return m_factory;
2048 }
2049 
2050 TypingMethod
get_typing_method(void)2051 AnthyInstance::get_typing_method (void)
2052 {
2053     return m_preedit.get_typing_method ();
2054 }
2055 
2056 InputMode
get_input_mode(void)2057 AnthyInstance::get_input_mode (void)
2058 {
2059     return m_preedit.get_input_mode ();
2060 }
2061 
2062 int
timeout_add(uint32 time_msec,timeout_func timeout_fn,void * data,delete_func delete_fn)2063 AnthyInstance::timeout_add (uint32 time_msec, timeout_func timeout_fn,
2064                             void *data, delete_func delete_fn)
2065 {
2066     uint32 id = ++m_timeout_id_seq;
2067     m_closures[id] = TimeoutClosure (time_msec, timeout_fn, data, delete_fn);
2068     /*
2069      * FIXME! Obsoleted closures should be removed at somewhere.
2070      * Currenly only NICOLA related timer uses this feature and it will be
2071      * removed each time on key press event so memory leaks doesn't exist.
2072      */
2073 
2074     Transaction send;
2075     send.put_command (SCIM_ANTHY_TRANS_CMD_TIMEOUT_ADD);
2076     send.put_data (id);
2077     send.put_data (time_msec);
2078     send_helper_event (String (SCIM_ANTHY_HELPER_UUID), send);
2079 
2080     return id;
2081 }
2082 
2083 void
timeout_remove(uint32 id)2084 AnthyInstance::timeout_remove (uint32 id)
2085 {
2086     if (m_closures.find (id) == m_closures.end ())
2087         return;
2088 
2089     m_closures.erase (id);
2090 
2091     Transaction send;
2092     send.put_command (SCIM_ANTHY_TRANS_CMD_TIMEOUT_REMOVE);
2093     send.put_data (id);
2094     send_helper_event (String (SCIM_ANTHY_HELPER_UUID), send);
2095 }
2096 
2097 void
trigger_property(const String & property)2098 AnthyInstance::trigger_property (const String &property)
2099 {
2100     String anthy_prop = property.substr (property.find_last_of ('/') + 1);
2101 
2102     SCIM_DEBUG_IMENGINE(2)
2103         << "trigger_property : " << property << " - " << anthy_prop << "\n";
2104 
2105     // input mode
2106     if (property == SCIM_PROP_INPUT_MODE_HIRAGANA) {
2107         set_input_mode (SCIM_ANTHY_MODE_HIRAGANA);
2108     } else if (property == SCIM_PROP_INPUT_MODE_KATAKANA) {
2109         set_input_mode (SCIM_ANTHY_MODE_KATAKANA);
2110     } else if (property == SCIM_PROP_INPUT_MODE_HALF_KATAKANA) {
2111         set_input_mode (SCIM_ANTHY_MODE_HALF_KATAKANA);
2112     } else if (property == SCIM_PROP_INPUT_MODE_LATIN) {
2113         set_input_mode (SCIM_ANTHY_MODE_LATIN);
2114     } else if (property == SCIM_PROP_INPUT_MODE_WIDE_LATIN) {
2115         set_input_mode (SCIM_ANTHY_MODE_WIDE_LATIN);
2116 
2117     // conversion mode
2118     } else if (property == SCIM_PROP_CONV_MODE_MULTI_SEG) {
2119         set_conversion_mode (SCIM_ANTHY_CONVERSION_MULTI_SEGMENT);
2120     } else if (property == SCIM_PROP_CONV_MODE_SINGLE_SEG) {
2121         set_conversion_mode (SCIM_ANTHY_CONVERSION_SINGLE_SEGMENT);
2122     } else if (property == SCIM_PROP_CONV_MODE_MULTI_REAL_TIME) {
2123         set_conversion_mode (SCIM_ANTHY_CONVERSION_MULTI_SEGMENT_IMMEDIATE);
2124     } else if (property == SCIM_PROP_CONV_MODE_SINGLE_REAL_TIME) {
2125         set_conversion_mode (SCIM_ANTHY_CONVERSION_SINGLE_SEGMENT_IMMEDIATE);
2126 
2127     // typing method
2128     } else if (property == SCIM_PROP_TYPING_METHOD_ROMAJI) {
2129         set_typing_method (SCIM_ANTHY_TYPING_METHOD_ROMAJI);
2130     } else if (property == SCIM_PROP_TYPING_METHOD_KANA) {
2131         set_typing_method (SCIM_ANTHY_TYPING_METHOD_KANA);
2132     } else if (property == SCIM_PROP_TYPING_METHOD_NICOLA) {
2133         set_typing_method (SCIM_ANTHY_TYPING_METHOD_NICOLA);
2134 
2135     // period type
2136     } else if (property == SCIM_PROP_PERIOD_STYLE_JAPANESE) {
2137         set_period_style (SCIM_ANTHY_PERIOD_JAPANESE,
2138                           SCIM_ANTHY_COMMA_JAPANESE);
2139     } else if (property == SCIM_PROP_PERIOD_STYLE_WIDE_LATIN_JAPANESE) {
2140         set_period_style (SCIM_ANTHY_PERIOD_JAPANESE,
2141                           SCIM_ANTHY_COMMA_WIDE);
2142     } else if (property == SCIM_PROP_PERIOD_STYLE_WIDE_LATIN) {
2143         set_period_style (SCIM_ANTHY_PERIOD_WIDE,
2144                           SCIM_ANTHY_COMMA_WIDE);
2145     } else if (property == SCIM_PROP_PERIOD_STYLE_LATIN) {
2146         set_period_style (SCIM_ANTHY_PERIOD_HALF,
2147                           SCIM_ANTHY_COMMA_HALF);
2148 
2149     // symbol type
2150     } else if (property == SCIM_PROP_SYMBOL_STYLE_JAPANESE) {
2151         set_symbol_style (SCIM_ANTHY_BRACKET_JAPANESE,
2152                           SCIM_ANTHY_SLASH_JAPANESE);
2153     } else if (property == SCIM_PROP_SYMBOL_STYLE_CORNER_BRACKET_SLASH) {
2154         set_symbol_style (SCIM_ANTHY_BRACKET_JAPANESE,
2155                           SCIM_ANTHY_SLASH_WIDE);
2156     } else if (property == SCIM_PROP_SYMBOL_STYLE_BRACKET_MIDDLE_DOT) {
2157         set_symbol_style (SCIM_ANTHY_BRACKET_WIDE,
2158                           SCIM_ANTHY_SLASH_JAPANESE);
2159     } else if (property == SCIM_PROP_SYMBOL_STYLE_BRACKET_SLASH) {
2160         set_symbol_style (SCIM_ANTHY_BRACKET_WIDE,
2161                           SCIM_ANTHY_SLASH_WIDE);
2162 
2163     // dictionary
2164     } else if (property == SCIM_PROP_DICT_ADD_WORD) {
2165         action_add_word ();
2166     } else if (property == SCIM_PROP_DICT_LAUNCH_ADMIN_TOOL) {
2167         action_launch_dict_admin_tool ();
2168     }
2169 }
2170 
2171 void
process_helper_event(const String & helper_uuid,const Transaction & recv)2172 AnthyInstance::process_helper_event (const String &helper_uuid,
2173                                      const Transaction &recv)
2174 {
2175     TransactionReader reader (recv);
2176     int cmd;
2177 
2178     if (helper_uuid != SCIM_ANTHY_HELPER_UUID)
2179         return;
2180 
2181     if (!reader.get_command (cmd))
2182         return;
2183 
2184     switch (cmd) {
2185     case SCIM_ANTHY_TRANS_CMD_GET_SELECTION:
2186     {
2187         // For reconversion feature, but this code is ad-hoc solution.
2188 
2189         WideString selection, surround;
2190         if (!reader.get_data (selection) || selection.empty ())
2191             break;
2192 
2193         int cursor;
2194         unsigned int len = selection.length ();
2195         if (!get_surrounding_text (surround, cursor, len, len))
2196         {
2197             // We expect application to delete selection text.
2198             m_preedit.convert(selection);
2199             set_preedition();
2200             set_lookup_table();
2201         }
2202         else
2203         {
2204             // This code will conflict if same string exists at both before and
2205             // after the caret.
2206             if (surround.length () - cursor >= len &&
2207                 surround.substr (cursor, len) == selection)
2208             {
2209                 delete_surrounding_text (0, len);
2210                 m_preedit.convert (selection);
2211                 set_preedition ();
2212                 set_lookup_table ();
2213             } else if (cursor >= (int) len &&
2214                        surround.substr (cursor - len, len) == selection)
2215             {
2216                 delete_surrounding_text (0 - len, len);
2217                 m_preedit.convert (selection);
2218                 set_preedition ();
2219                 set_lookup_table ();
2220             }
2221         }
2222         break;
2223     }
2224     case SCIM_ANTHY_TRANS_CMD_TIMEOUT_NOTIFY:
2225     {
2226         uint32 id;
2227         if (reader.get_data (id) &&
2228             m_closures.find (id) != m_closures.end ())
2229         {
2230             m_closures[id].close ();
2231             m_closures.erase (id);
2232         }
2233         break;
2234     }
2235     default:
2236         break;
2237     }
2238 }
2239 
2240 void
reload_config(const ConfigPointer & config)2241 AnthyInstance::reload_config (const ConfigPointer &config)
2242 {
2243     // set romaji settings
2244     m_preedit.set_symbol_width (m_factory->m_romaji_half_symbol);
2245     m_preedit.set_number_width (m_factory->m_romaji_half_number);
2246 
2247     // set input mode
2248     if (m_on_init || !m_factory->m_show_input_mode_label) {
2249         if (m_factory->m_input_mode == "Hiragana")
2250             m_preedit.set_input_mode (SCIM_ANTHY_MODE_HIRAGANA);
2251         else if (m_factory->m_input_mode == "Katakana")
2252             m_preedit.set_input_mode (SCIM_ANTHY_MODE_KATAKANA);
2253         else if (m_factory->m_input_mode == "HalfKatakana")
2254             m_preedit.set_input_mode (SCIM_ANTHY_MODE_HALF_KATAKANA);
2255         else if (m_factory->m_input_mode == "Latin")
2256             m_preedit.set_input_mode (SCIM_ANTHY_MODE_LATIN);
2257         else if (m_factory->m_input_mode == "WideLatin")
2258             m_preedit.set_input_mode (SCIM_ANTHY_MODE_WIDE_LATIN);
2259     }
2260 
2261     // set typing method and pseudo ASCII mode
2262     if (m_on_init || !m_factory->m_show_typing_method_label) {
2263         if (m_factory->m_typing_method == "NICOLA") {
2264             m_preedit.set_typing_method (SCIM_ANTHY_TYPING_METHOD_NICOLA);
2265         } else if (m_factory->m_typing_method == "Kana") {
2266             m_preedit.set_typing_method (SCIM_ANTHY_TYPING_METHOD_KANA);
2267         } else {
2268             m_preedit.set_typing_method (SCIM_ANTHY_TYPING_METHOD_ROMAJI);
2269         }
2270         m_preedit.set_pseudo_ascii_mode (get_pseudo_ascii_mode ());
2271     } else {
2272         m_preedit.set_typing_method (get_typing_method ());
2273         m_preedit.set_pseudo_ascii_mode (get_pseudo_ascii_mode ());
2274     }
2275 
2276     // set conversion mode
2277     if (m_on_init || !m_factory->m_show_conv_mode_label) {
2278         if (m_factory->m_conversion_mode == "MultiSeg")
2279             m_conv_mode = SCIM_ANTHY_CONVERSION_MULTI_SEGMENT;
2280         else if (m_factory->m_conversion_mode == "SingleSeg")
2281             m_conv_mode = SCIM_ANTHY_CONVERSION_SINGLE_SEGMENT;
2282         else if (m_factory->m_conversion_mode == "CAYT_MultiSeg")
2283             m_conv_mode = SCIM_ANTHY_CONVERSION_MULTI_SEGMENT_IMMEDIATE;
2284         else if (m_factory->m_conversion_mode == "CAYT_SingleSeg")
2285             m_conv_mode = SCIM_ANTHY_CONVERSION_SINGLE_SEGMENT_IMMEDIATE;
2286     }
2287 
2288     // set period style
2289     if (m_on_init || !m_factory->m_show_period_style_label) {
2290         if (m_factory->m_period_style == "WideLatin") {
2291             m_preedit.set_comma_style  (SCIM_ANTHY_COMMA_WIDE);
2292             m_preedit.set_period_style (SCIM_ANTHY_PERIOD_WIDE);
2293         } else if (m_factory->m_period_style == "Latin") {
2294             m_preedit.set_comma_style  (SCIM_ANTHY_COMMA_HALF);
2295             m_preedit.set_period_style (SCIM_ANTHY_PERIOD_HALF);
2296         } else if (m_factory->m_period_style == "Japanese") {
2297             m_preedit.set_comma_style  (SCIM_ANTHY_COMMA_JAPANESE);
2298             m_preedit.set_period_style (SCIM_ANTHY_PERIOD_JAPANESE);
2299         } else if (m_factory->m_period_style == "WideLatin_Japanese") {
2300             m_preedit.set_comma_style  (SCIM_ANTHY_COMMA_WIDE);
2301             m_preedit.set_period_style (SCIM_ANTHY_PERIOD_JAPANESE);
2302         } else {
2303             m_preedit.set_comma_style  (SCIM_ANTHY_COMMA_JAPANESE);
2304             m_preedit.set_period_style (SCIM_ANTHY_PERIOD_JAPANESE);
2305         }
2306     }
2307 
2308     // set symbol style
2309     if (m_on_init || !m_factory->m_show_symbol_style_label) {
2310         if (m_factory->m_symbol_style == "Japanese") {
2311             m_preedit.set_bracket_style (SCIM_ANTHY_BRACKET_JAPANESE);
2312             m_preedit.set_slash_style   (SCIM_ANTHY_SLASH_JAPANESE);
2313         } else if (m_factory->m_symbol_style == "WideBracket_WideSlash") {
2314             m_preedit.set_bracket_style (SCIM_ANTHY_BRACKET_WIDE);
2315             m_preedit.set_slash_style   (SCIM_ANTHY_SLASH_WIDE);
2316         } else if (m_factory->m_symbol_style == "CornerBracket_WideSlash") {
2317             m_preedit.set_bracket_style (SCIM_ANTHY_BRACKET_JAPANESE);
2318             m_preedit.set_slash_style   (SCIM_ANTHY_SLASH_WIDE);
2319         } else if (m_factory->m_symbol_style == "WideBracket_MiddleDot") {
2320             m_preedit.set_bracket_style (SCIM_ANTHY_BRACKET_WIDE);
2321             m_preedit.set_slash_style   (SCIM_ANTHY_SLASH_JAPANESE);
2322         } else {
2323             m_preedit.set_bracket_style (SCIM_ANTHY_BRACKET_JAPANESE);
2324             m_preedit.set_slash_style   (SCIM_ANTHY_SLASH_JAPANESE);
2325         }
2326     }
2327 
2328     // set lookup table
2329     if (m_factory->m_cand_win_page_size > 0)
2330         m_lookup_table.set_page_size (m_factory->m_cand_win_page_size);
2331     else
2332         m_lookup_table.set_page_size (SCIM_ANTHY_CONFIG_CAND_WIN_PAGE_SIZE_DEFAULT);
2333 
2334     // setup toolbar
2335     m_properties.clear ();
2336     install_properties ();
2337 
2338     // set encoding
2339     m_preedit.set_dict_encoding (m_factory->m_dict_encoding);
2340 }
2341 
2342 bool
is_single_segment(void)2343 AnthyInstance::is_single_segment (void)
2344 {
2345     if (m_conv_mode == SCIM_ANTHY_CONVERSION_SINGLE_SEGMENT ||
2346         m_conv_mode == SCIM_ANTHY_CONVERSION_SINGLE_SEGMENT_IMMEDIATE)
2347         return true;
2348     else
2349         return false;
2350 }
2351 
2352 bool
is_realtime_conversion(void)2353 AnthyInstance::is_realtime_conversion (void)
2354 {
2355     if (m_conv_mode == SCIM_ANTHY_CONVERSION_MULTI_SEGMENT_IMMEDIATE ||
2356         m_conv_mode == SCIM_ANTHY_CONVERSION_SINGLE_SEGMENT_IMMEDIATE)
2357         return true;
2358     else
2359         return false;
2360 }
2361 
2362 int
get_pseudo_ascii_mode(void)2363 AnthyInstance::get_pseudo_ascii_mode (void)
2364 {
2365     int retval = 0;
2366     TypingMethod m = get_typing_method ();
2367 
2368     if (m == SCIM_ANTHY_TYPING_METHOD_ROMAJI) {
2369         if (m_factory->m_romaji_pseudo_ascii_mode)
2370             retval |= SCIM_ANTHY_PSEUDO_ASCII_TRIGGERED_CAPITALIZED;
2371     }
2372 
2373     return retval;
2374 }
2375 
2376 /*
2377 vi:ts=4:nowrap:ai:expandtab
2378 */
2379