1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * Copyright (C) 2005 Takuro Ashie
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)
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.
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.
20 #include "scim_anthy_reading.h"
21 #include "scim_anthy_factory.h"
22 #include "scim_anthy_imengine.h"
23 #include "scim_anthy_utils.h"
25 using namespace scim_anthy;
27 ReadingSegment::ReadingSegment ()
31 ReadingSegment::~ReadingSegment ()
36 find_romaji (WideString c)
38 ConvRule *table = scim_anthy_romaji_typing_rule;
40 for (unsigned int i = 0; table[i].string; i++) {
41 WideString kana = utf8_mbstowcs (table[i].result);
43 return table[i].string;
50 to_half (String &dest, WideString &src)
52 WideRule *table = scim_anthy_wide_table;
54 for (unsigned int i = 0; i < src.size (); i++) {
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);
60 dest += table[i].code;
66 dest += utf8_wcstombs (kana1);
70 // Only a romaji string can be splited with raw key string.
71 // Other typing method aren't supported splitting raw key string.
73 ReadingSegment::split (ReadingSegments &segments)
75 if (kana.length () <= 1)
76 segments.push_back (*this);
80 bool same_with_raw = half == raw;
82 WideString::iterator it;
83 for (unsigned int i = 0; i < kana.size (); i++) {
84 WideString c = kana.substr (i, 1);
90 seg.raw = find_romaji (c);
91 segments.push_back (seg);
97 Reading::Reading (AnthyInstance &anthy)
99 //m_key2kana_tables (tables),
100 m_key2kana_normal (anthy, m_key2kana_tables),
102 m_nicola (anthy, m_nicola_tables),
103 m_key2kana (&m_key2kana_normal),
107 m_nicola_tables.set_typing_method (SCIM_ANTHY_TYPING_METHOD_NICOLA);
115 Reading::can_process_key_event (const KeyEvent & key)
117 if (m_kana.can_append (key))
120 return m_key2kana->can_append (key);
124 Reading::process_key_event (const KeyEvent & key)
126 if (!can_process_key_event (key))
129 if (m_caret_offset != 0) {
130 split_segment (m_segment_pos);
135 if (m_kana.can_append (key))
136 was_pending = m_kana.is_pending ();
138 was_pending = m_key2kana->is_pending ();
141 WideString result, pending;
143 if (m_kana.can_append (key))
144 need_commiting = m_kana.append (key, result, pending, raw);
146 need_commiting = m_key2kana->append (key, result, pending, raw);
148 ReadingSegments::iterator begin = m_segments.begin ();
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
156 m_segments.insert (begin + m_segment_pos, c);
162 if (result.length() > 0 && pending.length () > 0) {
163 m_segments[m_segment_pos - 1].kana = result;
168 m_segments.insert (begin + m_segment_pos, c);
171 } else if (result.length () > 0) {
172 m_segments[m_segment_pos - 1].raw += raw;
173 m_segments[m_segment_pos - 1].kana = result;
175 } else if (pending.length () > 0) {
176 m_segments[m_segment_pos - 1].raw += raw;
177 m_segments[m_segment_pos - 1].kana = pending;
187 Reading::finish (void)
189 if (!m_key2kana->is_pending ()) return;
192 result = m_key2kana->flush_pending ();
193 if (result.length () > 0)
194 m_segments[m_segment_pos - 1].kana = result;
198 Reading::clear (void)
200 m_key2kana_normal.clear ();
209 Reading::get (unsigned int start, int len, StringType type)
212 unsigned int pos = 0, end = len > 0 ? start + len : get_length () - start;
218 if (start >= get_length ())
222 case SCIM_ANTHY_STRING_LATIN:
223 raw = get_raw (start, len);
224 str = utf8_mbstowcs (raw);
227 case SCIM_ANTHY_STRING_WIDE_LATIN:
228 raw = get_raw (start, len);
229 util_convert_to_wide (str, raw);
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;
243 startstart = pos - start;
245 if (pos + m_segments[i].kana.length () > end)
248 len = m_segments[i].kana.length ();
250 kana += m_segments[i].kana.substr (startstart, len);
253 pos += m_segments[i].kana.length ();
259 case SCIM_ANTHY_STRING_HIRAGANA:
263 case SCIM_ANTHY_STRING_KATAKANA:
264 util_convert_to_katakana (str, kana);
267 case SCIM_ANTHY_STRING_HALF_KATAKANA:
268 util_convert_to_katakana (str, kana, true);
279 Reading::get_raw (unsigned int start, int len)
282 unsigned int pos = 0, end = len > 0 ? start + len : get_length () - start;
287 for (unsigned int i = 0; i < m_segments.size (); i++) {
288 if (pos >= start || pos + m_segments[i].kana.length () > start) {
290 str += m_segments[i].raw;
293 pos += m_segments[i].kana.length ();
303 Reading::split_segment (unsigned int seg_id)
305 if (seg_id >= m_segments.size ())
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 ();
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;
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)
327 if (caret_was_in_the_segment) {
328 m_segment_pos += m_caret_offset;
334 Reading::append (const KeyEvent & key,
335 const String & string)
338 WideString result, pending;
341 if (!m_kana.can_append (key, true) &&
342 !m_key2kana->can_append (key, true))
345 if (m_caret_offset != 0) {
346 split_segment (m_segment_pos);
350 if (m_kana.can_append (key))
351 was_pending = m_kana.is_pending ();
353 was_pending = m_key2kana->is_pending ();
355 if (m_kana.can_append (key))
356 need_commiting = m_kana.append (string, result, pending);
358 need_commiting = m_key2kana->append (string, result, pending);
360 ReadingSegments::iterator begin = m_segments.begin ();
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
368 m_segments.insert (begin + m_segment_pos, c);
374 if (result.length() > 0 && pending.length () > 0) {
375 m_segments[m_segment_pos - 1].kana = result;
380 m_segments.insert (begin + m_segment_pos, c);
383 } else if (result.length () > 0) {
384 m_segments[m_segment_pos - 1].raw += string;
385 m_segments[m_segment_pos - 1].kana = result;
387 } else if (pending.length () > 0) {
388 m_segments[m_segment_pos - 1].raw += string;
389 m_segments[m_segment_pos - 1].kana = pending;
399 Reading::erase (unsigned int start, int len, bool allow_split)
401 if (m_segments.size () <= 0)
404 if (get_length () < start)
408 len = get_length () - start;
411 unsigned int pos = 0;
412 for (int i = 0; i <= (int) m_segments.size (); i++) {
414 // we have not yet reached start position.
416 if (i == (int) m_segments.size ())
419 pos += m_segments[i].kana.length ();
421 } else if (pos == start) {
422 // we have reached start position.
424 if (i == (int) m_segments.size ())
428 pos + m_segments[i].kana.length () > start + len)
430 // we have overshooted the end position!
431 // we have to split this segment
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)
442 // retry from the same position
446 // we have overshooted the start position!
449 pos -= m_segments[i - 1].kana.length ();
450 split_segment (i - 1);
452 // retry from the previous position
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.
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)
465 // retry from the previous position
470 // Now all letters in the range are removed.
477 if (m_segments.size () <= 0) {
485 Reading::reset_pending (void)
487 if (m_key2kana->is_pending ())
488 m_key2kana->clear ();
489 if (m_kana.is_pending ())
492 if (m_segment_pos <= 0)
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);
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);
507 Reading::get_length (void)
509 unsigned int len = 0;
510 for (unsigned int i = 0; i < m_segments.size (); i++)
511 len += m_segments[i].kana.length();
516 Reading::get_caret_pos (void)
518 unsigned int pos = 0;
520 for (unsigned int i = 0;
521 i < m_segment_pos && i < m_segments.size ();
524 pos += m_segments[i].kana.length();
527 pos += m_caret_offset;
532 // FIXME! add "allow_split" argument.
534 Reading::set_caret_pos (unsigned int pos)
536 if (pos == get_caret_pos ())
539 m_key2kana->clear ();
542 if (pos >= get_length ()) {
543 m_segment_pos = m_segments.size ();
545 } else if (pos == 0 || m_segments.size () <= 0) {
549 unsigned int i, tmp_pos = 0;
551 for (i = 0; tmp_pos <= pos; i++)
552 tmp_pos += m_segments[i].kana.length();
554 if (tmp_pos == pos) {
555 m_segment_pos = i + 1;
556 } else if (tmp_pos < get_caret_pos ()) {
558 } else if (tmp_pos > get_caret_pos ()) {
559 m_segment_pos = i + 1;
567 Reading::move_caret (int step, bool allow_split)
572 m_key2kana->clear ();
576 unsigned int pos = get_caret_pos ();
577 if (step < 0 && pos < (int) abs (step)) {
581 } else if (step > 0 && pos + step > get_length ()) {
583 m_segment_pos = m_segments.size ();
586 unsigned int new_pos = pos + step;
587 ReadingSegments::iterator it;
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;
597 pos += it->kana.length ();
603 if (step < 0 && m_segment_pos < (int) abs (step)) {
607 } else if (step > 0 && m_segment_pos + step > m_segments.size ()) {
609 m_segment_pos = m_segments.size ();
613 m_segment_pos += step;
621 Reading::set_typing_method (TypingMethod method)
623 Key2KanaTable *fundamental_table = NULL;
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);
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);
644 Reading::get_typing_method (void)
646 if (m_key2kana == &m_nicola)
647 return SCIM_ANTHY_TYPING_METHOD_NICOLA;
649 return m_key2kana_tables.get_typing_method ();
653 Reading::set_period_style (PeriodStyle style)
655 m_key2kana_tables.set_period_style (style);
659 Reading::get_period_style (void)
661 return m_key2kana_tables.get_period_style ();
665 Reading::set_comma_style (CommaStyle style)
667 m_key2kana_tables.set_comma_style (style);
671 Reading::get_comma_style (void)
673 return m_key2kana_tables.get_comma_style ();
677 Reading::set_bracket_style (BracketStyle style)
679 m_key2kana_tables.set_bracket_style (style);
683 Reading::get_bracket_style (void)
685 return m_key2kana_tables.get_bracket_style ();
689 Reading::set_slash_style (SlashStyle style)
691 m_key2kana_tables.set_slash_style (style);
695 Reading::get_slash_style (void)
697 return m_key2kana_tables.get_slash_style ();
701 Reading::set_symbol_width (bool half)
703 m_key2kana_tables.set_symbol_width (half);
707 Reading::get_symbol_width (void)
709 return m_key2kana_tables.symbol_is_half ();
713 Reading::set_number_width (bool half)
715 m_key2kana_tables.set_number_width (half);
719 Reading::get_number_width (void)
721 return m_key2kana_tables.number_is_half ();
725 Reading::set_pseudo_ascii_mode (int mode)
727 m_key2kana_normal.set_pseudo_ascii_mode (mode);
731 Reading::is_pseudo_ascii_mode (void)
733 return m_key2kana_normal.is_pseudo_ascii_mode ();
737 Reading::reset_pseudo_ascii_mode (void)
739 if (m_key2kana_normal.is_pseudo_ascii_mode () &&
740 m_key2kana_normal.is_pending ())
743 ReadingSegments::iterator it = m_segments.begin ();
745 /* separate to another segment */
746 m_key2kana_normal.reset_pseudo_ascii_mode ();
747 m_segments.insert (it + m_segment_pos, c);