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