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

« back to all changes in this revision

Viewing changes to src/PYPunctEditor.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
 * Copyright (c) 2010 BYVoid <byvoid1@gmail.com>
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or modify
 
9
 * it under the terms of the GNU General Public License as published by
 
10
 * the Free Software Foundation; either version 2, or (at your option)
 
11
 * any later version.
 
12
 *
 
13
 * This program is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
 * GNU General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU General Public License
 
19
 * along with this program; if not, write to the Free Software
 
20
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
21
 */
 
22
#include "PYConfig.h"
 
23
#include "PYPunctEditor.h"
 
24
 
 
25
namespace PY {
 
26
 
 
27
#include "PYPunctTable.h"
 
28
 
 
29
PunctEditor::PunctEditor (PinyinProperties & props, Config & config)
 
30
    : Editor (props, config),
 
31
      m_punct_mode (MODE_DISABLE),
 
32
      m_lookup_table (m_config.pageSize ())
 
33
{
 
34
}
 
35
 
 
36
gboolean
 
37
PunctEditor::insert (gchar ch)
 
38
{
 
39
    switch (m_punct_mode) {
 
40
    case MODE_DISABLE:
 
41
        {
 
42
            g_assert (ch == IBUS_grave);
 
43
            g_assert (m_cursor == 0);
 
44
            m_text.insert (m_cursor++, ch);
 
45
            m_punct_mode = MODE_INIT;
 
46
            updatePunctCandidates (0);
 
47
            m_selected_puncts.clear ();
 
48
            m_selected_puncts.insert (m_selected_puncts.begin (), m_punct_candidates[0]);
 
49
            update ();
 
50
        }
 
51
        break;
 
52
    case MODE_INIT:
 
53
        {
 
54
            m_text.clear ();
 
55
            m_selected_puncts.clear ();
 
56
            m_cursor = 0;
 
57
        }
 
58
    case MODE_NORMAL:
 
59
        {
 
60
            m_text.insert (m_cursor, ch);
 
61
            updatePunctCandidates (ch);
 
62
            m_punct_mode = MODE_NORMAL;
 
63
            if (m_punct_candidates.size () > 0) {
 
64
                m_selected_puncts.insert (m_selected_puncts.begin () + m_cursor, m_punct_candidates[0]);
 
65
            }
 
66
            m_cursor ++;
 
67
            update ();
 
68
        }
 
69
        break;
 
70
    default:
 
71
        g_assert_not_reached ();
 
72
    }
 
73
 
 
74
    return TRUE;
 
75
}
 
76
 
 
77
inline gboolean
 
78
PunctEditor::processSpace (guint keyval, guint keycode, guint modifiers)
 
79
{
 
80
    if (m_punct_mode != MODE_INIT && m_punct_mode != MODE_NORMAL)
 
81
        return FALSE;
 
82
    if (cmshm_filter (modifiers) != 0)
 
83
        return TRUE;
 
84
    commit ();
 
85
    return TRUE;
 
86
}
 
87
 
 
88
gboolean
 
89
PunctEditor::processPunct (guint keyval, guint keycode, guint modifiers)
 
90
{
 
91
    if (cmshm_filter (modifiers) != 0)
 
92
        return TRUE;
 
93
 
 
94
    if (m_punct_mode == MODE_DISABLE) {
 
95
        if (keyval == IBUS_grave) {
 
96
            insert (keyval);
 
97
            return TRUE;
 
98
        }
 
99
    }
 
100
 
 
101
    g_assert (m_punct_mode == MODE_INIT || m_punct_mode == MODE_NORMAL);
 
102
 
 
103
    switch (keyval) {
 
104
    case IBUS_grave:        /* ` */
 
105
    case IBUS_asciitilde:   /* ~ */
 
106
    case IBUS_exclam:       /* ~ */
 
107
    case IBUS_at:           /* @ */
 
108
    case IBUS_numbersign:   /* # */
 
109
    case IBUS_dollar:       /* $ */
 
110
    case IBUS_percent:      /* % */
 
111
    case IBUS_asciicircum:  /* ^ */
 
112
    case IBUS_ampersand:    /* & */
 
113
    case IBUS_asterisk:     /* * */
 
114
    case IBUS_parenleft:    /* ( */
 
115
    case IBUS_parenright:   /* ) */
 
116
    case IBUS_minus:        /* - */
 
117
    case IBUS_underscore:   /* _ */
 
118
    case IBUS_equal:        /* = */
 
119
    case IBUS_plus:         /* + */
 
120
    case IBUS_bracketleft:  /* [ */
 
121
    case IBUS_bracketright: /* ] */
 
122
    case IBUS_braceleft:    /* { */
 
123
    case IBUS_braceright:   /* } */
 
124
    case IBUS_backslash:    /* \ */
 
125
    case IBUS_bar:          /* | */
 
126
    case IBUS_colon:        /* : */
 
127
    case IBUS_semicolon:    /* ; */
 
128
    case IBUS_apostrophe:   /* ' */
 
129
    case IBUS_quotedbl:     /* " */
 
130
    case IBUS_comma:        /* , */
 
131
    case IBUS_period:       /* . */
 
132
    case IBUS_less:         /* < */
 
133
    case IBUS_greater:      /* > */
 
134
    case IBUS_slash:        /* / */
 
135
    case IBUS_question:     /* ? */
 
136
    case IBUS_0...IBUS_9:
 
137
    case IBUS_a...IBUS_z:
 
138
    case IBUS_A...IBUS_Z:
 
139
        return insert (keyval);
 
140
    default:
 
141
        return FALSE;
 
142
    }
 
143
}
 
144
 
 
145
gboolean
 
146
PunctEditor::processKeyEvent (guint keyval, guint keycode, guint modifiers)
 
147
{
 
148
    modifiers &= (IBUS_SHIFT_MASK |
 
149
                  IBUS_CONTROL_MASK |
 
150
                  IBUS_MOD1_MASK |
 
151
                  IBUS_SUPER_MASK |
 
152
                  IBUS_HYPER_MASK |
 
153
                  IBUS_META_MASK |
 
154
                  IBUS_LOCK_MASK);
 
155
 
 
156
    switch (keyval) {
 
157
    case IBUS_space:
 
158
        return processSpace (keyval, keycode, modifiers);
 
159
 
 
160
    case IBUS_Return:
 
161
    case IBUS_KP_Enter:
 
162
        commit (m_text);
 
163
        return TRUE;
 
164
 
 
165
    case IBUS_Escape:
 
166
        reset ();
 
167
        return TRUE;
 
168
 
 
169
    case IBUS_BackSpace:
 
170
        removeCharBefore ();
 
171
        return TRUE;
 
172
 
 
173
    case IBUS_Delete:
 
174
    case IBUS_KP_Delete:
 
175
        removeCharAfter ();
 
176
        return TRUE;
 
177
 
 
178
    case IBUS_Left:
 
179
    case IBUS_KP_Left:
 
180
        moveCursorLeft ();
 
181
        return TRUE;
 
182
 
 
183
    case IBUS_Right:
 
184
    case IBUS_KP_Right:
 
185
        moveCursorRight ();
 
186
        return TRUE;
 
187
 
 
188
    case IBUS_Home:
 
189
    case IBUS_KP_Home:
 
190
        moveCursorToBegin ();
 
191
        return TRUE;
 
192
 
 
193
    case IBUS_End:
 
194
    case IBUS_KP_End:
 
195
        moveCursorToEnd ();
 
196
        return TRUE;
 
197
 
 
198
    case IBUS_Up:
 
199
    case IBUS_KP_Up:
 
200
        cursorUp ();
 
201
        return TRUE;
 
202
 
 
203
    case IBUS_Down:
 
204
    case IBUS_KP_Down:
 
205
        cursorDown ();
 
206
        return TRUE;
 
207
 
 
208
    case IBUS_Page_Up:
 
209
    case IBUS_KP_Page_Up:
 
210
        pageUp ();
 
211
        return TRUE;
 
212
 
 
213
    case IBUS_Page_Down:
 
214
    case IBUS_KP_Page_Down:
 
215
    case IBUS_Tab:
 
216
        pageDown ();
 
217
        return TRUE;
 
218
    default:
 
219
        return processPunct(keyval, keycode, modifiers);
 
220
    }
 
221
}
 
222
 
 
223
void
 
224
PunctEditor::pageUp (void)
 
225
{
 
226
    if (G_LIKELY (m_lookup_table.pageUp ())) {
 
227
        m_selected_puncts[m_cursor - 1] = m_punct_candidates[m_lookup_table.cursorPos ()];
 
228
        updateLookupTableFast (m_lookup_table, TRUE);
 
229
        updatePreeditText ();
 
230
        updateAuxiliaryText ();
 
231
    }
 
232
}
 
233
 
 
234
void
 
235
PunctEditor::pageDown (void)
 
236
{
 
237
    if (G_LIKELY (m_lookup_table.pageDown ())) {
 
238
        m_selected_puncts[m_cursor - 1] = m_punct_candidates[m_lookup_table.cursorPos ()];
 
239
        updateLookupTableFast (m_lookup_table, TRUE);
 
240
        updatePreeditText ();
 
241
        updateAuxiliaryText ();
 
242
    }
 
243
}
 
244
 
 
245
void
 
246
PunctEditor::cursorUp (void)
 
247
{
 
248
    if (G_LIKELY (m_lookup_table.cursorUp ())) {
 
249
        m_selected_puncts[m_cursor - 1] = m_punct_candidates[m_lookup_table.cursorPos ()];
 
250
        updateLookupTableFast (m_lookup_table, TRUE);
 
251
        updatePreeditText ();
 
252
        updateAuxiliaryText ();
 
253
    }
 
254
}
 
255
 
 
256
void
 
257
PunctEditor::cursorDown (void)
 
258
{
 
259
    if (G_LIKELY (m_lookup_table.cursorDown ())) {
 
260
        m_selected_puncts[m_cursor - 1] = m_punct_candidates[m_lookup_table.cursorPos ()];
 
261
        updateLookupTableFast (m_lookup_table, TRUE);
 
262
        updatePreeditText ();
 
263
        updateAuxiliaryText ();
 
264
    }
 
265
}
 
266
 
 
267
gboolean
 
268
PunctEditor::moveCursorLeft (void)
 
269
{
 
270
    if (G_UNLIKELY (m_cursor == 0))
 
271
        return FALSE;
 
272
    m_cursor --;
 
273
    if (m_cursor == 0)  {
 
274
        m_punct_candidates.clear ();
 
275
        fillLookupTable ();
 
276
    }
 
277
    else {
 
278
        updatePunctCandidates (m_text[m_cursor - 1]);
 
279
        /* restore cursor pos */
 
280
        std::vector<const gchar *>::iterator it;
 
281
        it = std::find (m_punct_candidates.begin (),
 
282
                        m_punct_candidates.end (),
 
283
                        m_selected_puncts[m_cursor - 1]);
 
284
        g_assert (it != m_punct_candidates.end ());
 
285
        m_lookup_table.setCursorPos (it - m_punct_candidates.begin ());
 
286
    }
 
287
    update();
 
288
    return TRUE;
 
289
}
 
290
 
 
291
gboolean
 
292
PunctEditor::moveCursorRight (void)
 
293
{
 
294
    if (G_UNLIKELY (m_cursor == m_text.length ()))
 
295
        return FALSE;
 
296
    m_cursor ++;
 
297
    updatePunctCandidates (m_text[m_cursor - 1]);
 
298
 
 
299
    /* restore cursor pos */
 
300
    std::vector<const gchar *>::iterator it;
 
301
    it = std::find (m_punct_candidates.begin (),
 
302
                    m_punct_candidates.end (),
 
303
                    m_selected_puncts[m_cursor - 1]);
 
304
    g_assert (it != m_punct_candidates.end ());
 
305
    m_lookup_table.setCursorPos (it - m_punct_candidates.begin ());
 
306
 
 
307
    update();
 
308
    return TRUE;
 
309
}
 
310
 
 
311
gboolean
 
312
PunctEditor::moveCursorToBegin (void)
 
313
{
 
314
    if (G_UNLIKELY (m_cursor == 0))
 
315
        return FALSE;
 
316
 
 
317
    g_assert (m_punct_mode == MODE_NORMAL);
 
318
    m_cursor = 0;
 
319
    m_punct_candidates.clear ();
 
320
    fillLookupTable ();
 
321
    update ();
 
322
 
 
323
    return TRUE;
 
324
}
 
325
 
 
326
gboolean
 
327
PunctEditor::moveCursorToEnd (void)
 
328
{
 
329
    if (G_UNLIKELY (m_cursor == m_text.length ()))
 
330
        return FALSE;
 
331
 
 
332
    g_assert (m_punct_mode == MODE_NORMAL);
 
333
    m_cursor = m_text.length ();
 
334
    updatePunctCandidates (m_text[m_cursor - 1]);
 
335
 
 
336
    /* restore cursor pos */
 
337
    std::vector<const gchar *>::iterator it;
 
338
    it = std::find (m_punct_candidates.begin (),
 
339
                    m_punct_candidates.end (),
 
340
                    m_selected_puncts[m_cursor - 1]);
 
341
    g_assert (it != m_punct_candidates.end ());
 
342
    m_lookup_table.setCursorPos (it - m_punct_candidates.begin ());
 
343
 
 
344
    update();
 
345
    return TRUE;
 
346
}
 
347
 
 
348
gboolean
 
349
PunctEditor::removeCharBefore (void)
 
350
{
 
351
    if (G_UNLIKELY (m_cursor == 0))
 
352
        return FALSE;
 
353
 
 
354
    m_cursor --;
 
355
    m_selected_puncts.erase (m_selected_puncts.begin () + m_cursor);
 
356
    m_text.erase (m_cursor, 1);
 
357
    if (m_text.empty()) {
 
358
        reset ();
 
359
    }
 
360
    else {
 
361
        if (m_cursor > 0) {
 
362
 
 
363
            updatePunctCandidates (m_text[m_cursor - 1]);
 
364
            /* restore cursor pos */
 
365
            std::vector<const gchar *>::iterator it;
 
366
            it = std::find (m_punct_candidates.begin (),
 
367
                            m_punct_candidates.end (),
 
368
                            m_selected_puncts[m_cursor - 1]);
 
369
            g_assert (it != m_punct_candidates.end ());
 
370
            m_lookup_table.setCursorPos (it - m_punct_candidates.begin ());
 
371
        }
 
372
        else {
 
373
            m_punct_candidates.clear ();
 
374
            fillLookupTable ();
 
375
        }
 
376
    }
 
377
 
 
378
    update();
 
379
 
 
380
    return TRUE;
 
381
}
 
382
 
 
383
gboolean
 
384
PunctEditor::removeCharAfter (void)
 
385
{
 
386
    if (G_UNLIKELY (m_cursor == m_text.length ()))
 
387
        return FALSE;
 
388
    m_selected_puncts.erase (m_selected_puncts.begin () + m_cursor);
 
389
    m_text.erase (m_cursor, 1);
 
390
    if (m_text.empty()) {
 
391
        reset ();
 
392
    }
 
393
 
 
394
    update();
 
395
 
 
396
    return TRUE;
 
397
}
 
398
 
 
399
void
 
400
PunctEditor::reset (void)
 
401
{
 
402
    m_punct_mode = MODE_DISABLE;
 
403
    m_selected_puncts.clear ();
 
404
    m_punct_candidates.clear ();
 
405
    fillLookupTable ();
 
406
    Editor::reset ();
 
407
}
 
408
 
 
409
void
 
410
PunctEditor::candidateClicked (guint index, guint button, guint state)
 
411
{
 
412
    selectCandidateInPage(index);
 
413
}
 
414
 
 
415
inline void
 
416
PunctEditor::commit (const gchar *str)
 
417
{
 
418
    StaticText text(str);
 
419
    commitText (text);
 
420
    reset ();
 
421
}
 
422
 
 
423
void
 
424
PunctEditor::commit (void)
 
425
{
 
426
    m_buffer.clear ();
 
427
    for (std::vector<const gchar *>::iterator it = m_selected_puncts.begin ();
 
428
         it != m_selected_puncts.end (); it++) {
 
429
        m_buffer << *it;
 
430
    }
 
431
 
 
432
    commit (m_buffer);
 
433
}
 
434
 
 
435
inline gboolean
 
436
PunctEditor::selectCandidate (guint i)
 
437
{
 
438
    switch (m_punct_mode) {
 
439
    case MODE_INIT:
 
440
        {
 
441
            g_assert (m_cursor == 1);
 
442
            m_lookup_table.setCursorPos (i);
 
443
            m_selected_puncts[m_cursor - 1] = m_punct_candidates[i];
 
444
            commit ();
 
445
            return TRUE;
 
446
        }
 
447
    case MODE_NORMAL:
 
448
        {
 
449
            m_lookup_table.setCursorPos (i);
 
450
            m_selected_puncts[m_cursor - 1] = m_punct_candidates[i];
 
451
 
 
452
            /* if it is the last punct, commit the result */
 
453
            if (m_cursor == m_text.length ()) {
 
454
                commit ();
 
455
            }
 
456
            else {
 
457
                moveCursorRight ();
 
458
            }
 
459
            return TRUE;
 
460
        }
 
461
    default:
 
462
        g_assert_not_reached ();
 
463
    }
 
464
 
 
465
    return FALSE;
 
466
}
 
467
 
 
468
inline gboolean
 
469
PunctEditor::selectCandidateInPage (guint i)
 
470
{
 
471
    guint page_size = m_lookup_table.pageSize ();
 
472
    guint cursor_pos = m_lookup_table.cursorPos ();
 
473
 
 
474
    if (G_UNLIKELY (i >= page_size))
 
475
        return FALSE;
 
476
 
 
477
    i += (cursor_pos / page_size) * page_size;
 
478
 
 
479
    return selectCandidate (i);
 
480
}
 
481
 
 
482
void
 
483
PunctEditor::update (void)
 
484
{
 
485
    updateLookupTable ();
 
486
    updatePreeditText ();
 
487
    updateAuxiliaryText ();
 
488
}
 
489
 
 
490
void
 
491
PunctEditor::fillLookupTable (void)
 
492
{
 
493
    m_lookup_table.clear ();
 
494
    m_lookup_table.setPageSize (m_config.pageSize ());
 
495
    m_lookup_table.setOrientation (m_config.orientation ());
 
496
 
 
497
    for (std::vector<const gchar *>::iterator it = m_punct_candidates.begin ();
 
498
         it != m_punct_candidates.end (); it++) {
 
499
        StaticText text (*it);
 
500
        // text.appendAttribute (IBUS_ATTR_TYPE_FOREGROUND, 0x004466, 0, -1);
 
501
        m_lookup_table.appendCandidate (text);
 
502
    }
 
503
}
 
504
 
 
505
void
 
506
PunctEditor::updateLookupTable (void)
 
507
{
 
508
    if (m_lookup_table.size ()) {
 
509
        Editor::updateLookupTable (m_lookup_table, TRUE);
 
510
    }
 
511
    else {
 
512
        hideLookupTable ();
 
513
    }
 
514
}
 
515
 
 
516
static int
 
517
punct_cmp (const void *p1, const void *p2)
 
518
{
 
519
    const gint s1 = (gint)(glong) p1;
 
520
    const gchar *s2 = **(gchar ***) p2;
 
521
    return s1 - s2[0];
 
522
}
 
523
 
 
524
void
 
525
PunctEditor::updatePunctCandidates (gchar ch)
 
526
{
 
527
    const gchar *** brs;
 
528
    const gchar ** res;
 
529
 
 
530
    m_punct_candidates.clear();
 
531
 
 
532
    brs = (const gchar ***) std::bsearch ((void *) ch,
 
533
                                          punct_table,
 
534
                                          G_N_ELEMENTS (punct_table),
 
535
                                          sizeof(punct_table[0]),
 
536
                                          punct_cmp);
 
537
    if (brs != NULL) {
 
538
        for (res = (*brs) + 1; *res != NULL; ++res) {
 
539
            m_punct_candidates.push_back (*res);
 
540
        }
 
541
    }
 
542
    fillLookupTable ();
 
543
}
 
544
 
 
545
void
 
546
PunctEditor::updateAuxiliaryText (void)
 
547
{
 
548
    switch (m_punct_mode) {
 
549
    case MODE_DISABLE:
 
550
        hideAuxiliaryText ();
 
551
        break;
 
552
    case MODE_INIT:
 
553
        {
 
554
            m_buffer = "`";
 
555
            StaticText aux_text (m_buffer);
 
556
            Editor::updateAuxiliaryText (aux_text, TRUE);
 
557
        }
 
558
        break;
 
559
    case MODE_NORMAL:
 
560
        {
 
561
            if (m_cursor == 0) {
 
562
                hideAuxiliaryText ();
 
563
            }
 
564
            else {
 
565
                m_buffer.clear ();
 
566
                for (String::iterator i = m_text.begin (); i != m_text.end (); ++i) {
 
567
                    if (i - m_text.begin () == (gint) m_cursor)
 
568
                        m_buffer << '|';
 
569
                    m_buffer << *i;
 
570
                }
 
571
                if (m_text.end () - m_text.begin () == (gint) m_cursor)
 
572
                    m_buffer << '|';
 
573
 
 
574
                StaticText aux_text (m_buffer);
 
575
                Editor::updateAuxiliaryText (aux_text, TRUE);
 
576
            }
 
577
        }
 
578
        break;
 
579
    default:
 
580
        g_assert_not_reached ();
 
581
    }
 
582
}
 
583
 
 
584
void
 
585
PunctEditor::updatePreeditText (void)
 
586
{
 
587
    switch (m_punct_mode) {
 
588
    case MODE_DISABLE:
 
589
        hidePreeditText ();
 
590
        break;
 
591
    case MODE_INIT:
 
592
        {
 
593
            m_buffer = m_punct_candidates[m_lookup_table.cursorPos ()];
 
594
            StaticText preedit_text (m_buffer);
 
595
            /* underline */
 
596
            preedit_text.appendAttribute (IBUS_ATTR_TYPE_UNDERLINE, IBUS_ATTR_UNDERLINE_SINGLE, 0, -1);
 
597
            Editor::updatePreeditText (preedit_text, m_cursor, TRUE);
 
598
        }
 
599
        break;
 
600
    case MODE_NORMAL:
 
601
        {
 
602
            m_buffer.clear ();
 
603
            for (std::vector<const gchar *>::iterator it = m_selected_puncts.begin ();
 
604
                 it != m_selected_puncts.end (); it++) {
 
605
                m_buffer << *it;
 
606
            }
 
607
            StaticText preedit_text (m_buffer);
 
608
            /* underline */
 
609
            preedit_text.appendAttribute (IBUS_ATTR_TYPE_UNDERLINE, IBUS_ATTR_UNDERLINE_SINGLE, 0, -1);
 
610
            Editor::updatePreeditText (preedit_text, m_cursor, TRUE);
 
611
        }
 
612
        break;
 
613
    default:
 
614
        g_assert_not_reached ();
 
615
    }
 
616
}
 
617
 
 
618
};
 
619
 
 
620