~ubuntu-branches/ubuntu/saucy/ibus-pinyin/saucy-proposed

« back to all changes in this revision

Viewing changes to src/PYDoublePinyinEditor.cc

  • Committer: Bazaar Package Importer
  • Author(s): LI Daobing, Asias He
  • Date: 2010-09-08 21:38:54 UTC
  • mfrom: (1.2.8 upstream)
  • Revision ID: james.westby@ubuntu.com-20100908213854-q4wlx8zlcyqxvelz
Tags: 1.3.11-1
[ Asias He ]
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* vim:set et ts=4 sts=4:
 
2
 *
 
3
 * ibus-pinyin - The Chinese PinYin engine for IBus
 
4
 *
 
5
 * Copyright (c) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or modify
 
8
 * it under the terms of the GNU General Public License as published by
 
9
 * the Free Software Foundation; either version 2, or (at your option)
 
10
 * any later version.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 * GNU General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, write to the Free Software
 
19
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
20
 */
 
21
#include "PYDoublePinyinEditor.h"
 
22
#include "PYConfig.h"
 
23
 
 
24
namespace PY {
 
25
 
 
26
#define DEFINE_DOUBLE_PINYIN_TABLES
 
27
#include "PYDoublePinyinTable.h"
 
28
 
 
29
/*
 
30
 * c in 'a' ... 'z' => id = c - 'a'
 
31
 * c == ';'         => id = 26
 
32
 * else             => id = -1
 
33
 */
 
34
#define ID(c) \
 
35
    ((c >= IBUS_a && c <= IBUS_z) ? c - IBUS_a : (c == IBUS_semicolon ? 26 : -1))
 
36
 
 
37
#define ID_TO_SHENG(id) \
 
38
    (double_pinyin_map[m_config.doublePinyinSchema ()].sheng[id])
 
39
#define ID_TO_YUNS(id) \
 
40
    (double_pinyin_map[m_config.doublePinyinSchema ()].yun[id])
 
41
 
 
42
#define IS_ALPHA(c) \
 
43
        ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
 
44
 
 
45
DoublePinyinEditor::DoublePinyinEditor (PinyinProperties & props, Config & config)
 
46
    : PinyinEditor (props, config)
 
47
{
 
48
}
 
49
 
 
50
gboolean
 
51
DoublePinyinEditor::insert (gint ch)
 
52
{
 
53
    gint id;
 
54
    /* is full */
 
55
    if (G_UNLIKELY (m_text.length () >= MAX_PINYIN_LEN))
 
56
        return TRUE;
 
57
 
 
58
    id = ID (ch);
 
59
    if (id == -1) {
 
60
        /* it is not availidate ch */
 
61
        return FALSE;
 
62
    }
 
63
 
 
64
    if (G_UNLIKELY (m_text.empty () &&
 
65
        ID_TO_SHENG (id) == PINYIN_ID_VOID)) {
 
66
        return FALSE;
 
67
    }
 
68
 
 
69
    m_text.insert (m_cursor++, ch);
 
70
 
 
71
    if (m_cursor > m_pinyin_len + 2 || updatePinyin (FALSE) == FALSE) {
 
72
        if (!IS_ALPHA (ch)) {
 
73
            m_text.erase (--m_cursor, 1);
 
74
            return FALSE;
 
75
        }
 
76
        else {
 
77
            if (updateSpecialPhrases ()) {
 
78
                update ();
 
79
            }
 
80
            else {
 
81
                updatePreeditText ();
 
82
                updateAuxiliaryText ();
 
83
            }
 
84
            return TRUE;
 
85
        }
 
86
    }
 
87
    else {
 
88
        updateSpecialPhrases ();
 
89
        updatePhraseEditor ();
 
90
        update ();
 
91
        return TRUE;
 
92
    }
 
93
}
 
94
 
 
95
gboolean
 
96
DoublePinyinEditor::removeCharBefore (void)
 
97
{
 
98
    if (G_UNLIKELY (m_cursor == 0))
 
99
        return FALSE;
 
100
 
 
101
    m_cursor --;
 
102
    m_text.erase (m_cursor, 1);
 
103
 
 
104
    if (updatePinyin (FALSE)) {
 
105
        updateSpecialPhrases ();
 
106
        updatePhraseEditor ();
 
107
        update ();
 
108
    }
 
109
    else {
 
110
        if (updateSpecialPhrases ()) {
 
111
            update ();
 
112
        }
 
113
        else {
 
114
            updatePreeditText ();
 
115
            updateAuxiliaryText ();
 
116
        }
 
117
    }
 
118
    return TRUE;
 
119
}
 
120
 
 
121
gboolean
 
122
DoublePinyinEditor::removeCharAfter (void)
 
123
{
 
124
    if (G_UNLIKELY (m_cursor == m_text.length ()))
 
125
        return FALSE;
 
126
 
 
127
    m_text.erase (m_cursor, 1);
 
128
    if (updateSpecialPhrases ()) {
 
129
        update ();
 
130
    }
 
131
    else {
 
132
        updatePreeditText ();
 
133
        updateAuxiliaryText ();
 
134
    }
 
135
    return TRUE;
 
136
}
 
137
 
 
138
gboolean
 
139
DoublePinyinEditor::removeWordBefore (void)
 
140
{
 
141
    if (G_UNLIKELY (m_cursor == 0))
 
142
        return FALSE;
 
143
 
 
144
    if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
 
145
        m_text.erase (m_pinyin_len, m_cursor - m_pinyin_len);
 
146
        m_cursor = m_pinyin_len;
 
147
        if (updateSpecialPhrases ()) {
 
148
            update ();
 
149
        }
 
150
        else {
 
151
            updatePreeditText ();
 
152
            updateAuxiliaryText ();
 
153
        }
 
154
    }
 
155
    else {
 
156
        m_pinyin_len = m_pinyin.back ().begin;
 
157
        m_pinyin.pop_back ();
 
158
        m_text.erase (m_pinyin_len, m_cursor - m_pinyin_len);
 
159
        m_cursor = m_pinyin_len;
 
160
        updateSpecialPhrases ();
 
161
        updatePhraseEditor ();
 
162
        update ();
 
163
    }
 
164
 
 
165
    return TRUE;
 
166
}
 
167
 
 
168
gboolean
 
169
DoublePinyinEditor::removeWordAfter (void)
 
170
{
 
171
    if (G_UNLIKELY (m_cursor == m_text.length ()))
 
172
        return FALSE;
 
173
 
 
174
    m_text.erase (m_cursor);
 
175
    if (updateSpecialPhrases ()) {
 
176
        update ();
 
177
    }
 
178
    else {
 
179
        updatePreeditText ();
 
180
        updateAuxiliaryText ();
 
181
    }
 
182
    return TRUE;
 
183
}
 
184
 
 
185
gboolean
 
186
DoublePinyinEditor::moveCursorLeft (void)
 
187
{
 
188
    if (G_UNLIKELY (m_cursor == 0))
 
189
        return FALSE;
 
190
 
 
191
    m_cursor --;
 
192
 
 
193
    if (m_cursor >= m_pinyin_len) {
 
194
        if (updateSpecialPhrases ()) {
 
195
            update ();
 
196
        }
 
197
        else {
 
198
            updatePreeditText ();
 
199
            updateAuxiliaryText ();
 
200
        }
 
201
    }
 
202
    else {
 
203
        if (updatePinyin (FALSE)) {
 
204
            updateSpecialPhrases ();
 
205
            updatePhraseEditor ();
 
206
            update ();
 
207
        }
 
208
        else {
 
209
            if (updateSpecialPhrases ()) {
 
210
                update ();
 
211
            }
 
212
            else {
 
213
                updatePreeditText ();
 
214
                updateAuxiliaryText ();
 
215
            }
 
216
        }
 
217
    }
 
218
 
 
219
    return TRUE;
 
220
}
 
221
 
 
222
gboolean
 
223
DoublePinyinEditor::moveCursorRight (void)
 
224
{
 
225
    if (G_UNLIKELY (m_cursor == m_text.length ()))
 
226
        return FALSE;
 
227
 
 
228
    m_cursor ++;
 
229
    if (updatePinyin (FALSE)) {
 
230
        updateSpecialPhrases ();
 
231
        updatePhraseEditor ();
 
232
        update ();
 
233
    }
 
234
    else {
 
235
        if (updateSpecialPhrases ()) {
 
236
            update ();
 
237
        }
 
238
        else {
 
239
            updatePreeditText ();
 
240
            updateAuxiliaryText ();
 
241
        }
 
242
    }
 
243
    return TRUE;
 
244
}
 
245
 
 
246
gboolean
 
247
DoublePinyinEditor::moveCursorLeftByWord (void)
 
248
{
 
249
    if (G_UNLIKELY (m_cursor == 0))
 
250
        return FALSE;
 
251
 
 
252
    if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
 
253
        m_cursor = m_pinyin_len;
 
254
        if (updateSpecialPhrases ()) {
 
255
            update ();
 
256
        }
 
257
        else {
 
258
            updatePreeditText ();
 
259
            updateAuxiliaryText ();
 
260
        }
 
261
    }
 
262
    else {
 
263
        m_cursor = m_pinyin_len = m_pinyin.back ().begin;
 
264
        m_pinyin.pop_back ();
 
265
        updateSpecialPhrases ();
 
266
        updatePhraseEditor ();
 
267
        update ();
 
268
    }
 
269
 
 
270
    return TRUE;
 
271
}
 
272
 
 
273
gboolean
 
274
DoublePinyinEditor::moveCursorRightByWord (void)
 
275
{
 
276
    return moveCursorToEnd ();
 
277
}
 
278
 
 
279
gboolean
 
280
DoublePinyinEditor::moveCursorToBegin (void)
 
281
{
 
282
    if (G_UNLIKELY (m_cursor == 0))
 
283
        return FALSE;
 
284
 
 
285
    m_cursor = 0;
 
286
    m_pinyin.clear ();
 
287
    m_pinyin_len = 0;
 
288
    updateSpecialPhrases ();
 
289
    updatePhraseEditor ();
 
290
    update ();
 
291
 
 
292
    return TRUE;
 
293
}
 
294
 
 
295
gboolean
 
296
DoublePinyinEditor::moveCursorToEnd (void)
 
297
{
 
298
    if (G_UNLIKELY (m_cursor == m_text.length ()))
 
299
        return FALSE;
 
300
 
 
301
    m_cursor = m_text.length ();
 
302
    if (updatePinyin (FALSE)) {
 
303
        updateSpecialPhrases ();
 
304
        updatePhraseEditor ();
 
305
        update ();
 
306
    }
 
307
    else {
 
308
        if (updateSpecialPhrases ()) {
 
309
            update ();
 
310
        }
 
311
        else {
 
312
            updatePreeditText ();
 
313
            updateAuxiliaryText ();
 
314
        }
 
315
    }
 
316
    return TRUE;
 
317
}
 
318
 
 
319
void
 
320
DoublePinyinEditor::reset (void)
 
321
{
 
322
    PinyinEditor::reset ();
 
323
}
 
324
 
 
325
inline const Pinyin *
 
326
DoublePinyinEditor::isPinyin (gint i)
 
327
{
 
328
    if ((m_config.option () & PINYIN_INCOMPLETE_PINYIN) == 0) {
 
329
        return NULL;
 
330
    }
 
331
 
 
332
    gint8 sheng = ID_TO_SHENG (i);
 
333
 
 
334
    if (sheng == PINYIN_ID_VOID) {
 
335
        return NULL;
 
336
    }
 
337
 
 
338
    return PinyinParser::isPinyin (sheng, 0, PINYIN_INCOMPLETE_PINYIN);
 
339
}
 
340
 
 
341
inline const Pinyin *
 
342
DoublePinyinEditor::isPinyin (gint i, gint j)
 
343
{
 
344
    const Pinyin *pinyin;
 
345
    gint8 sheng = ID_TO_SHENG (i);
 
346
    const gint8 *yun = ID_TO_YUNS (j);
 
347
 
 
348
    if (sheng == PINYIN_ID_VOID || yun[0] == PINYIN_ID_VOID)
 
349
        return NULL;
 
350
 
 
351
    if (sheng == PINYIN_ID_ZERO && yun[0] == PINYIN_ID_ZERO)
 
352
        return NULL;
 
353
 
 
354
    if (yun[1] == PINYIN_ID_VOID) {
 
355
        return PinyinParser::isPinyin (sheng, yun[0],
 
356
                        m_config.option () & (PINYIN_FUZZY_ALL | PINYIN_CORRECT_V_TO_U));
 
357
    }
 
358
 
 
359
    pinyin = PinyinParser::isPinyin (sheng, yun[0],
 
360
                    m_config.option () & (PINYIN_FUZZY_ALL));
 
361
    if (pinyin == NULL)
 
362
        pinyin = PinyinParser::isPinyin (sheng, yun[1],
 
363
                        m_config.option () & (PINYIN_FUZZY_ALL));
 
364
    if (pinyin != NULL)
 
365
        return pinyin;
 
366
 
 
367
    /* if sheng == j q x y and yun == v, try to correct v to u */
 
368
    if ((m_config.option () & PINYIN_CORRECT_V_TO_U) == 0)
 
369
        return NULL;
 
370
 
 
371
    if (yun[0] != PINYIN_ID_V && yun[1] != PINYIN_ID_V)
 
372
        return NULL;
 
373
 
 
374
    switch (sheng) {
 
375
    case PINYIN_ID_J:
 
376
    case PINYIN_ID_Q:
 
377
    case PINYIN_ID_X:
 
378
    case PINYIN_ID_Y:
 
379
        return PinyinParser::isPinyin (sheng, PINYIN_ID_V,
 
380
                            m_config.option () & (PINYIN_FUZZY_ALL | PINYIN_CORRECT_V_TO_U));
 
381
    default:
 
382
        return NULL;
 
383
    }
 
384
}
 
385
 
 
386
inline gboolean
 
387
DoublePinyinEditor::updatePinyin (gboolean all)
 
388
{
 
389
    gboolean retval = FALSE;
 
390
 
 
391
    if (all &&
 
392
        (m_pinyin_len != 0 || !m_pinyin.empty ())) {
 
393
        m_pinyin.clear ();
 
394
        m_pinyin_len = 0;
 
395
        retval = TRUE;
 
396
    }
 
397
 
 
398
    if (m_pinyin_len > m_cursor) {
 
399
        retval = TRUE;
 
400
        while (m_pinyin_len > m_cursor) {
 
401
            m_pinyin_len = m_pinyin.back ().begin;
 
402
            m_pinyin.pop_back ();
 
403
        }
 
404
    }
 
405
 
 
406
    if (m_pinyin_len == m_cursor) {
 
407
        return retval;
 
408
    }
 
409
 
 
410
    if (m_pinyin_len < m_cursor) {
 
411
        guint len = m_pinyin_len;
 
412
        if (m_pinyin.empty () == FALSE &&
 
413
            m_pinyin.back ()->flags & PINYIN_INCOMPLETE_PINYIN) {
 
414
            const Pinyin *pinyin = isPinyin (ID (m_text[m_pinyin_len -1]),ID (m_text[m_pinyin_len]));
 
415
            if (pinyin) {
 
416
                m_pinyin.pop_back ();
 
417
                m_pinyin.append (pinyin, m_pinyin_len - 1, 2);
 
418
                m_pinyin_len += 1;
 
419
            }
 
420
        }
 
421
        while (m_pinyin_len < m_cursor && m_pinyin.size () < MAX_PHRASE_LEN) {
 
422
            const Pinyin *pinyin = NULL;
 
423
            if (m_pinyin_len == m_cursor - 1) {
 
424
                pinyin = isPinyin (ID (m_text[m_pinyin_len]));
 
425
            }
 
426
            else {
 
427
                pinyin = isPinyin (ID (m_text[m_pinyin_len]), ID (m_text[m_pinyin_len + 1]));
 
428
                if (pinyin == NULL)
 
429
                    pinyin = isPinyin (ID (m_text[m_pinyin_len]));
 
430
            }
 
431
            if (pinyin == NULL)
 
432
                break;
 
433
            if (pinyin->flags & PINYIN_INCOMPLETE_PINYIN) {
 
434
                m_pinyin.append (pinyin, m_pinyin_len, 1);
 
435
                m_pinyin_len += 1;
 
436
            }
 
437
            else {
 
438
                m_pinyin.append (pinyin, m_pinyin_len, 2);
 
439
                m_pinyin_len += 2;
 
440
            }
 
441
        }
 
442
        if (len == m_pinyin_len)
 
443
            return retval;
 
444
        return TRUE;
 
445
    }
 
446
    return retval;
 
447
}
 
448
 
 
449
void
 
450
DoublePinyinEditor::updateAuxiliaryTextAfter (String &buffer)
 
451
{
 
452
    if (G_LIKELY (!m_config.doublePinyinShowRaw ()))
 
453
        return;
 
454
 
 
455
    if (G_LIKELY (m_config.orientation () == IBUS_ORIENTATION_HORIZONTAL)) {
 
456
        buffer << "        [ ";
 
457
    }
 
458
    else {
 
459
        buffer << "\n[ ";
 
460
    }
 
461
    
 
462
    if (G_LIKELY (m_cursor == m_text.length ())) {
 
463
        m_buffer << m_text << " ]";
 
464
    }
 
465
    else {
 
466
        buffer.append (m_text.c_str (), m_cursor);
 
467
        buffer << " ";
 
468
        buffer.append (m_text.c_str () + m_cursor);
 
469
        buffer << " ]";
 
470
    }
 
471
}
 
472
 
 
473
gboolean
 
474
DoublePinyinEditor::processKeyEvent (guint keyval, guint keycode, guint modifiers)
 
475
{
 
476
    /* handle ';' key */
 
477
    if (G_UNLIKELY (keyval == IBUS_semicolon)) {
 
478
        if (cmshm_filter (modifiers) == 0) {
 
479
            if (insert (keyval))
 
480
                return TRUE;
 
481
        }
 
482
    }
 
483
 
 
484
    return PinyinEditor::processKeyEvent (keyval, keycode, modifiers);
 
485
}
 
486
 
 
487
};
 
488
 
 
489