Tizen 2.1 base
[framework/uifw/ise-engine-anthy.git] / src / scim_anthy_reading.cpp
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  *  Copyright (C) 2005 Takuro Ashie
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #include "scim_anthy_reading.h"
21 #include "scim_anthy_factory.h"
22 #include "scim_anthy_imengine.h"
23 #include "scim_anthy_utils.h"
24
25 using namespace scim_anthy;
26
27 ReadingSegment::ReadingSegment ()
28 {
29 }
30
31 ReadingSegment::~ReadingSegment ()
32 {
33 }
34
35 static const char *
36 find_romaji (WideString c)
37 {
38     ConvRule *table = scim_anthy_romaji_typing_rule;
39
40     for (unsigned int i = 0; table[i].string; i++) {
41         WideString kana = utf8_mbstowcs (table[i].result);
42         if (c == kana)
43             return table[i].string;
44     }
45
46     return "";
47 }
48
49 static void
50 to_half (String &dest, WideString &src)
51 {
52     WideRule *table = scim_anthy_wide_table;
53     
54     for (unsigned int i = 0; i < src.size (); i++) {
55         bool found = false;
56         WideString kana1 = src.substr (i, 1);
57         for (unsigned int i = 0; table[i].code; i++) {
58             WideString kana2 = utf8_mbstowcs (table[i].wide);
59             if (kana1 == kana2) {
60                 dest += table[i].code;
61                 found = true;
62                 break;
63             }
64         }
65         if (!found)
66             dest += utf8_wcstombs (kana1);
67     }
68 }
69
70 // Only a romaji string can be splited with raw key string.
71 // Other typing method aren't supported splitting raw key string.
72 void
73 ReadingSegment::split (ReadingSegments &segments)
74 {
75     if (kana.length () <= 1)
76         segments.push_back (*this);
77
78     String half;
79     to_half (half, kana);
80     bool same_with_raw = half == raw;
81
82     WideString::iterator it;
83     for (unsigned int i = 0; i < kana.size (); i++) {
84         WideString c = kana.substr (i, 1);
85         ReadingSegment seg;
86         seg.kana = c;
87         if (same_with_raw)
88             to_half (seg.raw, c);
89         else
90             seg.raw = find_romaji (c);
91         segments.push_back (seg);
92     }
93 }
94
95
96
97 Reading::Reading (AnthyInstance &anthy)
98     : m_anthy           (anthy),
99       //m_key2kana_tables (tables),
100       m_key2kana_normal (anthy, m_key2kana_tables),
101       m_kana            (anthy),
102       m_nicola          (anthy, m_nicola_tables),
103       m_key2kana        (&m_key2kana_normal),
104       m_segment_pos     (0),
105       m_caret_offset    (0)
106 {
107     m_nicola_tables.set_typing_method (SCIM_ANTHY_TYPING_METHOD_NICOLA);
108 }
109
110 Reading::~Reading ()
111 {
112 }
113
114 bool
115 Reading::can_process_key_event (const KeyEvent & key)
116 {
117     if (m_kana.can_append (key))
118         return true;
119
120     return m_key2kana->can_append (key);
121 }
122
123 bool
124 Reading::process_key_event (const KeyEvent & key)
125 {
126     if (!can_process_key_event (key))
127         return false;
128
129     if (m_caret_offset != 0) {
130         split_segment (m_segment_pos);
131         reset_pending ();
132     }
133
134     bool was_pending;
135     if (m_kana.can_append (key))
136         was_pending = m_kana.is_pending ();
137     else
138         was_pending = m_key2kana->is_pending ();
139
140     String raw;
141     WideString result, pending;
142     bool need_commiting;
143     if (m_kana.can_append (key))
144         need_commiting = m_kana.append (key, result, pending, raw);
145     else
146         need_commiting = m_key2kana->append (key, result, pending, raw);
147
148     ReadingSegments::iterator begin = m_segments.begin ();
149
150     // fix previous segment and prepare next segment if needed
151     if (!result.empty () || !pending.empty ()) {
152         if (!was_pending ||  // previous segment was already fixed
153             need_commiting)  // previous segment has been fixed
154         {
155             ReadingSegment c;
156             m_segments.insert (begin + m_segment_pos, c);
157             m_segment_pos++;
158         }
159     }
160
161     // fill segment
162     if (result.length() > 0 && pending.length () > 0) {
163         m_segments[m_segment_pos - 1].kana = result;
164
165         ReadingSegment c;
166         c.raw += raw;
167         c.kana = pending;
168         m_segments.insert (begin + m_segment_pos, c);
169         m_segment_pos++;
170
171     } else if (result.length () > 0) {
172         m_segments[m_segment_pos - 1].raw += raw;
173         m_segments[m_segment_pos - 1].kana = result;
174
175     } else if (pending.length () > 0) {
176         m_segments[m_segment_pos - 1].raw += raw;
177         m_segments[m_segment_pos - 1].kana = pending;
178
179     } else {
180
181     }
182
183     return false;
184 }
185
186 void
187 Reading::finish (void)
188 {
189     if (!m_key2kana->is_pending ()) return;
190
191     WideString result;
192     result = m_key2kana->flush_pending ();
193     if (result.length () > 0)
194         m_segments[m_segment_pos - 1].kana = result;
195 }
196
197 void
198 Reading::clear (void)
199 {
200     m_key2kana_normal.clear ();
201     m_kana.clear ();
202     m_nicola.clear ();
203     m_segments.clear ();
204     m_segment_pos  = 0;
205     m_caret_offset = 0;
206 }
207
208 WideString
209 Reading::get (unsigned int start, int len, StringType type)
210 {
211     WideString str;
212     unsigned int pos = 0, end = len > 0 ? start + len : get_length () - start;
213     WideString kana;
214     String raw;
215
216     if (start >= end)
217         return str;
218     if (start >= get_length ())
219         return str;
220
221     switch (type) {
222     case SCIM_ANTHY_STRING_LATIN:
223         raw = get_raw (start, len);
224         str = utf8_mbstowcs (raw);
225         return str;
226
227     case SCIM_ANTHY_STRING_WIDE_LATIN:
228         raw = get_raw (start, len);
229         util_convert_to_wide (str, raw);
230         return str;
231
232     default:
233         break;
234     }
235
236     for (unsigned int i = 0; i < m_segments.size (); i++) {
237         if (pos >= start || pos + m_segments[i].kana.length () > start) {
238             unsigned int startstart = 0, len;
239
240             if (pos >= start)
241                 startstart = 0;
242             else
243                 startstart = pos - start;
244
245             if (pos + m_segments[i].kana.length () > end)
246                 len = end - start;
247             else
248                 len = m_segments[i].kana.length ();
249
250             kana += m_segments[i].kana.substr (startstart, len);
251         }
252
253         pos += m_segments[i].kana.length ();
254         if (pos >= end)
255             break;
256     }
257
258     switch (type) {
259     case SCIM_ANTHY_STRING_HIRAGANA:
260         str = kana;
261         break;
262
263     case SCIM_ANTHY_STRING_KATAKANA:
264         util_convert_to_katakana (str, kana);
265         break;
266
267     case SCIM_ANTHY_STRING_HALF_KATAKANA:
268         util_convert_to_katakana (str, kana, true);
269         break;
270
271     default:
272         break;
273     }
274
275     return str;
276 }
277
278 String
279 Reading::get_raw (unsigned int start, int len)
280 {
281     String str;
282     unsigned int pos = 0, end = len > 0 ? start + len : get_length () - start;
283
284     if (start >= end)
285         return str;
286
287     for (unsigned int i = 0; i < m_segments.size (); i++) {
288         if (pos >= start || pos + m_segments[i].kana.length () > start) {
289             // FIXME!
290             str += m_segments[i].raw;
291         }
292
293         pos += m_segments[i].kana.length ();
294
295         if (pos >= end)
296             break;
297     }
298
299     return str;
300 }
301
302 void
303 Reading::split_segment (unsigned int seg_id)
304 {
305     if (seg_id >= m_segments.size ())
306         return;
307
308     unsigned int pos = 0;
309     for (unsigned int i = 0; i < seg_id && i < m_segments.size (); i++)
310         pos += m_segments[i].kana.length ();
311
312     unsigned int caret = get_caret_pos ();
313     unsigned int seg_len = m_segments[seg_id].kana.length ();
314     bool caret_was_in_the_segment = false;
315     if (caret > pos && caret < pos + seg_len)
316         caret_was_in_the_segment = true;
317
318     ReadingSegments segments;
319     m_segments[seg_id].split (segments);
320     m_segments.erase (m_segments.begin () + seg_id);
321     for (int j = segments.size () - 1; j >= 0; j--) {
322         m_segments.insert (m_segments.begin () + seg_id, segments[j]);
323         if (m_segment_pos > seg_id)
324             m_segment_pos++;
325     }
326
327     if (caret_was_in_the_segment) {
328         m_segment_pos += m_caret_offset;
329         m_caret_offset = 0;
330     }
331 }
332
333 bool
334 Reading::append (const KeyEvent & key,
335                  const String   & string)
336 {
337     bool was_pending;
338     WideString result, pending;
339     bool need_commiting;
340
341     if (!m_kana.can_append (key, true) &&
342         !m_key2kana->can_append (key, true))
343         return false;
344
345     if (m_caret_offset != 0) {
346         split_segment (m_segment_pos);
347         reset_pending ();
348     }
349
350     if (m_kana.can_append (key))
351         was_pending = m_kana.is_pending ();
352     else
353         was_pending = m_key2kana->is_pending ();
354
355     if (m_kana.can_append (key))
356         need_commiting = m_kana.append (string, result, pending);
357     else
358         need_commiting = m_key2kana->append (string, result, pending);
359
360     ReadingSegments::iterator begin = m_segments.begin ();
361
362     // fix previous segment and prepare next segment if needed
363     if (!result.empty () || !pending.empty ()) {
364         if (!was_pending ||  // previous segment was already fixed
365             need_commiting)  // previous segment has been fixed
366         {
367             ReadingSegment c;
368             m_segments.insert (begin + m_segment_pos, c);
369             m_segment_pos++;
370         }
371     }
372
373     // fill segment
374     if (result.length() > 0 && pending.length () > 0) {
375         m_segments[m_segment_pos - 1].kana = result;
376
377         ReadingSegment c;
378         c.raw += string;
379         c.kana = pending;
380         m_segments.insert (begin + m_segment_pos, c);
381         m_segment_pos++;
382
383     } else if (result.length () > 0) {
384         m_segments[m_segment_pos - 1].raw += string;
385         m_segments[m_segment_pos - 1].kana = result;
386
387     } else if (pending.length () > 0) {
388         m_segments[m_segment_pos - 1].raw += string;
389         m_segments[m_segment_pos - 1].kana = pending;
390
391     } else {
392
393     }
394
395     return false;
396 }
397
398 void
399 Reading::erase (unsigned int start, int len, bool allow_split)
400 {
401     if (m_segments.size () <= 0)
402         return;
403
404     if (get_length () < start)
405         return;
406
407     if (len < 0)
408         len = get_length () - start;
409
410     // erase
411     unsigned int pos = 0;
412     for (int i = 0; i <= (int) m_segments.size (); i++) {
413         if (pos < start) {
414             // we have not yet reached start position.
415
416             if (i == (int) m_segments.size ())
417                 break;
418
419             pos += m_segments[i].kana.length ();
420
421         } else if (pos == start) {
422             // we have reached start position.
423
424             if (i == (int) m_segments.size ())
425                 break;
426
427             if (allow_split &&
428                 pos + m_segments[i].kana.length () > start + len)
429             {
430                 // we have overshooted the end position!
431                 // we have to split this segment
432                 split_segment (i);
433
434             } else {
435                 // This segment is completely in the rage, erase it!
436                 len -= m_segments[i].kana.length ();
437                 m_segments.erase (m_segments.begin () + i);
438                 if ((int) m_segment_pos > i)
439                     m_segment_pos--;
440             }
441
442             // retry from the same position
443             i--;
444
445         } else {
446             // we have overshooted the start position!
447
448             if (allow_split) {
449                 pos -= m_segments[i - 1].kana.length ();
450                 split_segment (i - 1);
451
452                 // retry from the previous position
453                 i -= 2;
454
455             } else {
456                 // we have overshooted the start position, but have not been
457                 // allowed to split the segment.
458                 // So remove all string of previous segment.
459                 len -= pos - start;
460                 pos -= m_segments[i - 1].kana.length ();
461                 m_segments.erase (m_segments.begin () + i - 1);
462                 if ((int) m_segment_pos > i - 1)
463                     m_segment_pos--;
464
465                 // retry from the previous position
466                 i -= 2;
467             }
468         }
469
470         // Now all letters in the range are removed.
471         // Exit the loop.
472         if (len <= 0)
473             break;
474     }
475
476     // reset values
477     if (m_segments.size () <= 0) {
478         clear ();
479     } else {
480         reset_pending ();
481     }
482 }
483
484 void
485 Reading::reset_pending (void)
486 {
487     if (m_key2kana->is_pending ())
488         m_key2kana->clear ();
489     if (m_kana.is_pending ())
490         m_kana.clear ();
491
492     if (m_segment_pos <= 0)
493         return;
494
495     m_key2kana->reset_pending (m_segments[m_segment_pos - 1].kana,
496                                m_segments[m_segment_pos - 1].raw);
497     m_kana.reset_pending (m_segments[m_segment_pos - 1].kana,
498                           m_segments[m_segment_pos - 1].raw);
499
500     // FIXME! this code breaks pending state on normal input mode.
501     m_key2kana->reset_pseudo_ascii_mode();
502     for (unsigned int i = 0; i < m_segment_pos; i++)
503         m_key2kana->process_pseudo_ascii_mode(m_segments[i].kana);
504 }
505
506 unsigned int
507 Reading::get_length (void)
508 {
509     unsigned int len = 0;
510     for (unsigned int i = 0; i < m_segments.size (); i++)
511         len += m_segments[i].kana.length();
512     return len;
513 }
514
515 unsigned int
516 Reading::get_caret_pos (void)
517 {
518     unsigned int pos = 0;
519
520     for (unsigned int i = 0;
521          i < m_segment_pos && i < m_segments.size ();
522          i++)
523     {
524         pos += m_segments[i].kana.length();
525     }
526
527     pos += m_caret_offset;
528
529     return pos;
530 }
531
532 // FIXME! add "allow_split" argument.
533 void
534 Reading::set_caret_pos (unsigned int pos)
535 {
536     if (pos == get_caret_pos ())
537         return;
538
539     m_key2kana->clear ();
540     m_kana.clear ();
541
542     if (pos >= get_length ()) {
543         m_segment_pos = m_segments.size ();
544
545     } else if (pos == 0 ||  m_segments.size () <= 0) {
546         m_segment_pos = 0;
547
548     } else {
549         unsigned int i, tmp_pos = 0;
550
551         for (i = 0; tmp_pos <= pos; i++)
552             tmp_pos += m_segments[i].kana.length();
553
554         if (tmp_pos == pos) {
555             m_segment_pos = i + 1;
556         } else if (tmp_pos < get_caret_pos ()) {
557             m_segment_pos = i;
558         } else if (tmp_pos > get_caret_pos ()) {
559             m_segment_pos = i + 1;
560         }
561     }
562
563     reset_pending ();
564 }
565
566 void
567 Reading::move_caret (int step, bool allow_split)
568 {
569     if (step == 0)
570         return;
571
572     m_key2kana->clear ();
573     m_kana.clear ();
574
575     if (allow_split) {
576         unsigned int pos = get_caret_pos ();
577         if (step < 0 && pos < (int) abs (step)) {
578             // lower limit
579             m_segment_pos = 0;
580
581         } else if (step > 0 && pos + step > get_length ()) {
582             // upper limit
583             m_segment_pos = m_segments.size ();
584
585         } else {
586             unsigned int new_pos = pos + step;
587             ReadingSegments::iterator it;
588             pos = 0;
589             m_segment_pos = 0;
590             m_caret_offset = 0;
591             for (it = m_segments.begin (); pos < new_pos; it++) {
592                 if (pos + it->kana.length () > new_pos) {
593                     m_caret_offset = new_pos - pos;
594                     break;
595                 } else {
596                     m_segment_pos++;
597                     pos += it->kana.length ();
598                 }
599             }
600         }
601
602     } else {
603         if (step < 0 && m_segment_pos < (int) abs (step)) {
604             // lower limit
605             m_segment_pos = 0;
606
607         } else if (step > 0 && m_segment_pos + step > m_segments.size ()) {
608             // upper limit
609             m_segment_pos = m_segments.size ();
610
611         } else {
612             // other
613             m_segment_pos += step;
614         }
615     }
616
617     reset_pending ();
618 }
619
620 void
621 Reading::set_typing_method (TypingMethod method)
622 {
623     Key2KanaTable *fundamental_table = NULL;
624
625     if (method == SCIM_ANTHY_TYPING_METHOD_NICOLA) {
626         fundamental_table = m_anthy.get_factory()->m_custom_nicola_table;
627         m_key2kana = &m_nicola;
628         m_nicola_tables.set_typing_method (method, fundamental_table);
629         m_nicola.set_case_sensitive (true);
630     } else if (method == SCIM_ANTHY_TYPING_METHOD_KANA) {
631         fundamental_table = m_anthy.get_factory()->m_custom_kana_table;
632         m_key2kana = &m_key2kana_normal;
633         m_key2kana_tables.set_typing_method (method, fundamental_table);
634         m_key2kana_normal.set_case_sensitive (true);
635     } else {
636         fundamental_table = m_anthy.get_factory()->m_custom_romaji_table;
637         m_key2kana = &m_key2kana_normal;
638         m_key2kana_tables.set_typing_method (method, fundamental_table);
639         m_key2kana_normal.set_case_sensitive (false);
640     }
641 }
642
643 TypingMethod
644 Reading::get_typing_method (void)
645 {
646     if (m_key2kana == &m_nicola)
647         return SCIM_ANTHY_TYPING_METHOD_NICOLA;
648     else
649         return m_key2kana_tables.get_typing_method ();
650 }
651
652 void
653 Reading::set_period_style (PeriodStyle style)
654 {
655     m_key2kana_tables.set_period_style (style);
656 }
657
658 PeriodStyle
659 Reading::get_period_style (void)
660 {
661     return m_key2kana_tables.get_period_style ();
662 }
663
664 void
665 Reading::set_comma_style (CommaStyle style)
666 {
667     m_key2kana_tables.set_comma_style (style);
668 }
669
670 CommaStyle
671 Reading::get_comma_style (void)
672 {
673     return m_key2kana_tables.get_comma_style ();
674 }
675
676 void
677 Reading::set_bracket_style (BracketStyle style)
678 {
679     m_key2kana_tables.set_bracket_style (style);
680 }
681
682 BracketStyle
683 Reading::get_bracket_style (void)
684 {
685     return m_key2kana_tables.get_bracket_style ();
686 }
687
688 void
689 Reading::set_slash_style (SlashStyle style)
690 {
691     m_key2kana_tables.set_slash_style (style);
692 }
693
694 SlashStyle
695 Reading::get_slash_style (void)
696 {
697     return m_key2kana_tables.get_slash_style ();
698 }
699
700 void
701 Reading::set_symbol_width (bool half)
702 {
703     m_key2kana_tables.set_symbol_width (half);
704 }
705
706 bool
707 Reading::get_symbol_width (void)
708 {
709     return m_key2kana_tables.symbol_is_half ();
710 }
711
712 void
713 Reading::set_number_width (bool half)
714 {
715     m_key2kana_tables.set_number_width (half);
716 }
717
718 bool
719 Reading::get_number_width (void)
720 {
721     return m_key2kana_tables.number_is_half ();
722 }
723
724 void
725 Reading::set_pseudo_ascii_mode (int mode)
726 {
727     m_key2kana_normal.set_pseudo_ascii_mode (mode);
728 }
729
730 bool
731 Reading::is_pseudo_ascii_mode (void)
732 {
733     return m_key2kana_normal.is_pseudo_ascii_mode ();
734 }
735
736 void
737 Reading::reset_pseudo_ascii_mode (void)
738 {
739     if (m_key2kana_normal.is_pseudo_ascii_mode () &&
740         m_key2kana_normal.is_pending ())
741     {
742         ReadingSegment c;
743         ReadingSegments::iterator it = m_segments.begin ();
744
745         /* separate to another segment */
746         m_key2kana_normal.reset_pseudo_ascii_mode ();
747         m_segments.insert (it + m_segment_pos, c);
748         m_segment_pos++;
749     }
750 }