~ubuntu-branches/ubuntu/quantal/sunpinyin/quantal

« back to all changes in this revision

Viewing changes to wrapper/ibus/src/sunpinyin_engine.cpp

  • Committer: Package Import Robot
  • Author(s): YunQiang Su
  • Date: 2012-04-11 03:06:40 UTC
  • mfrom: (1.1.4) (1.2.8 sid)
  • Revision ID: package-import@ubuntu.com-20120411030640-8mxepz5e6wffy87c
Tags: 2.0.3+git20120404-1
* Medium urgency for fixing RC bug.
* New upstream commit: fix FTBFS with gcc-4.7 (Closes: #667385).
* Add Multi-Arch: same to libsunpinyin3, -dev and -dbg.
* Add YunQiang Su to uploaders.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
3
 
 *
4
 
 * The contents of this file are subject to the terms of either the GNU Lesser
5
 
 * General Public License Version 2.1 only ("LGPL") or the Common Development and
6
 
 * Distribution License ("CDDL")(collectively, the "License"). You may not use this
7
 
 * file except in compliance with the License. You can obtain a copy of the CDDL at
8
 
 * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
9
 
 * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
10
 
 * specific language governing permissions and limitations under the License. When
11
 
 * distributing the software, include this License Header Notice in each file and
12
 
 * include the full text of the License in the License file as well as the
13
 
 * following notice:
14
 
 *
15
 
 * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
16
 
 * (CDDL)
17
 
 * For Covered Software in this distribution, this License shall be governed by the
18
 
 * laws of the State of California (excluding conflict-of-law provisions).
19
 
 * Any litigation relating to this License shall be subject to the jurisdiction of
20
 
 * the Federal Courts of the Northern District of California and the state courts
21
 
 * of the State of California, with venue lying in Santa Clara County, California.
22
 
 *
23
 
 * Contributor(s):
24
 
 *
25
 
 * If you wish your version of this file to be governed by only the CDDL or only
26
 
 * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
27
 
 * include this software in this distribution under the [CDDL or LGPL Version 2.1]
28
 
 * license." If you don't indicate a single choice of license, a recipient has the
29
 
 * option to distribute your version of this file under either the CDDL or the LGPL
30
 
 * Version 2.1, or to extend the choice of license to its licensees as provided
31
 
 * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
32
 
 * Version 2 license, then the option applies only if the new code is made subject
33
 
 * to such option by the copyright holder.
34
 
 */
35
 
 
36
 
#include <cassert>
37
 
#include <algorithm>
38
 
#include <sstream>
39
 
 
40
 
#include <sunpinyin.h>
41
 
 
42
 
#include "sunpinyin_property.h"
43
 
#include "sunpinyin_lookup_table.h"
44
 
#include "sunpinyin_config.h"
45
 
#include "sunpinyin_config_keys.h"
46
 
#include "imi_ibus_win.h"
47
 
#include "ibus_portable.h"
48
 
#include "sunpinyin_engine.h"
49
 
 
50
 
extern ibus::Config config;
51
 
 
52
 
SunPinyinEngine::SunPinyinEngine(IBusEngine *engine)
53
 
    : m_engine(engine),
54
 
      m_status_prop(SunPinyinProperty::create_status_prop(engine)),
55
 
      m_letter_prop(SunPinyinProperty::create_letter_prop(engine)),
56
 
      m_punct_prop(SunPinyinProperty::create_punct_prop(engine)),
57
 
      m_wh(NULL),
58
 
      m_pv(NULL),
59
 
      m_hotkey_profile(NULL)
60
 
{
61
 
    CSunpinyinSessionFactory& factory = CSunpinyinSessionFactory::getFactory();
62
 
 
63
 
    CSunpinyinSessionFactory::EPyScheme pinyin_scheme =
64
 
        m_config.get_py_scheme(CSunpinyinSessionFactory::QUANPIN);
65
 
    factory.setPinyinScheme(pinyin_scheme);
66
 
    if (pinyin_scheme == CSunpinyinSessionFactory::QUANPIN) {
67
 
        update_fuzzy_pinyins();
68
 
        update_correction_pinyins();
69
 
        update_fuzzy_segs();
70
 
    } else {
71
 
        update_shuangpin_type();
72
 
    }
73
 
    update_user_data_dir();
74
 
    update_punct_mappings();
75
 
 
76
 
    factory.setCandiWindowSize(m_config.get(CONFIG_GENERAL_PAGE_SIZE, 10));
77
 
 
78
 
    m_pv = factory.createSession();
79
 
    if (!m_pv)
80
 
        return;
81
 
 
82
 
    m_hotkey_profile = new CHotkeyProfile();
83
 
    m_pv->setHotkeyProfile(m_hotkey_profile);
84
 
 
85
 
    m_wh = new CIBusWinHandler(this);
86
 
    m_pv->attachWinHandler(m_wh);
87
 
 
88
 
    m_prop_list = ibus_prop_list_new();
89
 
 
90
 
    ibus_prop_list_append(m_prop_list, m_status_prop);
91
 
    ibus_prop_list_append(m_prop_list, m_letter_prop);
92
 
    ibus_prop_list_append(m_prop_list, m_punct_prop);
93
 
    ibus_prop_list_append(m_prop_list, m_setup_prop);
94
 
 
95
 
    update_config();
96
 
}
97
 
 
98
 
SunPinyinEngine::~SunPinyinEngine()
99
 
{
100
 
    if (m_pv) {
101
 
        CSunpinyinSessionFactory& factory =
102
 
            CSunpinyinSessionFactory::getFactory();
103
 
        factory.destroySession(m_pv);
104
 
    }
105
 
 
106
 
    delete m_wh;
107
 
    delete m_hotkey_profile;
108
 
}
109
 
 
110
 
static CKeyEvent
111
 
translate_key(guint key_val, guint /*key_code*/, guint modifiers)
112
 
{
113
 
    // XXX: may need to move this logic into CKeyEvent
114
 
    if (key_val > 0x20 && key_val < 0x7f // isprint(key_val) && !isspace(key_val)
115
 
        && !(modifiers & IM_CTRL_MASK)) {
116
 
        // we only care about key_val here
117
 
        return CKeyEvent(key_val, key_val, modifiers);
118
 
    } else {
119
 
        // what matters is key_code, but ibus sents me key_code as key_val
120
 
        return CKeyEvent(key_val, 0, modifiers);
121
 
    }
122
 
}
123
 
 
124
 
gboolean
125
 
SunPinyinEngine::process_key_event (guint key_val,
126
 
                                    guint key_code,
127
 
                                    guint modifiers)
128
 
{
129
 
    CKeyEvent key = translate_key(key_val, key_code, modifiers);
130
 
 
131
 
    if (!m_pv->getStatusAttrValue(CIBusWinHandler::STATUS_ID_CN)) {
132
 
        // we are in English input mode
133
 
        if (!m_hotkey_profile->isModeSwitchKey(key)) {
134
 
            m_hotkey_profile->rememberLastKey(key);
135
 
            return FALSE;
136
 
        }
137
 
    } else if (m_hotkey_profile->isModeSwitchKey(key)) {
138
 
        m_pv->onKeyEvent(CKeyEvent(IM_VK_ENTER, 0, 0));
139
 
        m_pv->setStatusAttrValue(CIMIWinHandler::STATUS_ID_CN, false);
140
 
        return TRUE;
141
 
    }
142
 
 
143
 
    return m_pv->onKeyEvent(key);
144
 
}
145
 
 
146
 
void
147
 
SunPinyinEngine::focus_in ()
148
 
{
149
 
    ibus_engine_register_properties(m_engine, m_prop_list);
150
 
    m_pv->updateWindows(CIMIView::PREEDIT_MASK | CIMIView::CANDIDATE_MASK);
151
 
}
152
 
 
153
 
void
154
 
SunPinyinEngine::focus_out ()
155
 
{
156
 
    reset();
157
 
}
158
 
 
159
 
void
160
 
SunPinyinEngine::reset ()
161
 
{
162
 
    m_pv->updateWindows(m_pv->clearIC());
163
 
}
164
 
 
165
 
void
166
 
SunPinyinEngine::enable ()
167
 
{
168
 
    bool is_cn = m_config.is_initial_mode_cn();
169
 
    m_status_prop.update(is_cn);
170
 
    m_pv->setStatusAttrValue(CIMIWinHandler::STATUS_ID_CN, is_cn);
171
 
 
172
 
    bool is_letter_full = m_config.is_initial_letter_full();
173
 
    m_letter_prop.update(is_letter_full);
174
 
    m_pv->setStatusAttrValue(CIMIWinHandler::STATUS_ID_FULLSYMBOL, is_letter_full);
175
 
 
176
 
    bool is_punct_full = m_config.is_initial_punct_full();
177
 
    m_punct_prop.update(is_punct_full);
178
 
    m_pv->setStatusAttrValue(CIMIWinHandler::STATUS_ID_FULLPUNC, is_punct_full);
179
 
}
180
 
 
181
 
void
182
 
SunPinyinEngine::disable ()
183
 
{
184
 
}
185
 
 
186
 
void
187
 
SunPinyinEngine::page_up ()
188
 
{
189
 
    m_pv->onCandidatePageRequest(-1, true /* relative */);
190
 
}
191
 
 
192
 
void
193
 
SunPinyinEngine::page_down ()
194
 
{
195
 
    m_pv->onCandidatePageRequest(1, true /* relative */);
196
 
}
197
 
 
198
 
void
199
 
SunPinyinEngine::property_activate (const std::string& property, unsigned /*state*/)
200
 
{
201
 
    if (m_status_prop.toggle(property)) {
202
 
        m_pv->setStatusAttrValue(CIMIWinHandler::STATUS_ID_CN,
203
 
                                 m_status_prop.state());
204
 
    } else if (m_letter_prop.toggle(property)) {
205
 
        m_pv->setStatusAttrValue(CIMIWinHandler::STATUS_ID_FULLSYMBOL,
206
 
                                 m_letter_prop.state());
207
 
    } else if (m_punct_prop.toggle(property)) {
208
 
        m_pv->setStatusAttrValue(CIMIWinHandler::STATUS_ID_FULLPUNC,
209
 
                                 m_punct_prop.state());
210
 
    } else {
211
 
        // try to launch the setup UI
212
 
        m_setup_prop.launch(property);
213
 
    }
214
 
}
215
 
 
216
 
void
217
 
SunPinyinEngine::candidate_clicked (guint index)
218
 
{
219
 
    m_pv->onCandidateSelectRequest(index);
220
 
}
221
 
 
222
 
void
223
 
SunPinyinEngine::cursor_up ()
224
 
{
225
 
    if (m_lookup_table.cursor_up()) {
226
 
        update_lookup_table();
227
 
    }
228
 
}
229
 
 
230
 
void
231
 
SunPinyinEngine::cursor_down ()
232
 
{
233
 
    if (m_lookup_table.cursor_down()) {
234
 
        update_lookup_table();
235
 
    }
236
 
}
237
 
 
238
 
bool
239
 
SunPinyinEngine::onConfigChanged(const COptionEvent& event)
240
 
{
241
 
    if (event.name == CONFIG_GENERAL_MEMORY_POWER) {
242
 
        update_history_power();
243
 
    } else if (event.name == CONFIG_GENERAL_PAGE_SIZE) {
244
 
        update_cand_window_size();
245
 
    } else if (event.name == CONFIG_GENERAL_CHARSET_LEVEL) {
246
 
        update_charset_level();
247
 
    } else if (event.name == CONFIG_GENERAL_MAX_BEST) {
248
 
        update_max_best();
249
 
    } else if (event.name == CONFIG_GENERAL_MAX_TAIL_CANDIDATE) {
250
 
        update_max_tail_candidate();
251
 
    } else if (event.name == CONFIG_KEYBOARD_MODE_SWITCH) {
252
 
        update_mode_key();
253
 
    } else if (event.name == CONFIG_KEYBOARD_PUNCT_SWITCH) {
254
 
        update_punct_key();
255
 
    } else if (event.name == CONFIG_KEYBOARD_PAGE_COMMA) {
256
 
        update_page_key_comma();
257
 
    } else if (event.name == CONFIG_KEYBOARD_PAGE_MINUS) {
258
 
        update_page_key_minus();
259
 
    } else if (event.name == CONFIG_KEYBOARD_PAGE_BRACKET) {
260
 
        update_page_key_bracket();
261
 
    } else if (event.name == CONFIG_QUANPIN_FUZZYSEGS_ENABLED) {
262
 
        update_fuzzy_segs();
263
 
    } else if (event.name == CONFIG_KEYBOARD_CANCEL_BACKSPACE) {
264
 
        update_cancel_with_backspace();
265
 
    } else if (event.name == CONFIG_KEYBOARD_SMARK_PUNCT) {
266
 
        update_smart_punc();
267
 
    }
268
 
 
269
 
    return false;
270
 
}
271
 
 
272
 
void
273
 
SunPinyinEngine::update_config()
274
 
{
275
 
    update_history_power();
276
 
    update_cand_window_size();
277
 
    update_max_best();
278
 
    update_max_tail_candidate();
279
 
    update_charset_level();
280
 
    update_page_key_minus();
281
 
    update_page_key_comma();
282
 
    update_page_key_bracket();
283
 
    update_mode_key();
284
 
    update_punct_key();
285
 
    update_cancel_with_backspace();
286
 
    update_smart_punc();
287
 
    update_punct_mappings();
288
 
    update_candi_delete_key();
289
 
    // update_quanpin_config();
290
 
    // update_shuangpin_config();
291
 
}
292
 
 
293
 
void
294
 
SunPinyinEngine::commit_string (const std::wstring& str)
295
 
{
296
 
    IBusText *text;
297
 
    text = ibus_text_new_from_ucs4((const gunichar*) str.c_str());
298
 
    ibus_engine_commit_text(m_engine, text);
299
 
}
300
 
 
301
 
void
302
 
SunPinyinEngine::update_candidates(const ICandidateList& cl)
303
 
{
304
 
    if (m_lookup_table.update_candidates(cl) > 0)
305
 
        update_lookup_table();
306
 
    else
307
 
        ibus_engine_hide_lookup_table (m_engine);
308
 
}
309
 
 
310
 
void
311
 
SunPinyinEngine::update_lookup_table()
312
 
{
313
 
    ibus_engine_update_lookup_table(m_engine, m_lookup_table, TRUE);
314
 
}
315
 
 
316
 
bool
317
 
SunPinyinEngine::is_valid() const
318
 
{
319
 
    return m_pv != NULL;
320
 
}
321
 
 
322
 
static int
323
 
find_embed_preedit_pos(const IPreeditString& preedit)
324
 
{
325
 
    int mask = IPreeditString::USER_CHOICE & IPreeditString::HANZI_CHAR;
326
 
    for (size_t i = 0; i < preedit.charTypeSize(); i++) {
327
 
        if ((preedit.charTypeAt(i) & mask) == 0) {
328
 
            return i;
329
 
        }
330
 
    }
331
 
    return preedit.charTypeSize();
332
 
}
333
 
 
334
 
enum {ORANGE = 0xE76F00, GRAY_BLUE = 0x35556B, WHITE = 0xFFFFFF,
335
 
      BLACK = 0x000000};
336
 
 
337
 
void
338
 
SunPinyinEngine::update_preedit_string(const IPreeditString& preedit)
339
 
{
340
 
    if (preedit.size() > 0) {
341
 
        wstring wstr(preedit.string());
342
 
        int embed_pos = find_embed_preedit_pos(preedit);
343
 
        wstring embed_wstr = wstr.substr(0, embed_pos);
344
 
        wstring preedit_wstr = wstr.substr(embed_pos);
345
 
        const gunichar* embed_cstr = (const gunichar*) embed_wstr.c_str();
346
 
        const gunichar* preedit_cstr = (const gunichar*) preedit_wstr.c_str();
347
 
        IBusText* preedit_text = ibus_text_new_from_ucs4(preedit_cstr);
348
 
        int caret = preedit.caret() - embed_pos;
349
 
 
350
 
        if (preedit.caret() < preedit.size()) {
351
 
            ibus_text_append_attribute(preedit_text, IBUS_ATTR_TYPE_FOREGROUND,
352
 
                                       WHITE, caret, preedit_wstr.size());
353
 
            ibus_text_append_attribute(preedit_text, IBUS_ATTR_TYPE_BACKGROUND,
354
 
                                       GRAY_BLUE, caret, preedit_wstr.size());
355
 
        }
356
 
        ibus_engine_update_auxiliary_text(m_engine, preedit_text, TRUE);
357
 
 
358
 
        ibus_engine_update_preedit_text(m_engine,
359
 
                                        ibus_text_new_from_ucs4(embed_cstr),
360
 
                                        preedit.caret(), TRUE);
361
 
 
362
 
    } else {
363
 
        ibus_engine_hide_auxiliary_text(m_engine);
364
 
        ibus_engine_hide_preedit_text(m_engine);
365
 
    }
366
 
}
367
 
 
368
 
void
369
 
SunPinyinEngine::update_status_property(bool cn)
370
 
{
371
 
    m_status_prop.update(cn);
372
 
}
373
 
 
374
 
void
375
 
SunPinyinEngine::update_punct_property(bool full)
376
 
{
377
 
    m_punct_prop.update(full);
378
 
}
379
 
 
380
 
void
381
 
SunPinyinEngine::update_letter_property(bool full)
382
 
{
383
 
    m_letter_prop.update(full);
384
 
}
385
 
 
386
 
void
387
 
SunPinyinEngine::update_history_power()
388
 
{
389
 
    unsigned power = m_config.get(CONFIG_GENERAL_MEMORY_POWER, 3);
390
 
    CIMIContext* ic = m_pv->getIC();
391
 
    assert(ic);
392
 
    ic->setHistoryPower(power);
393
 
}
394
 
 
395
 
void
396
 
SunPinyinEngine::update_charset_level()
397
 
{
398
 
    unsigned charset = m_config.get(CONFIG_GENERAL_CHARSET_LEVEL, GBK);
399
 
    CIMIContext* ic = m_pv->getIC();
400
 
    assert(ic);
401
 
    charset &= 3;               // charset can only be 0,1,2 or 3
402
 
    ic->setCharsetLevel(charset);
403
 
}
404
 
 
405
 
void
406
 
SunPinyinEngine::update_cand_window_size()
407
 
{
408
 
    unsigned size = m_config.get(CONFIG_GENERAL_PAGE_SIZE, 10);
409
 
    m_pv->setCandiWindowSize(size);
410
 
}
411
 
 
412
 
void
413
 
SunPinyinEngine::update_mode_key()
414
 
{
415
 
    std::string mode_switch("Shift");
416
 
    mode_switch = m_config.get(CONFIG_KEYBOARD_MODE_SWITCH, mode_switch);
417
 
 
418
 
    CKeyEvent shift_l  (IM_VK_SHIFT_L, 0, IM_SHIFT_MASK|IM_RELEASE_MASK);
419
 
    CKeyEvent shift_r  (IM_VK_SHIFT_R, 0, IM_SHIFT_MASK|IM_RELEASE_MASK);
420
 
    CKeyEvent control_l(IM_VK_CONTROL_L, 0, IM_CTRL_MASK|IM_RELEASE_MASK);
421
 
    CKeyEvent control_r(IM_VK_CONTROL_R, 0, IM_CTRL_MASK|IM_RELEASE_MASK);
422
 
 
423
 
    if (mode_switch == "Shift") {
424
 
        m_hotkey_profile->removeModeSwitchKey(control_l);
425
 
        m_hotkey_profile->removeModeSwitchKey(control_r);
426
 
        m_hotkey_profile->addModeSwitchKey(shift_l);
427
 
        m_hotkey_profile->addModeSwitchKey(shift_r);
428
 
    } else if (mode_switch == "Control") {
429
 
        m_hotkey_profile->removeModeSwitchKey(shift_l);
430
 
        m_hotkey_profile->removeModeSwitchKey(shift_r);
431
 
        m_hotkey_profile->addModeSwitchKey(control_l);
432
 
        m_hotkey_profile->addModeSwitchKey(control_r);
433
 
    }
434
 
}
435
 
 
436
 
void
437
 
SunPinyinEngine::update_punct_key()
438
 
{
439
 
    std::string punct_switch("ControlComma");
440
 
    punct_switch = m_config.get(CONFIG_KEYBOARD_PUNCT_SWITCH, punct_switch);
441
 
    if (punct_switch == "ControlComma") {
442
 
        m_hotkey_profile->setPunctSwitchKey(CKeyEvent(IM_VK_COMMA, 0, IM_CTRL_MASK));
443
 
    } else if (punct_switch == "ControlPeriod") {
444
 
        m_hotkey_profile->setPunctSwitchKey(CKeyEvent(IM_VK_PERIOD, 0, IM_CTRL_MASK));
445
 
    }
446
 
}
447
 
 
448
 
void
449
 
SunPinyinEngine::update_page_key_minus()
450
 
{
451
 
    update_page_key(CONFIG_KEYBOARD_PAGE_MINUS, false,
452
 
                    IM_VK_MINUS, IM_VK_EQUALS);
453
 
}
454
 
 
455
 
void
456
 
SunPinyinEngine::update_page_key_comma()
457
 
{
458
 
    update_page_key(CONFIG_KEYBOARD_PAGE_COMMA, false,
459
 
                    IM_VK_COMMA, IM_VK_PERIOD);
460
 
}
461
 
 
462
 
void
463
 
SunPinyinEngine::update_page_key_bracket()
464
 
{
465
 
    update_page_key(CONFIG_KEYBOARD_PAGE_BRACKET, false,
466
 
                    IM_VK_OPEN_BRACKET, IM_VK_CLOSE_BRACKET);
467
 
}
468
 
 
469
 
void
470
 
SunPinyinEngine::update_page_key(const char* conf_key, bool default_val,
471
 
                            unsigned page_up, unsigned page_down)
472
 
{
473
 
    bool enabled = m_config.get(conf_key, default_val);
474
 
 
475
 
    if (enabled) {
476
 
        m_hotkey_profile->addPageUpKey(CKeyEvent(page_up, 0));
477
 
        m_hotkey_profile->addPageDownKey(CKeyEvent(page_down, 0));
478
 
    } else {
479
 
        m_hotkey_profile->removePageUpKey(CKeyEvent(page_up, 0));
480
 
        m_hotkey_profile->removePageDownKey(CKeyEvent(page_down, 0));
481
 
    }
482
 
}
483
 
 
484
 
void
485
 
SunPinyinEngine::update_cancel_with_backspace()
486
 
{
487
 
    bool enabled = m_config.get(CONFIG_KEYBOARD_CANCEL_BACKSPACE, true);
488
 
    m_pv->setCancelOnBackspace(enabled);
489
 
}
490
 
 
491
 
void
492
 
SunPinyinEngine::update_smart_punc()
493
 
{
494
 
    m_pv->setSmartPunct(m_config.get(CONFIG_KEYBOARD_SMARK_PUNCT, true));
495
 
}
496
 
 
497
 
void
498
 
SunPinyinEngine::update_max_best()
499
 
{
500
 
    if (m_pv->getIC() == NULL) {
501
 
        return;
502
 
    }
503
 
    int oldval = (int) m_pv->getIC()->getMaxBest();
504
 
    m_pv->getIC()->setMaxBest(m_config.get(CONFIG_GENERAL_MAX_BEST, oldval));
505
 
}
506
 
 
507
 
void
508
 
SunPinyinEngine::update_max_tail_candidate()
509
 
{
510
 
    if (m_pv->getIC() == NULL) {
511
 
        return;
512
 
    }
513
 
    int oldval = (int) m_pv->getIC()->getMaxTailCandidateNum();
514
 
    m_pv->getIC()->setMaxTailCandidateNum(
515
 
        m_config.get(CONFIG_GENERAL_MAX_TAIL_CANDIDATE, oldval));
516
 
}
517
 
 
518
 
string_pairs parse_pairs(const std::vector<std::string>& strings)
519
 
{
520
 
    string_pairs pairs;
521
 
    for (std::vector<std::string>::const_iterator pair = strings.begin();
522
 
         pair != strings.end(); ++pair) {
523
 
 
524
 
        std::string::size_type found = pair->find(':');
525
 
        if (found == pair->npos || pair->length() < 3)
526
 
            continue;
527
 
        if (found == 0 && (*pair)[0] == ':')
528
 
            found = 1;
529
 
 
530
 
        pairs.push_back(make_pair(pair->substr(0, found),
531
 
                                  pair->substr(found+1)));
532
 
    }
533
 
    return pairs;
534
 
}
535
 
 
536
 
// the mappings in default_pairs will override the ones in user_pairs
537
 
string_pairs merge_pairs(const string_pairs& default_pairs,
538
 
                         const string_pairs& user_pairs)
539
 
{
540
 
    typedef std::map<std::string, int> Indexes;
541
 
    Indexes indexes;
542
 
    int index = 0;
543
 
    for (string_pairs::const_iterator it = default_pairs.begin();
544
 
         it != default_pairs.end(); ++it, ++index) {
545
 
        Indexes::iterator found = indexes.find(it->first);
546
 
        if (found == indexes.end()) {
547
 
            indexes[it->first] = index;
548
 
        } else {
549
 
            // it is a paired punct.
550
 
            indexes[it->first] = -found->second;
551
 
        }
552
 
    }
553
 
    string_pairs result(default_pairs);
554
 
    for (string_pairs::const_iterator it = user_pairs.begin();
555
 
         it != user_pairs.end(); ++it) {
556
 
        Indexes::iterator found = indexes.find(it->first);
557
 
        if (found == indexes.end()) {
558
 
            result.push_back(*it);
559
 
        } else if (found->second >= 0) {
560
 
            result[found->second] = *it;
561
 
        } else {
562
 
            // it is a paired punct,
563
 
            // but we don't support this kind of mapping yet,
564
 
            // so quietly ignore it.
565
 
        }
566
 
    }
567
 
    return result;
568
 
}
569
 
 
570
 
void
571
 
SunPinyinEngine::update_punct_mappings()
572
 
{
573
 
    CSimplifiedChinesePolicy& policy = ASimplifiedChinesePolicy::instance();
574
 
    if (m_config.get(PINYIN_PUNCTMAPPING_ENABLED, false)) {
575
 
        std::vector<std::string> mappings;
576
 
        mappings = m_config.get(PINYIN_PUNCTMAPPING_MAPPINGS, mappings);
577
 
        string_pairs pairs(merge_pairs(policy.getDefaultPunctMapping(),
578
 
                                       parse_pairs(mappings)));
579
 
        policy.setPunctMapping(pairs);
580
 
    }
581
 
}
582
 
 
583
 
void
584
 
SunPinyinEngine::update_user_data_dir()
585
 
{
586
 
    std::stringstream user_data_dir;
587
 
    user_data_dir << g_get_home_dir()
588
 
                  << G_DIR_SEPARATOR_S << ".sunpinyin";
589
 
    ASimplifiedChinesePolicy::instance().setUserDataDir(user_data_dir.str());
590
 
}
591
 
 
592
 
void
593
 
SunPinyinEngine::update_fuzzy_pinyins()
594
 
{
595
 
    bool enabled = m_config.get(QUANPIN_FUZZY_ENABLED, false);
596
 
    AQuanpinSchemePolicy::instance().setFuzzyForwarding(enabled);
597
 
    AShuangpinSchemePolicy::instance().setFuzzyForwarding(enabled);
598
 
    if (!enabled)
599
 
        return;
600
 
    std::vector<std::string> fuzzy_pinyins;
601
 
    fuzzy_pinyins = m_config.get(QUANPIN_FUZZY_PINYINS, fuzzy_pinyins);
602
 
    AQuanpinSchemePolicy::instance().setFuzzyPinyinPairs(parse_pairs(fuzzy_pinyins));
603
 
    AShuangpinSchemePolicy::instance().setFuzzyPinyinPairs(parse_pairs(fuzzy_pinyins));
604
 
}
605
 
 
606
 
void
607
 
SunPinyinEngine::update_correction_pinyins()
608
 
{
609
 
    bool enabled = m_config.get(QUANPIN_AUTOCORRECTION_ENABLED, false);
610
 
    AQuanpinSchemePolicy::instance().setAutoCorrecting(enabled);
611
 
    if (!enabled)
612
 
        return;
613
 
    std::vector<std::string> correction_pinyins;
614
 
    correction_pinyins = m_config.get(QUANPIN_AUTOCORRECTION_PINYINS, correction_pinyins);
615
 
    AQuanpinSchemePolicy::instance().setAutoCorrectionPairs(parse_pairs(correction_pinyins));
616
 
}
617
 
 
618
 
void
619
 
SunPinyinEngine::update_fuzzy_segs()
620
 
{
621
 
    bool enable_fuzzy_segs = m_config.get(CONFIG_QUANPIN_FUZZYSEGS_ENABLED, false);
622
 
    AQuanpinSchemePolicy::instance().setFuzzySegmentation(enable_fuzzy_segs);
623
 
    bool enable_inner_fuzzy = m_config.get(CONFIG_QUANPIN_INNERFUZZY_ENABLED, false);
624
 
    AQuanpinSchemePolicy::instance().setInnerFuzzySegmentation(CONFIG_QUANPIN_INNERFUZZY_ENABLED);
625
 
}
626
 
 
627
 
void
628
 
SunPinyinEngine::update_shuangpin_type()
629
 
{
630
 
    EShuangpinType shuangpin_type = MS2003;
631
 
    shuangpin_type = (EShuangpinType) m_config.get(SHUANGPIN_TYPE, (int) shuangpin_type);
632
 
    AShuangpinSchemePolicy::instance().setShuangpinType(shuangpin_type);
633
 
}
634
 
 
635
 
void
636
 
SunPinyinEngine::update_candi_delete_key()
637
 
{
638
 
    /* FIXME: need to get candi_delete_key from user's configuration */
639
 
    m_hotkey_profile->setCandiDeleteKey(CKeyEvent(0, 0, IM_ALT_MASK));
640
 
}