Import c version pinyin engine
authorPeng Huang <shawn.p.huang@gmail.com>
Wed, 23 Sep 2009 05:30:02 +0000 (13:30 +0800)
committerPeng Huang <shawn.p.huang@gmail.com>
Wed, 23 Sep 2009 05:30:02 +0000 (13:30 +0800)
110 files changed:
AUTHORS
Makefile.am
README
autogen.sh
configure.ac
data/Makefile.am [moved from icons/Makefile.am with 55% similarity]
data/icons/Makefile.am [new file with mode: 0644]
data/icons/chinese.svg [moved from icons/chinese.svg with 100% similarity]
data/icons/english.svg [moved from icons/english.svg with 100% similarity]
data/icons/full-punct.svg [moved from icons/full-punct.svg with 100% similarity]
data/icons/full.svg [moved from icons/full-letter.svg with 100% similarity]
data/icons/half-punct.svg [moved from icons/half-punct.svg with 100% similarity]
data/icons/half.svg [moved from icons/half-letter.svg with 100% similarity]
data/icons/ibus-pinyin.svg [moved from icons/ibus-pinyin.svg with 100% similarity]
data/scripts/create_db.py [new file with mode: 0644]
data/scripts/create_index.py [new file with mode: 0644]
data/scripts/create_unique_index.py [new file with mode: 0644]
data/scripts/double.py [new file with mode: 0644]
data/scripts/id.py [new file with mode: 0644]
data/scripts/pydict.py [moved from engine/pydict.py with 100% similarity]
data/scripts/pyutil.py [moved from engine/pyutil.py with 100% similarity]
debian/README.Debian [deleted file]
debian/changelog [deleted file]
debian/compat [deleted file]
debian/control [deleted file]
debian/copyright [deleted file]
debian/cron.d.ex [deleted file]
debian/dirs [deleted file]
debian/docs [deleted file]
debian/emacsen-install.ex [deleted file]
debian/emacsen-remove.ex [deleted file]
debian/emacsen-startup.ex [deleted file]
debian/ibus-pinyin-default.ex [deleted file]
debian/ibus-pinyin.doc-base.EX [deleted file]
debian/init.d.ex [deleted file]
debian/init.d.lsb.ex [deleted file]
debian/manpage.1.ex [deleted file]
debian/manpage.sgml.ex [deleted file]
debian/manpage.xml.ex [deleted file]
debian/menu.ex [deleted file]
debian/postinst.ex [deleted file]
debian/postrm.ex [deleted file]
debian/preinst.ex [deleted file]
debian/prerm.ex [deleted file]
debian/rules [deleted file]
debian/watch.ex [deleted file]
engine/Makefile.am [deleted file]
engine/factory.py [deleted file]
engine/ibus-engine-pinyin.in [deleted file]
engine/main.py [deleted file]
engine/pinyin.py [deleted file]
engine/pycreatedb.py [deleted file]
engine/pyparser.py [deleted file]
engine/pysqlitedb.py [deleted file]
engine/special_phrase [deleted file]
engine/specialphrase.py [deleted file]
engine/specialtable.py [deleted file]
ibus-pinyin.spec.in
po/LINGUAS
po/POTFILES.in
po/ja.po [deleted file]
po/zh_CN.gmo [new file with mode: 0644]
po/zh_CN.po
setup/Makefile.am
setup/ibus-pinyin-preferences.glade [new file with mode: 0644]
setup/ibus-setup-pinyin.in
setup/main.py
setup/pydict.py [deleted symlink]
setup/setup.glade [deleted file]
src/Array.h [new file with mode: 0644]
src/Bus.h [new file with mode: 0644]
src/Config.cc [new file with mode: 0644]
src/Config.h [new file with mode: 0644]
src/Database.cc [new file with mode: 0644]
src/Database.h [new file with mode: 0644]
src/DoublePinyinEditor.cc [new file with mode: 0644]
src/DoublePinyinEditor.h [new file with mode: 0644]
src/DoublePinyinTable.h [new file with mode: 0644]
src/Engine.cc [new file with mode: 0644]
src/Engine.h [new file with mode: 0644]
src/FullPinyinEditor.cc [new file with mode: 0644]
src/FullPinyinEditor.h [new file with mode: 0644]
src/HalfFullConverter.cc [new file with mode: 0644]
src/HalfFullConverter.h [new file with mode: 0644]
src/LookupTable.h [new file with mode: 0644]
src/Main.cc [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/PhraseArray.h [new file with mode: 0644]
src/PhraseEditor.cc [new file with mode: 0644]
src/PhraseEditor.h [new file with mode: 0644]
src/PinyinArray.h [new file with mode: 0644]
src/PinyinEditor.cc [new file with mode: 0644]
src/PinyinEditor.h [new file with mode: 0644]
src/PinyinEngine.cc [new file with mode: 0644]
src/PinyinEngine.h [new file with mode: 0644]
src/PinyinParser.cc [new file with mode: 0644]
src/PinyinParser.h [new file with mode: 0644]
src/Pointer.h [new file with mode: 0644]
src/Property.h [new file with mode: 0644]
src/SpecialTable.cc [new file with mode: 0644]
src/SpecialTable.h [new file with mode: 0644]
src/String.h [new file with mode: 0644]
src/Text.h [new file with mode: 0644]
src/Types.h [new file with mode: 0644]
src/Util.h [new file with mode: 0644]
src/main.db [new symlink]
src/pinyin.xml.in.in [moved from engine/pinyin.xml.in.in with 72% similarity]
src/scripts/genpytable.py [new file with mode: 0644]
src/scripts/pydict.py [new file with mode: 0644]
src/special_table [moved from engine/special_table with 99% similarity]

diff --git a/AUTHORS b/AUTHORS
index d6c43bf..a32ecc2 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,9 +1 @@
-
 Huang Peng <shawn.p.huang@gmail.com>
-
-Translators:
------------
-zh_CN.po:
-Huang Peng <shawn.p.huang@gmail.com>
-ja.po:
-UTUMI Hirosi <utuhiro78@yahoo.co.jp>
index ba1b395..f8f9eec 100644 (file)
@@ -1,6 +1,6 @@
 # vim:set noet ts=4:
 #
-# ibus-pinyin - The PinYin engine for IBus
+# ibus-pinyin - The Chinese PinYin engine for IBus
 #
 # Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
 #
@@ -19,9 +19,9 @@
 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
 SUBDIRS = \
-       engine \
+       src \
        setup \
-       icons \
+       data \
        m4 \
        po \
        $(NULL)
@@ -30,7 +30,7 @@ ACLOCAL_AMFLAGS = -I m4
 
 EXTRA_DIST = \
        autogen.sh \
-       @PACKAGE_NAME@.spec.in \
+       ibus-pinyin.spec.in \
        $(NULL)
 
 noinst_DIST = \
@@ -44,18 +44,18 @@ DISTCLEANFILES = \
 rpm: dist @PACKAGE_NAME@.spec
        rpmbuild -bb \
                        --define "_sourcedir `pwd`" \
-                       --define "_builddir `pwd`" \
+                       --define "_builddir `pwd`/rpm" \
+                       --define "_srcrpmdir `pwd`/rpm" \
+                       --define "_rpmdir `pwd`/rpm" \
                        --define "_specdir `pwd`" \
-                       --define "_rpmdir `pwd`" \
-                       --define "_srcrpmdir `pwd`" \
                        @PACKAGE_NAME@.spec
 
 srpm: dist @PACKAGE_NAME@.spec
        rpmbuild -bs \
                        --define "_sourcedir `pwd`" \
-                       --define "_builddir `pwd`" \
-                       --define "_srcrpmdir `pwd`" \
-                       --define "_rpmdir `pwd`" \
+                       --define "_builddir `pwd`/rpm" \
+                       --define "_srcrpmdir `pwd`/rpm" \
+                       --define "_rpmdir `pwd`/rpm" \
                        --define "_specdir `pwd`" \
                        @PACKAGE_NAME@.spec
 
diff --git a/README b/README
index 25d8464..3230969 100644 (file)
--- a/README
+++ b/README
@@ -1,2 +1,2 @@
 ibus-pinyin
-It is a PinYin engine for IBus.
+It is a Chinese Pinyin input method for IBus.
index 94f8fd3..9e533f0 100755 (executable)
@@ -5,7 +5,9 @@ set -x
 autopoint
 libtoolize --automake --copy
 aclocal -I m4
-autoheader
+autoheader
 automake --add-missing --copy
 autoconf
+export CFLAGS="-Wall -g -O0 -Wl,--no-undefined"
+export CXXFLAGS="$CFLAGS"
 ./configure --enable-maintainer-mode $*
index ee158a8..5c175c4 100644 (file)
@@ -1,6 +1,6 @@
 # vim:set et ts=4:
 #
-# ibus-pinyin - The PinYin engine for IBus
+# ibus-pinyin - The Chinese PinYin engine for IBus
 #
 # Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
 #
 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
 # if not 1, append datestamp to the version number.
-m4_define([package_name], [ibus-pinyin])
 m4_define([ibus_released], [0])
 m4_define([ibus_major_version], [1])
 m4_define([ibus_minor_version], [2])
-m4_define([ibus_micro_version], [0])
+m4_define([ibus_micro_version], [99])
 m4_define(ibus_maybe_datestamp,
     m4_esyscmd([if test x]ibus_released[ != x1; then date +.%Y%m%d | tr -d '\n\r'; fi]))
 
 m4_define([ibus_version],
     ibus_major_version.ibus_minor_version.ibus_micro_version[]ibus_maybe_datestamp)
 
-AC_INIT([package_name], [ibus_version], [http://code.google.com/p/ibus/issues/entry], [package_name])
+AC_INIT([ibus-pinyin], [ibus_version], [http://code.google.com/p/ibus/issues/entry],[ibus-pinyin])
 AM_INIT_AUTOMAKE([1.10])
-AC_GNU_SOURCE
+AC_GNU_SOURCE
 
-AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_MACRO_DIR([m4])
 
 # define PACKAGE_VERSION_* variables
-AS_VERSION
-AS_NANO
-AM_SANITY_CHECK
+AS_VERSION
+AS_NANO
+AM_SANITY_CHECK
 AM_MAINTAINER_MODE
-# AM_DISABLE_STATIC
-# AC_PROG_CC
-# AM_PROG_CC_C_O
-# AC_PROG_CXX
-# AC_ISC_POSIX
-# AC_HEADER_STDC
-# AM_PROG_LIBTOOL
+AM_DISABLE_STATIC
+AC_PROG_CC
+AC_PROG_CXX
+AM_PROG_CC_C_O
+AC_ISC_POSIX
+AC_HEADER_STDC
+AM_PROG_LIBTOOL
+
+# check ibus
+PKG_CHECK_MODULES(IBUS, [
+    ibus-1.0
+])
+
+# check sqlite
+PKG_CHECK_MODULES(SQLITE, [
+    sqlite3
+])
+
+# check uuid
+PKG_CHECK_MODULES(UUID, [
+    uuid
+])
+
+# check env
+AC_PATH_PROG(ENV, env)
+AC_SUBST(ENV)
 
 #check python
 AM_PATH_PYTHON([2.5])
 
 # define GETTEXT_* variables
-GETTEXT_PACKAGE="$PACKAGE_NAME"
+GETTEXT_PACKAGE=ibus-pinyin
 AC_SUBST(GETTEXT_PACKAGE)
 AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", [Define to the read-only architecture-independent data directory.])
 
@@ -63,16 +81,16 @@ AM_GNU_GETTEXT_VERSION(0.16.1)
 
 
 # OUTPUT files
-AC_CONFIG_FILES(po/Makefile.in
+AC_CONFIG_FILES(po/Makefile.in
 Makefile
 ibus-pinyin.spec
-engine/Makefile
-engine/ibus-engine-pinyin
-engine/pinyin.xml.in
+src/Makefile
+src/pinyin.xml.in
 setup/Makefile
 setup/ibus-setup-pinyin
-icons/Makefile
+data/Makefile
+data/icons/Makefile
 m4/Makefile
-)
+])
 
 AC_OUTPUT
similarity index 55%
rename from icons/Makefile.am
rename to data/Makefile.am
index ee5c45c..bca638d 100644 (file)
@@ -1,6 +1,6 @@
 # vim:set noet ts=4:
 #
-# ibus-pinyin - The PinYin engine for IBus
+# ibus-pinyin - The Chinese PinYin engine for IBus
 #
 # Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
 #
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-icons_DATA = \
-       ibus-pinyin.svg \
-       full-letter.svg \
-       half-letter.svg \
-       full-punct.svg \
-       half-punct.svg \
-       chinese.svg \
-       english.svg \
+
+SUBDIRS = \
+       icons \
+       $(NULL)
+
+main_db_DATA = \
+       db/main.db \
+       db/COPYING \
+       db/create_index.sql \
        $(NULL)
+main_dbdir = $(pkgdatadir)/db
+
+install-data-hook:
+       @( \
+if test "$(NO_INDEX)" = ""; then \
+  cd $(DESTDIR)$(main_dbdir); \
+  echo "Create INDEX"; \
+  sqlite3 main.db ".read create_index.sql"; \
+fi)
+
+DBVER = 1.2.99
+DBTAR = pinyin-database-$(DBVER).tar.bz2
 
-iconsdir = $(pkgdatadir)/icons
+$(DBTAR):
+       wget http://ibus.googlecode.com/files/$(DBTAR)
+
+db.stamp: $(DBTAR)
+       tar jxvfm $(DBTAR)
+       touch $@
+
+$(main_db_DATA): db.stamp
+
+CLEANFILES = \
+       db.stamp \
+       db/* \
+       $(NULL)
 
-EXTRA_DIST = \
-       $(icons_DATA) \
+DISTCLEANFILES = \
+       $(DBTAR) \
        $(NULL)
diff --git a/data/icons/Makefile.am b/data/icons/Makefile.am
new file mode 100644 (file)
index 0000000..5d59077
--- /dev/null
@@ -0,0 +1,37 @@
+# vim:set noet ts=4:
+#
+# ibus-pinyin - The Chinese PinYin engine for IBus
+#
+# Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+# Boston, MA  02111-1307  USA
+
+icons_DATA = \
+       ibus-pinyin.svg \
+       chinese.svg \
+       english.svg \
+       full.svg \
+       full-punct.svg \
+       half.svg \
+       half-punct.svg \
+       $(NULL)
+
+iconsdir = $(pkgdatadir)/icons
+
+EXTRA_DIST = \
+       $(icons_DATA) \
+       $(NULL)
+
similarity index 100%
rename from icons/chinese.svg
rename to data/icons/chinese.svg
similarity index 100%
rename from icons/english.svg
rename to data/icons/english.svg
similarity index 100%
rename from icons/full-letter.svg
rename to data/icons/full.svg
similarity index 100%
rename from icons/half-letter.svg
rename to data/icons/half.svg
diff --git a/data/scripts/create_db.py b/data/scripts/create_db.py
new file mode 100644 (file)
index 0000000..e4826ae
--- /dev/null
@@ -0,0 +1,94 @@
+import sqlite3
+from pydict import *
+from id import *
+import sys
+
+con1 = sqlite3.connect("py.db")
+con2 = sqlite3.connect("py-new.db")
+con2.execute ("PRAGMA synchronous = NORMAL;")
+con2.execute ("PRAGMA temp_store = MEMORY;")
+con2.execute ("PRAGMA default_cache_size = 5000;")
+
+sql = "CREATE TABLE py_phrase_%d (phrase TEXT, freq INTEGER, %s)"
+
+for i in range(0, 16):
+       column= []
+       for j in range(0, i + 1):
+               column.append ("s%d INTEGER" % j)
+               column.append ("y%d INTEGER" % j)
+       column = ",".join(column)
+       con2.execute(sql % (i, column))
+con2.commit()
+
+def get_sheng_yun(pinyin):
+       if pinyin == None:
+               return None, None
+       if pinyin == "ng":
+               return "", "en"
+       for i in xrange(2, 0, -1):
+               t = pinyin[:i]
+               if t in SHENGMU_DICT:
+                       return t, pinyin[len(t):]
+       return "", pinyin
+
+def encode_pinyin(pinyin):
+       if pinyin == None or pinyin == "":
+               return 0
+        return pinyin_id[pinyin]
+       e = 0
+       for c in pinyin:
+               e = (e << 5) + (ord(c) - ord('a') + 1)
+       return e
+
+insert_sql = "INSERT INTO py_phrase_%d VALUES (%s);"
+con2.commit()
+new_freq = 0
+freq = 0
+
+print "INSERTING"
+for  r in con1.execute("SELECT * FROM py_phrase ORDER BY freq"):
+       ylen = r[0]
+       phrase = r[10]
+       if r[11] > freq:
+               freq = r[11]
+               new_freq += 1
+
+       if ylen <= 4:
+               pys = map(lambda id: ID_PINYIN_DICT[id], r[1: 1 + ylen])
+       else:
+               pys = map(lambda id: ID_PINYIN_DICT[id], r[1: 5]) + r[5].encode("utf8").split("'")
+
+       i = ylen - 1
+       if i >= 15:
+               i = 15
+
+       pys = pys[0:16]
+
+       sheng_yun = []
+       for s, y in map(get_sheng_yun, pys):
+               sheng_yun.append(s)
+               sheng_yun.append(y)
+       
+       
+       column = [phrase, new_freq] + map(encode_pinyin, sheng_yun)
+
+       sql = insert_sql % (i, ",".join(["?"] * len(column)))
+       con2.execute (sql, column)
+
+print "Remove duplicate"
+for i in xrange(0, 16):
+    sql = "DELETE FROM py_phrase_%d WHERE rowid IN (SELECT rowid FROM (SELECT count() as count, rowid FROM py_phrase_%d GROUP by %s,phrase) WHERE count > 1)" % (i, i, ",".join(map(lambda i: "s%d,y%d"%(i,i), range(0, i + 1))))
+    con2.execute(sql)
+con2.commit()
+print "CACUUM"
+con2.execute("VACUUM;")
+con2.commit()
+
+# con2.execute("create index index_0_0 on py_phrase_0(s0, y0)")
+# 
+# for i in xrange(1, 16):
+#      con2.execute("create index index_%d_0 on py_phrase_%d(s0, y0, s1, y1)" % (i, i))
+#      con2.execute("create index index_%d_1 on py_phrase_%d(s0, s1, y1)" % (i, i))
+# 
+# con2.execute("vacuum")
+# con2.commit()
diff --git a/data/scripts/create_index.py b/data/scripts/create_index.py
new file mode 100644 (file)
index 0000000..823e616
--- /dev/null
@@ -0,0 +1,21 @@
+import sqlite3
+
+con2 = sqlite3.connect("py-new.db")
+con2.execute ("PRAGMA synchronous = NORMAL;")
+con2.execute ("PRAGMA temp_store = MEMORY;")
+
+
+con2.execute("CREATE INDEX index_0_0 ON py_phrase_0(s0, y0)")
+print "py_phrase_%d done" % 0
+
+con2.execute("CREATE INDEX index_1_0 ON py_phrase_1(s0, y0, s1, y1)")
+con2.execute("CREATE INDEX index_1_1 ON py_phrase_1(s0, s1, y1)")
+print "py_phrase_%d done" % 1
+
+for i in xrange(2, 16):
+       con2.execute("CREATE INDEX index_%d_0 ON py_phrase_%d(s0, y0, s1, y1, s2, y2)" % (i, i))
+       con2.execute("CREATE INDEX index_%d_1 ON py_phrase_%d(s0, s1, s2, y2)" % (i, i))
+       print "py_phrase_%d done" % i
+
+# con2.execute("vacuum")
+con2.commit()
diff --git a/data/scripts/create_unique_index.py b/data/scripts/create_unique_index.py
new file mode 100644 (file)
index 0000000..e22d986
--- /dev/null
@@ -0,0 +1,27 @@
+import sqlite3
+
+con2 = sqlite3.connect("py-new.db")
+con2.execute ("PRAGMA synchronous = NORMAL;")
+con2.execute ("PRAGMA temp_store = MEMORY;")
+
+
+con2.execute("CREATE UNIQUE INDEX IF NOT EXISTS index_0_0 ON py_phrase_0(s0, y0, phrase)")
+print "py_phrase_%d done" % 0
+
+con2.execute("CREATE UNIQUE INDEX IF NOT EXISTS index_1_0 ON py_phrase_1(s0, y0, s1, y1, phrase)")
+con2.execute("CREATE INDEX IF NOT EXISTS index_1_1 ON py_phrase_1(s0, s1, y1)")
+print "py_phrase_%d done" % 1
+
+for i in xrange(2, 16):
+    sql = "CREATE UNIQUE INDEX IF NOT EXISTS index_%d_0 ON py_phrase_%d (" % (i, i)
+    sql = sql + "s0,y0"
+    for j in xrange(1, i + 1):
+        sql = sql + ",s%d,y%d" % (j, j)
+    sql = sql + ", phrase)"
+    print sql
+    con2.execute(sql)
+    con2.execute("CREATE INDEX IF NOT EXISTS index_%d_1 ON py_phrase_%d(s0, s1, s2, y2)" % (i, i))
+    print "py_phrase_%d done" % i
+
+# con2.execute("vacuum")
+con2.commit()
diff --git a/data/scripts/double.py b/data/scripts/double.py
new file mode 100644 (file)
index 0000000..1ee8359
--- /dev/null
@@ -0,0 +1,38 @@
+import pydict
+
+for name, (sheng, yun) in pydict.SHUANGPIN_SCHEMAS.items():
+    print "static const gint double_pinyin_%s_sheng[] = {" % name.lower()
+    for c in "abcdefghijklmnopqrstuvwxyz;":
+        s = sheng.get(c, "VOID")
+        if s == "'":
+            s = "ZERO"
+        else:
+            s = s.upper()
+        print "    PINYIN_ID_%s // %s" % ((s + ",").ljust(5), c.upper())
+    print "};"
+    
+    print "static const gint double_pinyin_%s_yun[][2] = {" % name.lower()
+    for c in "abcdefghijklmnopqrstuvwxyz;":
+        s = yun.get(c, ("VOID", "VOID"))
+        if len(s) == 1:
+            s1 = s[0]
+            s2 = "VOID"
+        else:
+            s1, s2 = s
+        if s1 == "'":
+            s1 = "ZERO"
+        if s2 == "'":
+            s2 = "ZERO"
+        s1 = s1.upper()
+        s2 = s2.upper()
+        print "    { PINYIN_ID_%s PINYIN_ID_%s }, // %s" % ((s1 + ",").ljust(5), s2.ljust(4), c.upper())
+    print "};"
+
+print '''
+static const struct {
+    const gint  (&sheng)[27];
+    const gint  (&yun)[27][2];
+} double_pinyin_map [] = {'''
+for name, (sheng, yun) in pydict.SHUANGPIN_SCHEMAS.items():
+    print "    { double_pinyin_%s_sheng, double_pinyin_%s_yun}," %  (name.lower(), name.lower())
+print "};"
diff --git a/data/scripts/id.py b/data/scripts/id.py
new file mode 100644 (file)
index 0000000..44bd80c
--- /dev/null
@@ -0,0 +1 @@
+pinyin_id = {'ch': 3, 'zh': 23, 'ai': 25, 'uan': 50, 'iu': 43, 'ong': 45, 'ao': 28, 'an': 26, 'uai': 49, 'ang': 27, 'iong': 42, 'in': 40, 'ia': 35, 'ei': 30, 'ing': 41, 'ie': 39, 'er': 33, 'iao': 38, 'ian': 36, 'eng': 32, 'iang': 37, 'uo': 55, 'r': 15, 'en': 31, 'ui': 53, 'un': 54, 'ue': 52, 'uang': 51, 'a': 24, 'c': 2, 'b': 1, 'e': 29, 'd': 4, 'g': 6, 'f': 5, 'i': 34, 'h': 7, 'k': 9, 'j': 8, 'm': 11, 'l': 10, 'o': 44, 'n': 12, 'q': 14, 'p': 13, 's': 16, 'sh': 17, 'u': 47, 't': 18, 'w': 19, 'v': 56, 'y': 21, 'x': 20, 'ou': 46, 'z': 22, 'ua': 48}
similarity index 100%
rename from engine/pydict.py
rename to data/scripts/pydict.py
similarity index 100%
rename from engine/pyutil.py
rename to data/scripts/pyutil.py
diff --git a/debian/README.Debian b/debian/README.Debian
deleted file mode 100644 (file)
index e9e6ec8..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-ibus-pinyin for Debian
-----------------------
-
-<possible notes regarding this package - if none, delete this file>
-
- -- oneleaf <oneleaf@gmail.com>  Thu, 11 Sep 2008 10:29:30 +0800
diff --git a/debian/changelog b/debian/changelog
deleted file mode 100644 (file)
index 2175cd9..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-ibus-pinyin (0.1.1.20080901-1) unstable; urgency=low
-
-  * Initial release (Closes: #nnnn)  <nnnn is the bug number of your ITP>
-
- -- oneleaf <oneleaf@gmail.com>  Thu, 11 Sep 2008 10:29:30 +0800
-
diff --git a/debian/compat b/debian/compat
deleted file mode 100644 (file)
index 7ed6ff8..0000000
+++ /dev/null
@@ -1 +0,0 @@
-5
diff --git a/debian/control b/debian/control
deleted file mode 100644 (file)
index 161986c..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-Source: ibus-pinyin
-Section: unknown
-Priority: extra
-Maintainer: oneleaf <oneleaf@gmail.com>
-Build-Depends: debhelper (>= 5), autotools-dev
-Standards-Version: 3.7.2
-
-Package: ibus-pinyin
-Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}, ibus
-Description: ibus-pinyin
- It is a PinYin engine for IBus.
diff --git a/debian/copyright b/debian/copyright
deleted file mode 100644 (file)
index 26049cd..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-This package was debianized by oneleaf <oneleaf@gmail.com> on
-Thu, 11 Sep 2008 09:58:03 +0800.
-
-It was downloaded from <http://code.google.com/p/ibus/>
-
-Upstream Author(s): 
-
-    Shawn.P.Huang <Shawn.P.Huang@gmail.com>
-
-Copyright: 
-
-    <Copyright (C) Shawn.P.Huang>
-
-License:
-
-    GNU Lesser General Public License
-
-The Debian packaging is (C) 2008, oneleaf <oneleaf@gmail.com> and
-is licensed under the GPL, see `/usr/share/common-licenses/GPL'.
-
-# Please also look if there are files or directories which have a
-# different copyright/license attached and list them here.
diff --git a/debian/cron.d.ex b/debian/cron.d.ex
deleted file mode 100644 (file)
index 02b68ea..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#
-# Regular cron jobs for the ibus-pinyin package
-#
-0 4    * * *   root    ibus-pinyin_maintenance
diff --git a/debian/dirs b/debian/dirs
deleted file mode 100644 (file)
index ca882bb..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-usr/bin
-usr/sbin
diff --git a/debian/docs b/debian/docs
deleted file mode 100644 (file)
index 50bd824..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-NEWS
-README
diff --git a/debian/emacsen-install.ex b/debian/emacsen-install.ex
deleted file mode 100644 (file)
index 09c12aa..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#! /bin/sh -e
-# /usr/lib/emacsen-common/packages/install/ibus-pinyin
-
-# Written by Jim Van Zandt <jrv@debian.org>, borrowing heavily
-# from the install scripts for gettext by Santiago Vila
-# <sanvila@ctv.es> and octave by Dirk Eddelbuettel <edd@debian.org>.
-
-FLAVOR=$1
-PACKAGE=ibus-pinyin
-
-if [ ${FLAVOR} = emacs ]; then exit 0; fi
-
-echo install/${PACKAGE}: Handling install for emacsen flavor ${FLAVOR}
-
-#FLAVORTEST=`echo $FLAVOR | cut -c-6`
-#if [ ${FLAVORTEST} = xemacs ] ; then
-#    SITEFLAG="-no-site-file"
-#else
-#    SITEFLAG="--no-site-file"
-#fi
-FLAGS="${SITEFLAG} -q -batch -l path.el -f batch-byte-compile"
-
-ELDIR=/usr/share/emacs/site-lisp/${PACKAGE}
-ELCDIR=/usr/share/${FLAVOR}/site-lisp/${PACKAGE}
-
-# Install-info-altdir does not actually exist. 
-# Maybe somebody will write it.
-if test -x /usr/sbin/install-info-altdir; then
-    echo install/${PACKAGE}: install Info links for ${FLAVOR}
-    install-info-altdir --quiet --section "" "" --dirname=${FLAVOR} /usr/share/info/${PACKAGE}.info.gz
-fi
-
-install -m 755 -d ${ELCDIR}
-cd ${ELDIR}
-FILES=`echo *.el`
-cp ${FILES} ${ELCDIR}
-cd ${ELCDIR}
-
-cat << EOF > path.el
-(setq load-path (cons "." load-path) byte-compile-warnings nil)
-EOF
-${FLAVOR} ${FLAGS} ${FILES}
-rm -f *.el path.el
-
-exit 0
diff --git a/debian/emacsen-remove.ex b/debian/emacsen-remove.ex
deleted file mode 100644 (file)
index 853219d..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/sh -e
-# /usr/lib/emacsen-common/packages/remove/ibus-pinyin
-
-FLAVOR=$1
-PACKAGE=ibus-pinyin
-
-if [ ${FLAVOR} != emacs ]; then
-    if test -x /usr/sbin/install-info-altdir; then
-        echo remove/${PACKAGE}: removing Info links for ${FLAVOR}
-        install-info-altdir --quiet --remove --dirname=${FLAVOR} /usr/share/info/ibus-pinyin.info.gz
-    fi
-
-    echo remove/${PACKAGE}: purging byte-compiled files for ${FLAVOR}
-    rm -rf /usr/share/${FLAVOR}/site-lisp/${PACKAGE}
-fi
diff --git a/debian/emacsen-startup.ex b/debian/emacsen-startup.ex
deleted file mode 100644 (file)
index 0691f53..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-;; -*-emacs-lisp-*-
-;;
-;; Emacs startup file, e.g.  /etc/emacs/site-start.d/50ibus-pinyin.el
-;; for the Debian ibus-pinyin package
-;;
-;; Originally contributed by Nils Naumann <naumann@unileoben.ac.at>
-;; Modified by Dirk Eddelbuettel <edd@debian.org>
-;; Adapted for dh-make by Jim Van Zandt <jrv@debian.org>
-
-;; The ibus-pinyin package follows the Debian/GNU Linux 'emacsen' policy and
-;; byte-compiles its elisp files for each 'emacs flavor' (emacs19,
-;; xemacs19, emacs20, xemacs20...).  The compiled code is then
-;; installed in a subdirectory of the respective site-lisp directory.
-;; We have to add this to the load-path:
-(let ((package-dir (concat "/usr/share/"
-                           (symbol-name flavor)
-                           "/site-lisp/ibus-pinyin")))
-;; If package-dir does not exist, the ibus-pinyin package must have
-;; removed but not purged, and we should skip the setup.
-  (when (file-directory-p package-dir)
-        (setq load-path (cons package-dir load-path))
-       (autoload 'ibus-pinyin-mode "ibus-pinyin-mode"
-         "Major mode for editing ibus-pinyin files." t)
-       (add-to-list 'auto-mode-alist '("\\.ibus-pinyin$" . ibus-pinyin-mode))))
-
diff --git a/debian/ibus-pinyin-default.ex b/debian/ibus-pinyin-default.ex
deleted file mode 100644 (file)
index 9ca3204..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-# Defaults for ibus-pinyin initscript
-# sourced by /etc/init.d/ibus-pinyin
-# installed at /etc/default/ibus-pinyin by the maintainer scripts
-
-#
-# This is a POSIX shell fragment
-#
-
-# Additional options that are passed to the Daemon.
-DAEMON_OPTS=""
diff --git a/debian/ibus-pinyin.doc-base.EX b/debian/ibus-pinyin.doc-base.EX
deleted file mode 100644 (file)
index 14ad664..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-Document: ibus-pinyin
-Title: Debian ibus-pinyin Manual
-Author: <insert document author here>
-Abstract: This manual describes what ibus-pinyin is
- and how it can be used to
- manage online manuals on Debian systems.
-Section: unknown
-
-Format: debiandoc-sgml
-Files: /usr/share/doc/ibus-pinyin/ibus-pinyin.sgml.gz
-
-Format: postscript
-Files: /usr/share/doc/ibus-pinyin/ibus-pinyin.ps.gz
-
-Format: text
-Files: /usr/share/doc/ibus-pinyin/ibus-pinyin.text.gz
-
-Format: HTML
-Index: /usr/share/doc/ibus-pinyin/html/index.html
-Files: /usr/share/doc/ibus-pinyin/html/*.html
-
-  
diff --git a/debian/init.d.ex b/debian/init.d.ex
deleted file mode 100644 (file)
index 0b800d9..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-#! /bin/sh
-#
-# skeleton     example file to build /etc/init.d/ scripts.
-#              This file should be used to construct scripts for /etc/init.d.
-#
-#              Written by Miquel van Smoorenburg <miquels@cistron.nl>.
-#              Modified for Debian 
-#              by Ian Murdock <imurdock@gnu.ai.mit.edu>.
-#               Further changes by Javier Fernandez-Sanguino <jfs@debian.org>
-#
-# Version:     @(#)skeleton  1.9  26-Feb-2001  miquels@cistron.nl
-#
-
-PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
-DAEMON=/usr/sbin/ibus-pinyin
-NAME=ibus-pinyin
-DESC=ibus-pinyin
-
-test -x $DAEMON || exit 0
-
-LOGDIR=/var/log/ibus-pinyin
-PIDFILE=/var/run/$NAME.pid
-DODTIME=1                   # Time to wait for the server to die, in seconds
-                            # If this value is set too low you might not
-                            # let some servers to die gracefully and
-                            # 'restart' will not work
-
-# Include ibus-pinyin defaults if available
-if [ -f /etc/default/ibus-pinyin ] ; then
-       . /etc/default/ibus-pinyin
-fi
-
-set -e
-
-running_pid()
-{
-    # Check if a given process pid's cmdline matches a given name
-    pid=$1
-    name=$2
-    [ -z "$pid" ] && return 1 
-    [ ! -d /proc/$pid ] &&  return 1
-    cmd=`cat /proc/$pid/cmdline | tr "\000" "\n"|head -n 1 |cut -d : -f 1`
-    # Is this the expected child?
-    [ "$cmd" != "$name" ] &&  return 1
-    return 0
-}
-
-running()
-{
-# Check if the process is running looking at /proc
-# (works for all users)
-
-    # No pidfile, probably no daemon present
-    [ ! -f "$PIDFILE" ] && return 1
-    # Obtain the pid and check it against the binary name
-    pid=`cat $PIDFILE`
-    running_pid $pid $NAME || return 1
-    return 0
-}
-
-force_stop() {
-# Forcefully kill the process
-    [ ! -f "$PIDFILE" ] && return
-    if running ; then
-        kill -15 $pid
-        # Is it really dead?
-        [ -n "$DODTIME" ] && sleep "$DODTIME"s
-        if running ; then
-            kill -9 $pid
-            [ -n "$DODTIME" ] && sleep "$DODTIME"s
-            if running ; then
-                echo "Cannot kill $LABEL (pid=$pid)!"
-                exit 1
-            fi
-        fi
-    fi
-    rm -f $PIDFILE
-    return 0
-}
-
-case "$1" in
-  start)
-       echo -n "Starting $DESC: "
-       start-stop-daemon --start --quiet --pidfile $PIDFILE \
-               --exec $DAEMON -- $DAEMON_OPTS
-        if running then
-            echo "$NAME."
-        else
-            echo " ERROR."
-        fi
-       ;;
-  stop)
-       echo -n "Stopping $DESC: "
-       start-stop-daemon --stop --quiet --pidfile $PIDFILE \
-               --exec $DAEMON
-       echo "$NAME."
-       ;;
-  force-stop)
-       echo -n "Forcefully stopping $DESC: "
-        force_stop
-        if ! running then
-            echo "$NAME."
-        else
-            echo " ERROR."
-        fi
-       ;;
-  #reload)
-       #
-       #       If the daemon can reload its config files on the fly
-       #       for example by sending it SIGHUP, do it here.
-       #
-       #       If the daemon responds to changes in its config file
-       #       directly anyway, make this a do-nothing entry.
-       #
-       # echo "Reloading $DESC configuration files."
-       # start-stop-daemon --stop --signal 1 --quiet --pidfile \
-       #       /var/run/$NAME.pid --exec $DAEMON
-  #;;
-  force-reload)
-       #
-       #       If the "reload" option is implemented, move the "force-reload"
-       #       option to the "reload" entry above. If not, "force-reload" is
-       #       just the same as "restart" except that it does nothing if the
-       #   daemon isn't already running.
-       # check wether $DAEMON is running. If so, restart
-       start-stop-daemon --stop --test --quiet --pidfile \
-               /var/run/$NAME.pid --exec $DAEMON \
-       && $0 restart \
-       || exit 0
-       ;;
-  restart)
-    echo -n "Restarting $DESC: "
-       start-stop-daemon --stop --quiet --pidfile \
-               /var/run/$NAME.pid --exec $DAEMON
-       [ -n "$DODTIME" ] && sleep $DODTIME
-       start-stop-daemon --start --quiet --pidfile \
-               /var/run/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS
-       echo "$NAME."
-       ;;
-  status)
-    echo -n "$LABEL is "
-    if running ;  then
-        echo "running"
-    else
-        echo " not running."
-        exit 1
-    fi
-    ;;
-  *)
-       N=/etc/init.d/$NAME
-       # echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
-       echo "Usage: $N {start|stop|restart|force-reload|status|force-stop}" >&2
-       exit 1
-       ;;
-esac
-
-exit 0
diff --git a/debian/init.d.lsb.ex b/debian/init.d.lsb.ex
deleted file mode 100644 (file)
index e73dc7f..0000000
+++ /dev/null
@@ -1,281 +0,0 @@
-#!/bin/sh 
-#
-# Example init.d script with LSB support.
-#
-# Please read this init.d carefully and modify the sections to
-# adjust it to the program you want to run.
-#
-# Copyright (c) 2007 Javier Fernandez-Sanguino <jfs@debian.org>
-#
-# This is free software; you may redistribute it and/or modify
-# it under the terms of the GNU General Public License as
-# published by the Free Software Foundation; either version 2,
-# or (at your option) any later version.
-#
-# This is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License with
-# the Debian operating system, in /usr/share/common-licenses/GPL;  if
-# not, write to the Free Software Foundation, Inc., 59 Temple Place,
-# Suite 330, Boston, MA 02111-1307 USA
-#
-### BEGIN INIT INFO
-# Provides:          ibus-pinyin
-# Required-Start:    $network $local_fs
-# Required-Stop:     
-# Should-Start:      $named
-# Should-Stop:       
-# Default-Start:     2 3 4 5
-# Default-Stop:      0 1 6
-# Short-Description: <Enter a short description of the sortware>
-# Description:       <Enter a long description of the software>
-#                    <...>
-#                    <...>
-### END INIT INFO
-
-PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
-
-DAEMON=/usr/sbin/ibus-pinyin # Introduce the server's location here
-NAME=#PACKAGE              # Introduce the short server's name here
-DESC=#PACKAGE              # Introduce a short description here
-LOGDIR=/var/log/ibus-pinyin  # Log directory to use
-
-PIDFILE=/var/run/$NAME.pid 
-
-test -x $DAEMON || exit 0
-test -x $DAEMON_WRAPPER || exit 0
-
-. /lib/lsb/init-functions
-
-# Default options, these can be overriden by the information
-# at /etc/default/$NAME
-DAEMON_OPTS=""          # Additional options given to the server 
-
-DODTIME=10              # Time to wait for the server to die, in seconds
-                        # If this value is set too low you might not
-                        # let some servers to die gracefully and
-                        # 'restart' will not work
-                        
-LOGFILE=$LOGDIR/$NAME.log  # Server logfile
-#DAEMONUSER=ibus-pinyin   # Users to run the daemons as. If this value
-                        # is set start-stop-daemon will chuid the server
-
-# Include defaults if available
-if [ -f /etc/default/$NAME ] ; then
-       . /etc/default/$NAME
-fi
-
-# Use this if you want the user to explicitly set 'RUN' in 
-# /etc/default/
-#if [ "x$RUN" != "xyes" ] ; then
-#    log_failure_msg "$NAME disabled, please adjust the configuration to your needs "
-#    log_failure_msg "and then set RUN to 'yes' in /etc/default/$NAME to enable it."
-#    exit 1
-#fi
-
-# Check that the user exists (if we set a user)
-# Does the user exist?
-if [ -n "$DAEMONUSER" ] ; then
-    if getent passwd | grep -q "^$DAEMONUSER:"; then
-        # Obtain the uid and gid
-        DAEMONUID=`getent passwd |grep "^$DAEMONUSER:" | awk -F : '{print $3}'`
-        DAEMONGID=`getent passwd |grep "^$DAEMONUSER:" | awk -F : '{print $4}'`
-    else
-        log_failure_msg "The user $DAEMONUSER, required to run $NAME does not exist."
-        exit 1
-    fi
-fi
-
-
-set -e
-
-running_pid() {
-# Check if a given process pid's cmdline matches a given name
-    pid=$1
-    name=$2
-    [ -z "$pid" ] && return 1 
-    [ ! -d /proc/$pid ] &&  return 1
-    cmd=`cat /proc/$pid/cmdline | tr "\000" "\n"|head -n 1 |cut -d : -f 1`
-    # Is this the expected server
-    [ "$cmd" != "$name" ] &&  return 1
-    return 0
-}
-
-running() {
-# Check if the process is running looking at /proc
-# (works for all users)
-
-    # No pidfile, probably no daemon present
-    [ ! -f "$PIDFILE" ] && return 1
-    pid=`cat $PIDFILE`
-    running_pid $pid $DAEMON_WRAPPER || return 1
-    return 0
-}
-
-start_server() {
-# Start the process using the wrapper
-        if [ -z "$DAEMONUSER" ] ; then
-            start-stop-daemon --start --quiet --pidfile $PIDFILE \
-                        --exec $DAEMON -- $DAEMON_OPTS
-            errcode=$?
-        else
-# if we are using a daemonuser then change the user id
-            start-stop-daemon --start --quiet --pidfile $PIDFILE \
-                        --chuid $DAEMONUSER \
-                        --exec $DAEMON -- $DAEMON_OPTS
-            errcode=$?
-        fi
-       return $errcode
-}
-
-stop_server() {
-# Stop the process using the wrapper
-        if [ -z "$DAEMONUSER" ] ; then
-            start-stop-daemon --stop --quiet --pidfile $PIDFILE \
-                        --exec $DAEMON
-            errcode=$
-        else
-# if we are using a daemonuser then look for process that match
-            start-stop-daemon --stop --quiet --pidfile $PIDFILE \
-                        --user $DAEMONUSER \
-                        --exec $DAEMON
-            errcode=$
-        fi
-
-       return $errcode
-}
-
-reload_server() {
-    [ ! -f "$PIDFILE" ] && return 1
-    pid=`cat $PIDFILE` # This is the daemon's pid
-    # Send a SIGHUP
-    kill -1 $pid
-    return $?
-}
-
-force_stop() {
-# Force the process to die killing it manually
-       [ ! -e "$PIDFILE" ] && return
-       if running ; then
-               kill -15 $pid
-       # Is it really dead?
-               sleep "$DIETIME"s
-               if running ; then
-                       kill -9 $pid
-                       sleep "$DIETIME"s
-                       if running ; then
-                               echo "Cannot kill $NAME (pid=$pid)!"
-                               exit 1
-                       fi
-               fi
-       fi
-       rm -f $PIDFILE
-}
-
-
-case "$1" in
-  start)
-       log_daemon_msg "Starting $DESC " "$NAME"
-        # Check if it's running first
-        if running ;  then
-            log_progress_msg "apparently already running"
-            log_end_msg 0
-            exit 0
-        fi
-        if start_server && running ;  then
-            # It's ok, the server started and is running
-            log_end_msg 0
-        else
-            # Either we could not start it or it is not running
-            # after we did
-            # NOTE: Some servers might die some time after they start,
-            # this code does not try to detect this and might give
-            # a false positive (use 'status' for that)
-            log_end_msg 1
-        fi
-       ;;
-  stop)
-        log_daemon_msg "Stopping $DESC" "$NAME"
-        if running ; then
-            # Only stop the server if we see it running
-            stop_server
-            log_end_msg $?
-        else
-            # If it's not running don't do anything
-            log_progress_msg "apparently not running"
-            log_end_msg 0
-            exit 0
-        fi
-        ;;
-  force-stop)
-        # First try to stop gracefully the program
-        $0 stop
-        if running; then
-            # If it's still running try to kill it more forcefully
-            log_daemon_msg "Stopping (force) $DESC" "$NAME"
-            force_stop
-            log_end_msg $?
-        fi
-       ;;
-  restart|force-reload)
-        log_daemon_msg "Restarting $DESC" "$NAME"
-        stop_server
-        # Wait some sensible amount, some server need this
-        [ -n "$DIETIME" ] && sleep $DIETIME
-        start_server
-        running
-        log_end_msg $?
-       ;;
-  status)
-
-        log_daemon_msg "Checking status of $DESC" "$NAME"
-        if running ;  then
-            log_progress_msg "running"
-            log_end_msg 0
-        else
-            log_progress_msg "apparently not running"
-            log_end_msg 1
-            exit 1
-        fi
-        ;;
-  # Use this if the daemon cannot reload
-  reload)
-        log_warning_msg "Reloading $NAME daemon: not implemented, as the daemon"
-        log_warning_msg "cannot re-read the config file (use restart)."
-        ;;
-  # And this if it cann
-  #reload)
-          #
-          # If the daemon can reload its config files on the fly
-          # for example by sending it SIGHUP, do it here.
-          #
-          # If the daemon responds to changes in its config file
-          # directly anyway, make this a do-nothing entry.
-          #
-          # log_daemon_msg "Reloading $DESC configuration files" "$NAME"
-          # if running ; then
-          #    reload_server
-          #    if ! running ;  then
-          # Process died after we tried to reload
-          #       log_progress_msg "died on reload"
-          #       log_end_msg 1
-          #       exit 1
-          #    fi
-          # else
-          #    log_progress_msg "server is not running"
-          #    log_end_msg 1
-          #    exit 1
-          # fi
-                                                                                    #;;
-
-  *)
-       N=/etc/init.d/$NAME
-       echo "Usage: $N {start|stop|force-stop|restart|force-reload|status}" >&2
-       exit 1
-       ;;
-esac
-
-exit 0
diff --git a/debian/manpage.1.ex b/debian/manpage.1.ex
deleted file mode 100644 (file)
index 15dae44..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-.\"                                      Hey, EMACS: -*- nroff -*-
-.\" First parameter, NAME, should be all caps
-.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
-.\" other parameters are allowed: see man(7), man(1)
-.TH IBUS-PINYIN SECTION "九月 11, 2008"
-.\" Please adjust this date whenever revising the manpage.
-.\"
-.\" Some roff macros, for reference:
-.\" .nh        disable hyphenation
-.\" .hy        enable hyphenation
-.\" .ad l      left justify
-.\" .ad b      justify to both left and right margins
-.\" .nf        disable filling
-.\" .fi        enable filling
-.\" .br        insert line break
-.\" .sp <n>    insert n+1 empty lines
-.\" for manpage-specific macros, see man(7)
-.SH NAME
-ibus-pinyin \- program to do something
-.SH SYNOPSIS
-.B ibus-pinyin
-.RI [ options ] " files" ...
-.br
-.B bar
-.RI [ options ] " files" ...
-.SH DESCRIPTION
-This manual page documents briefly the
-.B ibus-pinyin
-and
-.B bar
-commands.
-.PP
-.\" TeX users may be more comfortable with the \fB<whatever>\fP and
-.\" \fI<whatever>\fP escape sequences to invode bold face and italics, 
-.\" respectively.
-\fBibus-pinyin\fP is a program that...
-.SH OPTIONS
-These programs follow the usual GNU command line syntax, with long
-options starting with two dashes (`-').
-A summary of options is included below.
-For a complete description, see the Info files.
-.TP
-.B \-h, \-\-help
-Show summary of options.
-.TP
-.B \-v, \-\-version
-Show version of program.
-.SH SEE ALSO
-.BR bar (1),
-.BR baz (1).
-.br
-The programs are documented fully by
-.IR "The Rise and Fall of a Fooish Bar" ,
-available via the Info system.
-.SH AUTHOR
-ibus-pinyin was written by <upstream author>.
-.PP
-This manual page was written by oneleaf <oneleaf@gmail.com>,
-for the Debian project (but may be used by others).
diff --git a/debian/manpage.sgml.ex b/debian/manpage.sgml.ex
deleted file mode 100644 (file)
index 5adbcb0..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
-
-<!-- Process this file with docbook-to-man to generate an nroff manual
-     page: `docbook-to-man manpage.sgml > manpage.1'.  You may view
-     the manual page with: `docbook-to-man manpage.sgml | nroff -man |
-     less'.  A typical entry in a Makefile or Makefile.am is:
-
-manpage.1: manpage.sgml
-       docbook-to-man $< > $@
-
-    
-       The docbook-to-man binary is found in the docbook-to-man package.
-       Please remember that if you create the nroff version in one of the
-       debian/rules file targets (such as build), you will need to include
-       docbook-to-man in your Build-Depends control field.
-
-  -->
-
-  <!-- Fill in your name for FIRSTNAME and SURNAME. -->
-  <!ENTITY dhfirstname "<firstname>FIRSTNAME</firstname>">
-  <!ENTITY dhsurname   "<surname>SURNAME</surname>">
-  <!-- Please adjust the date whenever revising the manpage. -->
-  <!ENTITY dhdate      "<date>九月 11, 2008</date>">
-  <!-- SECTION should be 1-8, maybe w/ subsection other parameters are
-       allowed: see man(7), man(1). -->
-  <!ENTITY dhsection   "<manvolnum>SECTION</manvolnum>">
-  <!ENTITY dhemail     "<email>oneleaf@gmail.com</email>">
-  <!ENTITY dhusername  "oneleaf">
-  <!ENTITY dhucpackage "<refentrytitle>IBUS-PINYIN</refentrytitle>">
-  <!ENTITY dhpackage   "ibus-pinyin">
-
-  <!ENTITY debian      "<productname>Debian</productname>">
-  <!ENTITY gnu         "<acronym>GNU</acronym>">
-  <!ENTITY gpl         "&gnu; <acronym>GPL</acronym>">
-]>
-
-<refentry>
-  <refentryinfo>
-    <address>
-      &dhemail;
-    </address>
-    <author>
-      &dhfirstname;
-      &dhsurname;
-    </author>
-    <copyright>
-      <year>2003</year>
-      <holder>&dhusername;</holder>
-    </copyright>
-    &dhdate;
-  </refentryinfo>
-  <refmeta>
-    &dhucpackage;
-
-    &dhsection;
-  </refmeta>
-  <refnamediv>
-    <refname>&dhpackage;</refname>
-
-    <refpurpose>program to do something</refpurpose>
-  </refnamediv>
-  <refsynopsisdiv>
-    <cmdsynopsis>
-      <command>&dhpackage;</command>
-
-      <arg><option>-e <replaceable>this</replaceable></option></arg>
-
-      <arg><option>--example <replaceable>that</replaceable></option></arg>
-    </cmdsynopsis>
-  </refsynopsisdiv>
-  <refsect1>
-    <title>DESCRIPTION</title>
-
-    <para>This manual page documents briefly the
-      <command>&dhpackage;</command> and <command>bar</command>
-      commands.</para>
-
-    <para>This manual page was written for the &debian; distribution
-      because the original program does not have a manual page.
-      Instead, it has documentation in the &gnu;
-      <application>Info</application> format; see below.</para>
-
-    <para><command>&dhpackage;</command> is a program that...</para>
-
-  </refsect1>
-  <refsect1>
-    <title>OPTIONS</title>
-
-    <para>These programs follow the usual &gnu; command line syntax,
-      with long options starting with two dashes (`-').  A summary of
-      options is included below.  For a complete description, see the
-      <application>Info</application> files.</para>
-
-    <variablelist>
-      <varlistentry>
-        <term><option>-h</option>
-          <option>--help</option>
-        </term>
-        <listitem>
-          <para>Show summary of options.</para>
-        </listitem>
-      </varlistentry>
-      <varlistentry>
-        <term><option>-v</option>
-          <option>--version</option>
-        </term>
-        <listitem>
-          <para>Show version of program.</para>
-        </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-  <refsect1>
-    <title>SEE ALSO</title>
-
-    <para>bar (1), baz (1).</para>
-
-    <para>The programs are documented fully by <citetitle>The Rise and
-      Fall of a Fooish Bar</citetitle> available via the
-      <application>Info</application> system.</para>
-  </refsect1>
-  <refsect1>
-    <title>AUTHOR</title>
-
-    <para>This manual page was written by &dhusername; &dhemail; for
-      the &debian; system (but may be used by others).  Permission is
-      granted to copy, distribute and/or modify this document under
-      the terms of the &gnu; General Public License, Version 2 any 
-         later version published by the Free Software Foundation.
-    </para>
-       <para>
-         On Debian systems, the complete text of the GNU General Public
-         License can be found in /usr/share/common-licenses/GPL.
-       </para>
-
-  </refsect1>
-</refentry>
-
-<!-- Keep this comment at the end of the file
-Local variables:
-mode: sgml
-sgml-omittag:t
-sgml-shorttag:t
-sgml-minimize-attributes:nil
-sgml-always-quote-attributes:t
-sgml-indent-step:2
-sgml-indent-data:t
-sgml-parent-document:nil
-sgml-default-dtd-file:nil
-sgml-exposed-tags:nil
-sgml-local-catalogs:nil
-sgml-local-ecat-files:nil
-End:
--->
-
-
diff --git a/debian/manpage.xml.ex b/debian/manpage.xml.ex
deleted file mode 100644 (file)
index b99a183..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-<?xml version='1.0' encoding='ISO-8859-1'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
-
-<!--
-
-Process this file with an XSLT processor: `xsltproc \
--''-nonet /usr/share/sgml/docbook/stylesheet/xsl/nwalsh/\
-manpages/docbook.xsl manpage.dbk'.  A manual page
-<package>.<section> will be generated.  You may view the
-manual page with: nroff -man <package>.<section> | less'.  A
-typical entry in a Makefile or Makefile.am is:
-
-DB2MAN=/usr/share/sgml/docbook/stylesheet/xsl/nwalsh/\
-manpages/docbook.xsl
-XP=xsltproc -''-nonet
-
-manpage.1: manpage.dbk
-        $(XP) $(DB2MAN) $<
-    
-The xsltproc binary is found in the xsltproc package.  The
-XSL files are in docbook-xsl.  Please remember that if you
-create the nroff version in one of the debian/rules file
-targets (such as build), you will need to include xsltproc
-and docbook-xsl in your Build-Depends control field.
-
--->
-
-  <!-- Fill in your name for FIRSTNAME and SURNAME. -->
-  <!ENTITY dhfirstname "<firstname>FIRSTNAME</firstname>">
-  <!ENTITY dhsurname   "<surname>SURNAME</surname>">
-  <!-- Please adjust the date whenever revising the manpage. -->
-  <!ENTITY dhdate      "<date>九月 11, 2008</date>">
-  <!-- SECTION should be 1-8, maybe w/ subsection other parameters are
-       allowed: see man(7), man(1). -->
-  <!ENTITY dhsection   "<manvolnum>SECTION</manvolnum>">
-  <!ENTITY dhemail     "<email>oneleaf@gmail.com</email>">
-  <!ENTITY dhusername  "oneleaf">
-  <!ENTITY dhucpackage "<refentrytitle>IBUS-PINYIN</refentrytitle>">
-  <!ENTITY dhpackage   "ibus-pinyin">
-
-  <!ENTITY debian      "<productname>Debian</productname>">
-  <!ENTITY gnu         "<acronym>GNU</acronym>">
-  <!ENTITY gpl         "&gnu; <acronym>GPL</acronym>">
-]>
-
-<refentry>
-  <refentryinfo>
-    <address>
-      &dhemail;
-    </address>
-    <copyright>
-      <year>2007</year>
-      <holder>&dhusername;</holder>
-    </copyright>
-    &dhdate;
-  </refentryinfo>
-  <refmeta>
-    &dhucpackage;
-
-    &dhsection;
-  </refmeta>
-  <refnamediv>
-    <refname>&dhpackage;</refname>
-
-    <refpurpose>program to do something</refpurpose>
-  </refnamediv>
-  <refsynopsisdiv>
-    <cmdsynopsis>
-      <command>&dhpackage;</command>
-
-      <arg><option>-e <replaceable>this</replaceable></option></arg>
-
-      <arg><option>--example <replaceable>that</replaceable></option></arg>
-    </cmdsynopsis>
-  </refsynopsisdiv>
-  <refsect1>
-    <title>DESCRIPTION</title>
-
-    <para>This manual page documents briefly the
-      <command>&dhpackage;</command> and <command>bar</command>
-      commands.</para>
-
-    <para>This manual page was written for the &debian; distribution
-      because the original program does not have a manual page.
-      Instead, it has documentation in the &gnu;
-      <application>Info</application> format; see below.</para>
-
-    <para><command>&dhpackage;</command> is a program that...</para>
-
-  </refsect1>
-  <refsect1>
-    <title>OPTIONS</title>
-
-    <para>These programs follow the usual &gnu; command line syntax,
-      with long options starting with two dashes (`-').  A summary of
-      options is included below.  For a complete description, see the
-      <application>Info</application> files.</para>
-
-    <variablelist>
-      <varlistentry>
-        <term><option>-h</option>
-          <option>--help</option>
-        </term>
-        <listitem>
-          <para>Show summary of options.</para>
-        </listitem>
-      </varlistentry>
-      <varlistentry>
-        <term><option>-v</option>
-          <option>--version</option>
-        </term>
-        <listitem>
-          <para>Show version of program.</para>
-        </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-  <refsect1>
-    <title>SEE ALSO</title>
-
-    <para>bar (1), baz (1).</para>
-
-    <para>The programs are documented fully by <citetitle>The Rise and
-      Fall of a Fooish Bar</citetitle> available via the
-      <application>Info</application> system.</para>
-  </refsect1>
-  <refsect1>
-    <title>AUTHOR</title>
-
-    <para>This manual page was written by &dhusername; &dhemail; for
-      the &debian; system (but may be used by others).  Permission is
-      granted to copy, distribute and/or modify this document under
-      the terms of the &gnu; General Public License, Version 2 any 
-         later version published by the Free Software Foundation.
-    </para>
-       <para>
-         On Debian systems, the complete text of the GNU General Public
-         License can be found in /usr/share/common-licenses/GPL.
-       </para>
-
-  </refsect1>
-</refentry>
-
diff --git a/debian/menu.ex b/debian/menu.ex
deleted file mode 100644 (file)
index 67524d6..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-?package(ibus-pinyin):needs="X11|text|vc|wm" section="Applications/see-menu-manual"\
-  title="ibus-pinyin" command="/usr/bin/ibus-pinyin"
diff --git a/debian/postinst.ex b/debian/postinst.ex
deleted file mode 100644 (file)
index 6094692..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/bin/sh
-# postinst script for ibus-pinyin
-#
-# see: dh_installdeb(1)
-
-set -e
-
-# summary of how this script can be called:
-#        * <postinst> `configure' <most-recently-configured-version>
-#        * <old-postinst> `abort-upgrade' <new version>
-#        * <conflictor's-postinst> `abort-remove' `in-favour' <package>
-#          <new-version>
-#        * <postinst> `abort-remove'
-#        * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
-#          <failed-install-package> <version> `removing'
-#          <conflicting-package> <version>
-# for details, see http://www.debian.org/doc/debian-policy/ or
-# the debian-policy package
-
-
-case "$1" in
-    configure)
-    ;;
-
-    abort-upgrade|abort-remove|abort-deconfigure)
-    ;;
-
-    *)
-        echo "postinst called with unknown argument \`$1'" >&2
-        exit 1
-    ;;
-esac
-
-# dh_installdeb will replace this with shell code automatically
-# generated by other debhelper scripts.
-
-#DEBHELPER#
-
-exit 0
-
-
diff --git a/debian/postrm.ex b/debian/postrm.ex
deleted file mode 100644 (file)
index e56c758..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/sh
-# postrm script for ibus-pinyin
-#
-# see: dh_installdeb(1)
-
-set -e
-
-# summary of how this script can be called:
-#        * <postrm> `remove'
-#        * <postrm> `purge'
-#        * <old-postrm> `upgrade' <new-version>
-#        * <new-postrm> `failed-upgrade' <old-version>
-#        * <new-postrm> `abort-install'
-#        * <new-postrm> `abort-install' <old-version>
-#        * <new-postrm> `abort-upgrade' <old-version>
-#        * <disappearer's-postrm> `disappear' <overwriter>
-#          <overwriter-version>
-# for details, see http://www.debian.org/doc/debian-policy/ or
-# the debian-policy package
-
-
-case "$1" in
-    purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
-    ;;
-
-    *)
-        echo "postrm called with unknown argument \`$1'" >&2
-        exit 1
-    ;;
-esac
-
-# dh_installdeb will replace this with shell code automatically
-# generated by other debhelper scripts.
-
-#DEBHELPER#
-
-exit 0
-
-
diff --git a/debian/preinst.ex b/debian/preinst.ex
deleted file mode 100644 (file)
index a3dd684..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/bin/sh
-# preinst script for ibus-pinyin
-#
-# see: dh_installdeb(1)
-
-set -e
-
-# summary of how this script can be called:
-#        * <new-preinst> `install'
-#        * <new-preinst> `install' <old-version>
-#        * <new-preinst> `upgrade' <old-version>
-#        * <old-preinst> `abort-upgrade' <new-version>
-# for details, see http://www.debian.org/doc/debian-policy/ or
-# the debian-policy package
-
-
-case "$1" in
-    install|upgrade)
-    ;;
-
-    abort-upgrade)
-    ;;
-
-    *)
-        echo "preinst called with unknown argument \`$1'" >&2
-        exit 1
-    ;;
-esac
-
-# dh_installdeb will replace this with shell code automatically
-# generated by other debhelper scripts.
-
-#DEBHELPER#
-
-exit 0
-
-
diff --git a/debian/prerm.ex b/debian/prerm.ex
deleted file mode 100644 (file)
index a237b14..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/bin/sh
-# prerm script for ibus-pinyin
-#
-# see: dh_installdeb(1)
-
-set -e
-
-# summary of how this script can be called:
-#        * <prerm> `remove'
-#        * <old-prerm> `upgrade' <new-version>
-#        * <new-prerm> `failed-upgrade' <old-version>
-#        * <conflictor's-prerm> `remove' `in-favour' <package> <new-version>
-#        * <deconfigured's-prerm> `deconfigure' `in-favour'
-#          <package-being-installed> <version> `removing'
-#          <conflicting-package> <version>
-# for details, see http://www.debian.org/doc/debian-policy/ or
-# the debian-policy package
-
-
-case "$1" in
-    remove|upgrade|deconfigure)
-    ;;
-
-    failed-upgrade)
-    ;;
-
-    *)
-        echo "prerm called with unknown argument \`$1'" >&2
-        exit 1
-    ;;
-esac
-
-# dh_installdeb will replace this with shell code automatically
-# generated by other debhelper scripts.
-
-#DEBHELPER#
-
-exit 0
-
-
diff --git a/debian/rules b/debian/rules
deleted file mode 100644 (file)
index 222c57f..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-#!/usr/bin/make -f
-# -*- makefile -*-
-# Sample debian/rules that uses debhelper.
-# This file was originally written by Joey Hess and Craig Small.
-# As a special exception, when this file is copied by dh-make into a
-# dh-make output file, you may use that output file without restriction.
-# This special exception was added by Craig Small in version 0.37 of dh-make.
-
-# Uncomment this to turn on verbose mode.
-#export DH_VERBOSE=1
-
-
-# These are used for cross-compiling and for saving the configure script
-# from having to guess our platform (since we know it already)
-DEB_HOST_GNU_TYPE   ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
-DEB_BUILD_GNU_TYPE  ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
-
-
-config.status: configure
-       dh_testdir
-       # Add here commands to configure the package.
-ifneq "$(wildcard /usr/share/misc/config.sub)" ""
-       cp -f /usr/share/misc/config.sub config.sub
-endif
-ifneq "$(wildcard /usr/share/misc/config.guess)" ""
-       cp -f /usr/share/misc/config.guess config.guess
-endif
-       ./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info CFLAGS="$(CFLAGS)" LDFLAGS="-Wl,-z,defs"
-
-
-build: build-stamp
-
-build-stamp:  config.status
-       dh_testdir
-
-       # Add here commands to compile the package.
-       $(MAKE)
-       #docbook-to-man debian/ibus-pinyin.sgml > ibus-pinyin.1
-
-       touch $@
-
-clean:
-       dh_testdir
-       dh_testroot
-       rm -f build-stamp 
-
-       # Add here commands to clean up after the build process.
-       -$(MAKE) distclean
-       rm -f config.sub config.guess
-
-       dh_clean 
-
-install: build
-       dh_testdir
-       dh_testroot
-       dh_clean -k 
-       dh_installdirs
-
-       # Add here commands to install the package into debian/ibus-pinyin.
-       $(MAKE) DESTDIR=$(CURDIR)/debian/ibus-pinyin install
-
-
-# Build architecture-independent files here.
-binary-indep: build install
-# We have nothing to do by default.
-
-# Build architecture-dependent files here.
-binary-arch: build install
-       dh_testdir
-       dh_testroot
-       dh_installchangelogs ChangeLog
-       dh_installdocs
-       dh_installexamples
-#      dh_install
-#      dh_installmenu
-#      dh_installdebconf       
-#      dh_installlogrotate
-#      dh_installemacsen
-#      dh_installpam
-#      dh_installmime
-#      dh_python
-#      dh_installinit
-#      dh_installcron
-#      dh_installinfo
-       dh_installman
-       dh_link
-       dh_strip
-       dh_compress
-       dh_fixperms
-#      dh_perl
-#      dh_makeshlibs
-       dh_installdeb
-       dh_shlibdeps
-       dh_gencontrol
-       dh_md5sums
-       dh_builddeb
-
-binary: binary-indep binary-arch
-.PHONY: build clean binary-indep binary-arch binary install 
diff --git a/debian/watch.ex b/debian/watch.ex
deleted file mode 100644 (file)
index 545b10f..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-# Example watch control file for uscan
-# Rename this file to "watch" and then you can run the "uscan" command
-# to check for upstream updates and more.
-# See uscan(1) for format
-
-# Compulsory line, this is a version 3 file
-version=3
-
-# Uncomment to examine a Webpage 
-# <Webpage URL> <string match>
-#http://www.example.com/downloads.php ibus-pinyin-(.*)\.tar\.gz
-
-# Uncomment to examine a Webserver directory
-#http://www.example.com/pub/ibus-pinyin-(.*)\.tar\.gz
-
-# Uncommment to examine a FTP server
-#ftp://ftp.example.com/pub/ibus-pinyin-(.*)\.tar\.gz debian uupdate
-
-# Uncomment to find new files on sourceforge, for debscripts >= 2.9
-# http://sf.net/ibus-pinyin/ibus-pinyin-(.*)\.tar\.gz
-
-
diff --git a/engine/Makefile.am b/engine/Makefile.am
deleted file mode 100644 (file)
index aaae759..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-# vim:set noet ts=4:
-#
-# ibus-pinyin - The PinYin engine for IBus
-#
-# Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-engine_pinyin_PYTHON = \
-       factory.py \
-       main.py \
-       pinyin.py \
-       pydict.py \
-       pyparser.py \
-       specialphrase.py \
-       specialtable.py \
-       pysqlitedb.py \
-       pyutil.py \
-       $(NULL)
-engine_pinyin_DATA = \
-       special_phrase \
-       special_table \
-       py.db \
-       $(NULL)
-engine_pinyindir = $(datadir)/ibus-pinyin/engine
-
-libexec_SCRIPTS = ibus-engine-pinyin
-
-engine_DATA = pinyin.xml
-enginedir = $(datadir)/ibus/component
-
-DBVER = 0.1.10.6
-DBTAR = pinyin-database-${DBVER}.tar.bz2
-
-${DBTAR}:
-       wget http://ibus.googlecode.com/files/${DBTAR}
-
-py.db: ${DBTAR}
-       tar jxvfm ${DBTAR}
-
-
-EXTRA_DIST = \
-       ibus-engine-pinyin.in \
-       pinyin.xml.in \
-       special_phrase \
-       special_table \
-       $(NULL)
-
-CLEANFILES = \
-       pinyin.xml \
-       *.pyc \
-       py.db \
-       $(DBTAR) \
-       $(NULL)
-
-pinyin.xml: pinyin.xml.in
-       ( \
-               libexecdir=${libexecdir}; \
-               pkgdatadir=${pkgdatadir}; \
-               s=`cat $<`; \
-               eval "echo \"$${s}\""; \
-       ) > $@
-
-test:
-       $(ENV) \
-               IBUS_PINYIN_LOCATION=$(abs_top_srcdir) \
-               DBUS_DEBUG=true \
-               LANG=en_US \
-               PYTHONPATH=$(abs_top_srcdir):$(pyexecdir) \
-               $(PYTHON) $(srcdir)/main.py
-
-install-data-hook:
-       @(if test "${NO_INDEX}" = ""; then \
-               cd $(DESTDIR)$(engine_pinyindir); \
-               echo "Creating INDEX"; \
-               $(PYTHON) -c "import pysqlitedb; db = pysqlitedb.PYSQLiteDB (filename='py.db'); db.create_indexes ();" ;\
-       fi)
-
diff --git a/engine/factory.py b/engine/factory.py
deleted file mode 100644 (file)
index 6f66d8b..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-# vim:set et sts=4 sw=4:
-#
-# ibus-tmpl - The Input Bus template project
-#
-# Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-import ibus
-import pinyin
-import os
-
-from gettext import dgettext
-_  = lambda a : dgettext("ibus-pinyin", a)
-N_ = lambda a : a
-
-
-class EngineFactory(ibus.EngineFactoryBase):
-    FACTORY_PATH = "/com/redhat/IBus/engines/PinYin/Factory"
-    ENGINE_PATH = "/com/redhat/IBus/engines/PinYin/Engine"
-    NAME = _("PinYin")
-    LANG = "zh_CN"
-    ICON = os.getenv("IBUS_PINYIN_LOCATION") + "/icons/ibus-pinyin.svg"
-    AUTHORS = "Huang Peng <shawn.p.huang@gmail.com>"
-    CREDITS = "GPLv2"
-
-    def __init__(self, bus):
-        self.__bus = bus
-        pinyin.PinYinEngine.CONFIG_RELOADED(bus)
-        super(EngineFactory, self).__init__(bus)
-
-        self.__id = 0
-        self.__config = self.__bus.get_config()
-
-        self.__config.connect("reloaded", self.__config_reloaded_cb)
-        self.__config.connect("value-changed", self.__config_value_changed_cb)
-
-    def create_engine(self, engine_name):
-        if engine_name == "pinyin":
-            self.__id += 1
-            return pinyin.PinYinEngine(self.__bus, "%s/%d" % (self.ENGINE_PATH, self.__id))
-
-        return super(EngineFactory, self).create_engine(engine_name)
-
-    def __config_reloaded_cb(self, config):
-        pinyin.PinYinEngine.CONFIG_RELOADED(self.__bus)
-
-    def __config_value_changed_cb(self, config, section, name, value):
-        pinyin.PinYinEngine.CONFIG_VALUE_CHANGED(self.__bus, section, name, value)
-
diff --git a/engine/ibus-engine-pinyin.in b/engine/ibus-engine-pinyin.in
deleted file mode 100644 (file)
index 9a3c8bb..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/sh
-# vim:set noet ts=4:
-#
-# ibus-tmpl - The Input Bus template project
-#
-# Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libexecdir=@libexecdir@
-pyexecdir=@pyexecdir@
-export PYTHONPATH=@pyexecdir@:$PYTHONPATH
-export IBUS_PINYIN_LOCATION=@prefix@/share/ibus-pinyin
-export LIBEXECDIR=$libexecdir
-exec python @prefix@/share/ibus-pinyin/engine/main.py $@
-
diff --git a/engine/main.py b/engine/main.py
deleted file mode 100644 (file)
index fd4d88c..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-# vim:set et sts=4 sw=4:
-#
-# ibus-pinyin - The PinYin engine for IBus
-#
-# Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-import os
-import sys
-import getopt
-import ibus
-import gobject
-import factory
-
-class IMApp:
-    def __init__(self, exec_by_ibus):
-        self.__component = ibus.Component("org.freedesktop.IBus.PinYin",
-                                          "Chinese PinYin Component",
-                                          "0.1.0",
-                                          "GPL",
-                                          "Peng Huang <shawn.p.huang@gmail.com>")
-        self.__component.add_engine("pinyin",
-                                    "pinyin",
-                                    "Chinese PinYin",
-                                    "zh_CN",
-                                    "GPL",
-                                    "Peng Huang <shawn.p.huang@gmail.com>",
-                                    "",
-                                    "en")
-        self.__mainloop = gobject.MainLoop()
-        self.__bus = ibus.Bus()
-        self.__bus.connect("destroy", self.__bus_destroy_cb)
-        self.__factory = factory.EngineFactory(self.__bus)
-        if exec_by_ibus:
-            self.__bus.request_name("org.freedesktop.IBus.PinYin", 0)
-        else:
-            self.__bus.register_component(self.__component)
-
-    def run(self):
-        self.__mainloop.run()
-
-    def __bus_destroy_cb(self, bus):
-        self.__mainloop.quit()
-
-
-def launch_engine(exec_by_ibus):
-    IMApp(exec_by_ibus).run()
-
-def print_help(out, v = 0):
-    print >> out, "-i, --ibus             execute by ibus."
-    print >> out, "-h, --help             show this message."
-    print >> out, "-d, --daemonize        daemonize ibus"
-    sys.exit(v)
-
-def main():
-    daemonize = False
-    exec_by_ibus = False
-    shortopt = "hdi"
-    longopt = ["help", "daemonize", "ibus"]
-    try:
-        opts, args = getopt.getopt(sys.argv[1:], shortopt, longopt)
-    except getopt.GetoptError, err:
-        print_help(sys.stderr, 1)
-
-    for o, a in opts:
-        if o in("-h", "--help"):
-            print_help(sys.stdout)
-        elif o in ("-d", "--daemonize"):
-            daemonize = True
-        elif o in ("-i", "--ibus"):
-            exec_by_ibus = True
-        else:
-            print >> sys.stderr, "Unknown argument: %s" % o
-            print_help(sys.stderr, 1)
-
-    if daemonize:
-        if os.fork():
-            sys.exit()
-
-    launch_engine(exec_by_ibus)
-
-if __name__ == "__main__":
-    main()
diff --git a/engine/pinyin.py b/engine/pinyin.py
deleted file mode 100644 (file)
index 4182336..0000000
+++ /dev/null
@@ -1,1317 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim:set et sts=4 sw=4:
-#
-# ibus-pinyin - The PinYin engine for IBus
-#
-# Copyright(c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or(at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-__all__ = (
-    "PinYinEngine",
-)
-import ibus
-import gobject
-import os
-import signal
-import os.path as path
-from ibus import keysyms
-from ibus import modifier
-from ibus import ascii
-
-import pyparser
-import pysqlitedb
-from specialtable import SpecialTable
-from specialphrase import SpecialPhrase
-import pyutil
-import pydict
-
-from gettext import dgettext
-_  = lambda a : dgettext("ibus-pinyin", a)
-N_ = lambda a : a
-
-IBUS_PINYIN_LOCATION = os.getenv("IBUS_PINYIN_LOCATION")
-LIBEXECDIR = os.getenv("LIBEXECDIR")
-
-__MAX_LEN__ = 64        # Max length of preedit pinyin
-
-# Define colours
-RGB = lambda r, g, b : (((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff) )
-
-try:
-    import enchant
-    __EN_DICT__ = enchant.Dict("en_US")
-except:
-    class MY_DICT:
-        def __init__(self):
-            pass
-        def suggest(self, word):
-            return []
-        def check(self, word):
-            return True
-    __EN_DICT__ = MY_DICT()
-
-
-
-class PinYinEngine(ibus.EngineBase):
-
-    # create pinyin database
-    __pydb = pysqlitedb.PYSQLiteDB(user_db = "user.db")
-
-    # create special table
-    __special_phrase = SpecialPhrase()
-    __special_table = SpecialTable()
-
-    # shuang pin
-    __shuangpin = False
-    __shuangpin_schema = "MSPY"
-
-    # gbk
-    __gbk = False
-
-    # fuzzy pinyin & auto correct
-    __fuzzy_pinyin = False
-    __auto_correct = True
-    __spell_check = True
-
-    # colors
-    __phrase_color = RGB(0, 0, 0)
-    __user_phrase_color = RGB(0, 0, 0xef)
-    __new_phrase_color = RGB(0xef, 0, 0)
-    __special_phrase_color = RGB(0, 0xbf, 0)
-    __english_phrase_color = RGB(0, 0xbf, 0)
-    __error_eng_phrase_color = RGB(0xef, 0, 0)
-
-    # lookup table page size
-    __page_size = 5
-
-    # press [u] or [v] to temp English mode
-    __uv_to_temp = True
-
-    # press [shift] to select candidates
-    __shift_select_candidates = True
-
-    # press [-] [=] to page down & up candidates
-    __equal_page_down_up = True
-
-    # press [,] [.] to page down & up candidates
-    __comma_page_down_up = True
-
-    # auto commit
-    __auto_commit = False
-
-    # setup pid
-    __setup_pid = 0
-
-    # half punctuations
-    __half_puncts = u"+-*/=%"
-
-
-    def __init__(self, conn, object_path):
-        super(PinYinEngine, self).__init__(conn, object_path)
-
-        self.__need_update = False
-        self.__lookup_table = ibus.LookupTable(PinYinEngine.__page_size)
-
-        self.__py_parser = pyparser.PinYinParser()
-        self.__user_input = UserInput(self.__py_parser)
-
-        # 0 = english input mode
-        # 1 = chinese input mode
-        self.__mode = 1
-        self.__full_width_letter = [False, False]
-        self.__full_width_punct = [False, True]
-        self.__full_width_punct[1] = True #config.get_value("engine/PinYin/FullWidthPunct", True)
-
-        self.__committed_phrases = PhraseList()
-        self.__preedit_phrases = PhraseList()
-        self.reset()
-
-        # init properties
-        self.__prop_list = ibus.PropList()
-        self.__status_property = ibus.Property(u"status")
-        self.__prop_list.append(self.__status_property)
-        self.__letter_property = ibus.Property(u"full_letter")
-        self.__prop_list.append(self.__letter_property)
-        self.__punct_property = ibus.Property(u"full_punct")
-        self.__prop_list.append(self.__punct_property)
-        # self.__shuangpin_property = ibus.Property("shuangpin")
-        # self.__prop_list.append(self.__shuangpin_property)
-        # self.__gbk_property = ibus.Property("gbk")
-        # self.__prop_list.append(self.__gbk_property)
-        self.__setup_property = ibus.Property(u"setup")
-        self.__setup_property.tooltip = _(u"Configure PinYin")
-        self.__prop_list.append(self.__setup_property)
-
-
-    def __refresh_properties(self):
-        if self.__mode == 1: # refresh mode
-            self.__status_property.icon = path.join(IBUS_PINYIN_LOCATION, "icons", "chinese.svg")
-            self.__status_property.label = _(u"CN")
-            self.__status_property.tooltip = _(u"Switch to English mode")
-        else:
-            self.__status_property.icon = path.join(IBUS_PINYIN_LOCATION, "icons", "english.svg")
-            self.__status_property.label = _(u"EN")
-            self.__status_property.tooltip = _(u"Switch to Chinese mode")
-
-        if self.__full_width_letter[self.__mode]:
-            self.__letter_property.icon = path.join(IBUS_PINYIN_LOCATION, "icons", "full-letter.svg")
-            self.__letter_property.label = u"Aa"
-            self.__letter_property.tooltip = _(u"Switch to half letter mode")
-        else:
-            self.__letter_property.icon = path.join(IBUS_PINYIN_LOCATION, "icons", "half-letter.svg")
-            self.__letter_property.label = u"Aa"
-            self.__letter_property.tooltip = _(u"Switch to full letter mode")
-
-        if self.__full_width_punct[self.__mode]:
-            self.__punct_property.icon = path.join(IBUS_PINYIN_LOCATION, "icons", "full-punct.svg")
-            self.__punct_property.label = u",。"
-            self.__punct_property.tooltip = _(u"Switch to half punctuation mode")
-        else:
-            self.__punct_property.icon = path.join(IBUS_PINYIN_LOCATION, "icons", "half-punct.svg")
-            self.__punct_property.label = u".,"
-            self.__punct_property.tooltip = _(u"Switch to full punctuation mode")
-
-        # if PinYinEngine.__shuangpin:
-        #     self.__shuangpin_property.label = _("SHUANG")
-        #     self.__shuangpin_property.tip = _("Switch to QUAN PIN")
-        # else:
-        #     self.__shuangpin_property.label = _("QUAN")
-        #     self.__shuangpin_property.tip = _("Switch to SHUANG PIN")
-
-        # if PinYinEngine.__gbk:
-        #     self.__gbk_property.label = _("GBK")
-        #     self.__gbk_property.tip = _("Switch to GB2312 codeset")
-        # else:
-        #     self.__gbk_property.label = _("GB")
-        #     self.__gbk_property.tip = _("Switch to GBK codeset")
-
-        properties =(
-            self.__status_property,
-            self.__letter_property,
-            self.__punct_property,
-            # self.__shuangpin_property,
-            # self.__gbk_property,
-            )
-
-        for prop in properties:
-            self.update_property(prop)
-
-
-    def __change_mode(self):
-        self.__mode =(self.__mode + 1) % 2
-        self.__refresh_properties()
-
-    def __is_input_english(self):
-        return self.__mode == 0
-
-    def __update_candidates(self):
-        if self.__temp_english_mode:
-            if self.__spell_check == False:
-                return
-            self.__english_candidates = []
-            string = "".join(self.__user_input.get_chars())
-            if string[0] in u"uv":
-                string = string [1:]
-            words = string.split()
-            if not words:
-                return
-            word = words[-1]
-
-            if len(words) == 1 and word[0:1] in u"uv":
-                word = word[1:]
-
-            if not word.isalpha():
-                return
-            if  __EN_DICT__.check(word):
-                return
-            self.__current_word = word
-            candidates = __EN_DICT__.suggest(word)
-            is_same  = lambda x : x[0].isupper() == word[0].isupper()
-            self.__english_candidates = filter(is_same, candidates)[:10]
-            return
-
-        if self.__i_mode:
-            chars = self.__user_input.get_chars()[1:]
-            self.__candidates = self.__special_phrase.lookup(u"".join(chars))
-            self.__candidates += self.__special_table.lookup(u"".join(chars))
-            return
-
-        self.__preedit_phrases.clean()
-
-        if len(self.__user_input.get_pinyin_list()) == 0:
-            self.__candidates = []
-            self.__special_candidates = []
-            return
-
-        if len(self.__committed_phrases) == 0:
-            self.__special_candidates = self.__special_phrase.lookup(u"".join(self.__user_input.get_chars()))
-        else:
-            self.__special_candidates = []
-
-
-        pinyin_list = self.__user_input.get_pinyin_list()
-        pinyin_list = pinyin_list [self.__committed_phrases.length_of_chars():]
-
-
-        if pinyin_list:
-            self.__candidates =  self.__get_candidates(pinyin_list)
-            self.__preedit_phrases.append(self.__candidates[0])
-
-        count = self.__preedit_phrases.length_of_chars()
-
-        while count < len(pinyin_list):
-            candidate = self.__get_a_candidate(pinyin_list[count:])
-            self.__preedit_phrases.append(candidate)
-            count += candidate[pysqlitedb.YLEN]
-
-    def __update_ui(self):
-        if self.__i_mode:
-            preedit_string = u"".join(self.__user_input.get_chars())
-            self.update_preedit(preedit_string, None, len(preedit_string), True)
-
-            self.hide_auxiliary_text()
-
-            self.__lookup_table.clean()
-            self.__lookup_table.show_cursor(True)
-            if not self.__candidates:
-                self.hide_lookup_table()
-            else:
-                for c in self.__candidates:
-                    self.__lookup_table.append_candidate(ibus.Text(c))
-                self.update_lookup_table(self.__lookup_table, True, True)
-            return
-
-        if self.__temp_english_mode:
-            preedit_string = u"".join(self.__user_input.get_chars())
-            if preedit_string [0:1] in(u"v", u"u"):
-                preedit_string = " " + preedit_string[1:]
-            else:
-                preedit_string = " " + preedit_string
-
-            words = preedit_string.split()
-            if words:
-                aux_string = words[-1]
-            else:
-                aux_string = u""
-
-            if preedit_string:
-                self.update_preedit(preedit_string, None, len(preedit_string), True)
-                if self.__spell_check:
-                    attrs = ibus.AttrList()
-                    if aux_string and not __EN_DICT__.check(aux_string):
-                        attr = ibus.AttributeForeground(PinYinEngine.__error_eng_phrase_color, 0, len(aux_string))
-                        attrs.append(attr)
-                    self.update_aux_string(aux_string, attrs, True)
-            else:
-                self.hide_preedit_text()
-                self.hide_auxiliary_text()
-
-
-            self.__lookup_table.clean()
-            self.__lookup_table.show_cursor(False)
-            if not self.__english_candidates:
-                self.hide_lookup_table()
-            else:
-                for c in self.__english_candidates:
-                    attrs = ibus.AttrList()
-                    attr = ibus.AttributeForeground(PinYinEngine.__english_phrase_color, 0, len(c))
-                    attrs.append(attr)
-                    self.__lookup_table.append_candidate(ibus.Text(c, attrs))
-                self.update_lookup_table(self.__lookup_table, True, True)
-
-            return
-
-        if len(self.__candidates) == 0:
-            self.hide_lookup_table()
-        else:
-            self.__lookup_table.clean()
-            candidates = self.__candidates[:]
-            if len(self.__preedit_phrases) != 1: # we need display the automatically created new phrase
-                attrs = ibus.AttrList ()
-                preedit_string = self.__preedit_phrases.get_string()
-                attr = ibus.AttributeForeground(PinYinEngine.__new_phrase_color, 0, len(preedit_string))
-                attrs.append (attr)
-                self.__lookup_table.append_candidate(ibus.Text(preedit_string, attrs))
-            else:
-                c = candidates[0]
-                attrs = ibus.AttrList ()
-                if c[pysqlitedb.FREQ] == None: # This phrase was created by user.
-                    attr = ibus.AttributeForeground(PinYinEngine.__user_phrase_color, 0, c[pysqlitedb.YLEN])
-                else:
-                    attr = ibus.AttributeForeground(PinYinEngine.__phrase_color, 0, c[pysqlitedb.YLEN])
-                attrs.append(attr)
-                self.__lookup_table.append_candidate(ibus.Text(c[pysqlitedb.PHRASE], attrs))
-                del candidates[0]
-
-            for c in self.__special_candidates:
-                attrs = ibus.AttrList ()
-                attr = ibus.AttributeForeground(PinYinEngine.__special_phrase_color, 0, len(c))
-                attrs.append(attr)
-                self.__lookup_table.append_candidate(ibus.Text(c, attrs))
-
-            for c in candidates:
-                attrs = ibus.AttrList ()
-                if c[pysqlitedb.FREQ] == None: # This phrase was created by user.
-                    attr = ibus.AttributeForeground(PinYinEngine.__user_phrase_color, 0, c[pysqlitedb.YLEN])
-                else:
-                    attr = ibus.AttributeForeground(PinYinEngine.__phrase_color, 0, c[pysqlitedb.YLEN])
-                attrs.append(attr)
-                self.__lookup_table.append_candidate(ibus.Text(c[pysqlitedb.PHRASE], attrs))
-            self.__lookup_table.show_cursor(True)
-            self.__lookup_table.set_cursor_pos(0)
-            self.update_lookup_table(self.__lookup_table, True, True)
-
-        committed_string = self.__committed_phrases.get_string()
-        invalid_pinyin = self.__user_input.get_invalid_string()
-        preedit_string = " ".join([committed_string, self.__preedit_phrases.get_string(), invalid_pinyin])
-        preedit_string = preedit_string.strip()
-
-        if preedit_string:
-            self.update_preedit(preedit_string, None, len(preedit_string), True)
-        else:
-            self.hide_preedit_text()
-
-        if committed_string or len(self.__user_input) != 0:
-            pinyin_list = self.__user_input.get_pinyin_list()
-            pinyin_list = pinyin_list [len(committed_string):]
-            pinyin_list = map(str, pinyin_list)
-            if committed_string:
-                aux_string = u"".join([committed_string, u" ", u"'".join(pinyin_list)])
-            else:
-                aux_string = u"'".join(pinyin_list)
-
-            if PinYinEngine.__shuangpin:
-                aux_string += " [" + u"".join(self.__user_input.get_chars()) + "]" 
-
-            if aux_string:
-                self.update_aux_string(aux_string, None, True)
-            else:
-                self.hide_auxiliary_text()
-        else:
-            self.hide_auxiliary_text()
-
-    def __invalidate(self):
-        if self.__need_update:
-            return
-        self.__need_update = True
-
-    def __update(self):
-        if self.__need_update:
-            self.__update_candidates()
-            self.__update_ui()
-            self.__need_update = False
-
-    def __is_gb2312(self, record):
-        try:
-            record[pysqlitedb.PHRASE].encode("gb2312")
-        except:
-            return False
-        return True
-
-    def __get_candidates(self, pinyin_list):
-        candidates = []
-
-        for i in range(len(pinyin_list), 0, -1):
-            candidates += self.__pydb.select_words_by_pinyin_list(pinyin_list[:i], PinYinEngine.__fuzzy_pinyin)
-        if not PinYinEngine.__gbk:
-            candidates = filter(self.__is_gb2312, candidates)
-        return candidates
-
-    def __get_a_candidate(self, pinyin_list):
-        for i in range(len(pinyin_list), 0, -1):
-            candidates = self.__pydb.select_words_by_pinyin_list(pinyin_list[:i], PinYinEngine.__fuzzy_pinyin)
-            if not PinYinEngine.__gbk:
-                candidates = filter(self.__is_gb2312, candidates)
-            if candidates:
-                return candidates[0]
-        return None
-
-
-    def __append_char(self, char):
-        self.__user_input.append(char)
-        self.__committed_phrases.clean()
-        self.__invalidate()
-
-        return True
-
-    def __pop_char(self):
-        if len(self.__user_input) == 0:
-            return False
-        if len(self.__committed_phrases) != 0:
-            self.__committed_phrases.pop()
-        else:
-            self.__user_input.pop()
-        self.__invalidate()
-
-        return True
-
-    def __match_hotkey(self, key, code, mask):
-        if key.code == code and key.mask == mask:
-            if self.__prev_key and key.code == self.__prev_key.code and key.mask & modifier.RELEASE_MASK:
-                return True
-            if not key.mask & modifier.RELEASE_MASK:
-                return True
-
-        return False
-
-    def __internal_process_key_event(self, key):
-
-        # When CapsLock is lock, we ignore all key events
-        if key.mask & modifier.LOCK_MASK:
-            if self.__user_input:
-                self.reset()
-            return False
-
-        # ignore NumLock mask
-        key.mask &= ~modifier.MOD2_MASK
-
-        # Match mode switch hotkey
-        if self.__match_hotkey(key, keysyms.Shift_L, modifier.SHIFT_MASK + modifier.RELEASE_MASK) or \
-            self.__match_hotkey(key, keysyms.Shift_R, modifier.SHIFT_MASK + modifier.RELEASE_MASK):
-            if self.__candidates and not self.__is_input_english() and PinYinEngine.__shift_select_canidates:
-                index = self.__lookup_table.get_current_page_start()
-                if key.code == keysyms.Shift_L:
-                    index += 1
-                else:
-                    index += 2
-                result = self.__commit_candidate(index)
-                if result:
-                    if self.__committed_special_phrase:
-                        self.commit_string(self.__committed_special_phrase)
-                    else:
-                        commit_phrases = self.__committed_phrases.get_phrases()
-                        commit_string = self.__committed_phrases.get_string()
-                        self.commit_string(commit_string + self.__user_input.get_invalid_string())
-
-                        # adjust phrase freq and create new phrase
-                        try:
-                            self.__pydb.commit_phrases(commit_phrases)
-                            if len(commit_phrases) > 1:
-                                self.__pydb.new_phrase(commit_phrases)
-                        except:
-                            print "Can not inster phrases in db"
-                return True
-            else:
-                self.property_activate("status")
-                self.reset()
-            return True
-
-        # Match full half letter mode switch hotkey
-        if self.__match_hotkey(key, keysyms.space, modifier.SHIFT_MASK):
-            self.property_activate("full_letter")
-            return True
-
-        # Match full half punct mode switch hotkey
-        if self.__match_hotkey(key, keysyms.period, modifier.CONTROL_MASK):
-            self.property_activate("full_punct")
-            return True
-
-        # Match remove user phrase hotkeys
-        for code in xrange(keysyms._1, keysyms._1 + PinYinEngine.__page_size):
-            if self.__match_hotkey(key, code, modifier.CONTROL_MASK):
-                index = code - keysyms._1 + self.__lookup_table.get_current_page_start()
-                return self.__remove_candidate(index)
-
-        # we ignore all hotkeys
-        if key.mask &(modifier.CONTROL_MASK + modifier.ALT_MASK):
-            return False
-
-        # Ignore key release event
-        if key.mask & modifier.RELEASE_MASK:
-            return True
-
-        if self.__is_input_english():
-            return self.__english_mode_process_key_event(key)
-        else:
-            if self.__temp_english_mode:
-                return self.__temp_english_mode_process_key_event(key)
-            elif self.__i_mode:
-                return self.__i_mode_process_key_event(key)
-            else:
-                return self.__chinese_mode_process_key_event(key)
-
-    def __convert_to_full_width(self, c):
-        if c in PinYinEngine.__half_puncts:
-            return c
-        elif c == u".":
-            return u"\u3002"
-        elif c == u"\\":
-            return u"\u3001"
-        elif c == u"^":
-            return u"\u2026\u2026"
-        elif c == u"_":
-            return u"\u2014\u2014"
-        elif c == u"$":
-            return u"\uffe5"
-        elif c == u"\"":
-            self.__double_quotation_state = not self.__double_quotation_state
-            if self.__double_quotation_state:
-                return u"\u201c"
-            else:
-                return u"\u201d"
-        elif c == u"'":
-            self.__single_quotation_state = not self.__single_quotation_state
-            if self.__single_quotation_state:
-                return u"\u2018"
-            else:
-                return u"\u2019"
-
-        elif c == u"<":
-            if not self.__is_input_english():
-                return u"\u300a"
-        elif c == u">":
-            if not self.__is_input_english():
-                return u"\u300b"
-
-        return ibus.unichar_half_to_full(c)
-
-    def __english_mode_process_key_event(self, key):
-        # ignore if key code is not a normal ascii char
-        if key.code >= 128:
-            return False
-
-        c = unichr(key.code)
-        if ascii.ispunct(key.code): # if key code is a punctation
-            if self.__full_width_punct[self.__mode]:
-                self.commit_string(self.__convert_to_full_width(c), False)
-                return True
-            else:
-                self.commit_string(c, False)
-                return True
-
-        if self.__full_width_letter[self.__mode]: # if key code is a letter or digit
-            self.commit_string(self.__convert_to_full_width(c), False)
-            return True
-        else:
-            self.commit_string(c, False)
-            return True
-
-        # should not reach there
-        return False
-
-    def __i_mode_process_key_event(self, key):
-        if key.code in(keysyms.Return, keysyms.KP_Enter):
-            commit_string = u"".join(self.__user_input.get_chars())
-            self.commit_string(commit_string)
-            return True
-        elif key.code == keysyms.BackSpace and len(self.__user_input) != 0:
-            self.__user_input.pop()
-            if len(self.__user_input) == 0:
-                self.__i_mode = False
-            self.__invalidate()
-            return True
-        elif key.code == keysyms.Escape:
-            self.__user_input.clean()
-            self.__i_mode = False
-            self.__invalidate()
-            return True
-        elif key.code >= keysyms._1 and key.code <= keysyms._9:
-            if not self.__candidates:
-                return True
-            index = key.code - keysyms._1
-            if index >= PinYinEngine.__page_size:
-                return True
-            index += self.__lookup_table.get_current_page_start()
-            if index >= len(self.__candidates):
-                return True
-            self.commit_string(self.__candidates[index])
-            return True
-        elif key.code in(keysyms.KP_Space, keysyms.space):
-            if not self.__candidates:
-                return True
-            index = self.__lookup_table.get_cursor_pos()
-            if index >= len(self.__candidates):
-                return True
-            self.commit_string(self.__candidates[index])
-            return True
-        elif key.code == keysyms.Down:
-            self.cursor_down()
-            return True
-        elif key.code == keysyms.Up:
-            self.cursor_up()
-            return True
-        elif key.code == keysyms.Page_Down and self.__candidates: # press PageDown
-            self.page_down()
-            return True
-        elif key.code == keysyms.Page_Up and self.__candidates: # press PageUp
-            self.page_up()
-            return True
-        elif key.code == keysyms.period and self.__candidates and PinYinEngine.__comma_page_down_up: # press .
-            self.page_down()
-            return True
-        elif key.code == keysyms.comma and self.__candidates and PinYinEngine.__comma_page_down_up: # press ,
-            self.page_up()
-            return True
-        elif key.code == keysyms.equal and self.__candidates and PinYinEngine.__equal_page_down_up: # press =
-            self.page_down()
-            return True
-        elif key.code == keysyms.minus and self.__candidates and PinYinEngine.__equal_page_down_up: # press -
-            self.page_up()
-            return True
-
-        if key.code >= 128:
-            return True
-
-        self.__user_input.append(unichr(key.code))
-        self.__invalidate()
-
-        return True
-
-    def __temp_english_mode_process_key_event(self, key):
-        if key.code in(keysyms.Return, keysyms.KP_Enter):
-            commit_string = u"".join(self.__user_input.get_chars())
-            if commit_string[0] in(u"v", u"u"):
-                commit_string = commit_string[1:]
-            self.commit_string(commit_string)
-            return True
-        elif key.code == keysyms.BackSpace and len(self.__user_input) != 0:
-            self.__user_input.pop()
-            if len(self.__user_input) == 0:
-                self.__temp_english_mode = False
-            self.__invalidate()
-            return True
-        elif key.code == keysyms.Escape:
-            self.__user_input.clean()
-            self.__temp_english_mode = False
-            self.__invalidate()
-            return True
-        elif key.code >= keysyms._1 and key.code <= keysyms._9 and self.__english_candidates:
-            index = key.code - keysyms._1
-            if index >= PinYinEngine.__page_size:
-                return False
-            index += self.__lookup_table.get_current_page_start()
-            if index >=0 and index < len(self.__english_candidates):
-                for i in xrange(0, len(self.__current_word)):
-                    self.__user_input.pop()
-                for c in self.__english_candidates[index]:
-                    self.__user_input.append(c)
-                self.__invalidate()
-                return True
-            return False
-        elif key.code in(keysyms.Page_Down, ) and self.__english_candidates:
-            self.page_down()
-            return True
-        elif key.code in(keysyms.Page_Up, ) and self.__english_candidates:
-            self.page_up()
-            return True
-
-        if key.code >= 128:
-            return True
-
-        self.__user_input.append(unichr(key.code))
-        self.__invalidate()
-
-        return True
-
-    def __chinese_mode_process_key_event(self, key):
-        # define a condition half to full width translate functions
-        cond_letter_translate = lambda(c): \
-            self.__convert_to_full_width(c) if self.__full_width_letter [self.__mode] else c
-        cond_punct_translate = lambda(c): \
-            self.__convert_to_full_width(c) if self.__full_width_punct [self.__mode] else c
-
-        if key.code in(keysyms.Return, keysyms.KP_Enter):
-            if len(self.__user_input) == 0: # forward Return if inputed chars is empty
-                return False
-            chars = map(cond_letter_translate, self.__user_input.get_chars())
-            commit_string = u"".join(chars)
-            self.commit_string(commit_string)
-            return True
-        elif key.code == keysyms.Escape:
-            if len(self.__user_input) != 0:
-                self.reset()
-                return True
-            return False
-        elif key.code == keysyms.Down:
-            return self.cursor_down()
-        elif key.code == keysyms.Up:
-            return self.cursor_up()
-        elif key.code == keysyms.BackSpace:
-            return self.__pop_char()
-        elif key.code >= keysyms._1 and key.code <= keysyms._9:
-            if not self.__candidates:
-                self.commit_string(cond_letter_translate(unichr(key.code)))
-            else:
-                index = key.code - keysyms._1
-                if index >= PinYinEngine.__page_size:
-                    return True
-                index += self.__lookup_table.get_current_page_start()
-                result = self.__commit_candidate(index)
-                if result:
-                    if self.__committed_special_phrase:
-                        self.commit_string(self.__committed_special_phrase)
-                    else:
-                        commit_phrases = self.__committed_phrases.get_phrases()
-                        commit_string = self.__committed_phrases.get_string()
-                        self.commit_string(commit_string + self.__user_input.get_invalid_string())
-
-                        # adjust phrase freq and create new phrase
-                        try:
-                            self.__pydb.commit_phrases(commit_phrases)
-                            if len(commit_phrases) > 1:
-                                self.__pydb.new_phrase(commit_phrases)
-                        except:
-                            print "Can not inster phrases in db"
-            return True
-        elif key.code in(keysyms.KP_Space, keysyms.space):
-            if not self.__candidates:
-                self.commit_string(cond_letter_translate(u" "))
-            else:
-                index = self.__lookup_table.get_cursor_pos()
-                result = self.__commit_candidate(index)
-                if result:
-                    if self.__committed_special_phrase:
-                        self.commit_string(self.__committed_special_phrase)
-                    else:
-                        commit_phrases = self.__committed_phrases.get_phrases()
-                        commit_string = self.__committed_phrases.get_string()
-                        self.commit_string(commit_string + self.__user_input.get_invalid_string())
-
-                        # adjust phrase freq and create new phrase
-                        try:
-                            self.__pydb.commit_phrases(commit_phrases)
-                            if len(commit_phrases) > 1:
-                                self.__pydb.new_phrase(commit_phrases)
-                        except:
-                            print "Can not inster phrases in db"
-            return True
-        elif key.code == keysyms.Page_Down and self.__candidates: # press PageDown
-            self.page_down()
-            return True
-        elif key.code == keysyms.equal and self.__candidates and PinYinEngine.__equal_page_down_up: # press equal
-            self.page_down()
-            return True
-        elif key.code == keysyms.period and self.__candidates and PinYinEngine.__comma_page_down_up: # press period
-            self.page_down()
-            return True
-        elif key.code == keysyms.Page_Up and self.__candidates: # press PageUp
-            self.page_up()
-            return True
-        elif key.code == keysyms.minus and self.__candidates and PinYinEngine.__equal_page_down_up: # press minus
-            self.page_up()
-            return True
-        elif key.code == keysyms.comma and self.__candidates and PinYinEngine.__comma_page_down_up: #press comma
-            self.page_up()
-            return True
-
-        elif key.code in(keysyms.bracketleft, keysyms.bracketright) and self.__candidates:
-            cursor_pos = self.__lookup_table.get_cursor_pos()
-            candidate = self.__candidates[cursor_pos]
-            if key.code == keysyms.bracketleft:
-                i = 0
-            else:
-                i = len(candidate[pysqlitedb.PHRASE]) - 1
-            char = candidate[pysqlitedb.PHRASE][i]
-            if i < 4:
-                pinyin_id = candidate[pysqlitedb.Y0 + i]
-                shengmu_id = candidate[pysqlitedb.S0 + i]
-            else:
-                pinyin = candidate[pysqlitedb.YX].split("'")[-1]
-                word = pyutil.PinYinWord(pinyin)
-                pinyin_id = word.get_pinyin_id()
-                shengmu_id = word.get_sheng_mu_id()
-
-            self.__pydb.commit_char(char, pinyin_id, shengmu_id)
-            self.commit_string(char)
-            return True
-        elif PinYinEngine.__uv_to_temp and not PinYinEngine.__shuangpin \
-             and len(self.__user_input) == 0 \
-             and key.code in(keysyms.v, keysyms.u):
-            self.__user_input.append(unichr(key.code))
-            self.__temp_english_mode = True
-            self.__invalidate()
-            return True
-        elif key.code >= keysyms.A and key.code <= keysyms.Z and len(self.__user_input) == 0:
-            self.__user_input.append(unichr(key.code))
-            self.__temp_english_mode = True
-            self.__invalidate()
-            return True
-        elif key.code == keysyms.i and \
-             len(self.__user_input) == 0 and \
-             not PinYinEngine.__shuangpin:
-             # we goto i_mode
-            self.__user_input.append(unichr(key.code))
-            self.__i_mode = True
-            self.__invalidate()
-            return True
-        elif(key.code >= keysyms.a and key.code <= keysyms.z) or \
-           (key.code == keysyms.apostrophe and len(self.__user_input) != 0) or \
-           (key.code == keysyms.semicolon and len(self.__user_input) != 0 and PinYinEngine.__shuangpin) :
-            return self.__append_char(unichr(key.code))
-        elif key.code <= 127:
-            if len(self.__user_input) != 0:
-                if PinYinEngine.__auto_commit:
-                    self.__chinese_mode_process_key_event(KeyEvent(keysyms.space, True, key.mask))
-                else:
-                    return True
-            c = chr(key.code)
-            if c == "." and self.__prev_char and self.__prev_char.isdigit() \
-                and self.__prev_key and chr(self.__prev_key.code) == self.__prev_char:
-                self.commit_string(u".")
-            elif ascii.ispunct(key.code):
-                self.commit_string(cond_punct_translate(unichr(key.code)))
-            else:
-                self.commit_string(cond_letter_translate(unichr(key.code)))
-            return True
-        elif len(self.__user_input) != 0:
-            return True
-
-        return False
-
-    def __commit_candidate(self, i):
-        if i == 0:
-            for phrase in self.__preedit_phrases.get_phrases():
-                self.__committed_phrases.append(phrase)
-            return True
-
-        if i >=1 and i <= len(self.__special_candidates):
-            self.__committed_special_phrase = self.__special_candidates [i - 1]
-            return True
-
-        if len(self.__preedit_phrases) != 1:
-            i -= 1
-
-        i -= len(self.__special_candidates)
-
-        if i >= len(self.__candidates):
-            return False
-
-        self.__committed_phrases.append( self.__candidates[i])
-        pinyin_list = self.__user_input.get_pinyin_list()
-
-        if self.__committed_phrases.length_of_chars() == len(pinyin_list):
-            return True
-
-        self.__invalidate()
-
-        return False
-
-    def __remove_candidate(self, i):
-        if i >= 1:
-            i -= len(self.__special_candidates)
-
-        if len(self.__preedit_phrases) != 1:
-            i -= 1
-
-        if i >= len(self.__candidates) or i < 0:
-            return False
-
-        if self.__candidates[i][pysqlitedb.FREQ] != None: # This phrase was not create by user.
-            return False
-
-        candidate = self.__candidates.pop(i)
-        try:
-            self.__pydb.remove_phrase(candidate)
-        except:
-            print "Can not remove phrase from db"
-        self.__invalidate()
-
-        return True
-
-    def __start_setup(self):
-        if PinYinEngine.__setup_pid != 0:
-            pid, state = os.waitpid(PinYinEngine.__setup_pid, os.P_NOWAIT)
-            if pid != PinYinEngine.__setup_pid:
-                os.kill(PinYinEngine.__setup_pid, signal.SIGUSR1)
-                return
-            PinYinEngine.__setup_pid = 0
-        setup_cmd = path.join(LIBEXECDIR, "ibus-setup-pinyin")
-        PinYinEngine.__setup_pid = os.spawnl(os.P_NOWAIT, setup_cmd, "ibus-setup-pinyin")
-
-
-    def process_key_event(self, keyval, keycode, state):
-        key = KeyEvent(keyval, state & modifier.RELEASE_MASK == 0, state)
-        result = self.__internal_process_key_event(key)
-        self.__update()
-        self.__prev_key = key
-        return result
-
-    def commit_string(self, string, need_update = True):
-        self.__temp_english_mode = False
-        self.__i_mode = False
-        self.__candidates = []
-        self.__english_candidates = []
-        self.__cursor = 0
-        self.__user_input.clean()
-        self.__preedit_string = u""
-        self.__committed_phrases.clean()
-        self.__committed_special_phrase = u""
-        self.__need_update = True
-        self.__update()
-        super(PinYinEngine,self).commit_text(ibus.Text(string))
-        self.__prev_char = string[-1]
-
-    def update_preedit(self, preedit_string, preedit_attrs, cursor_pos, visible):
-        if preedit_attrs == None:
-            preedit_attrs = ibus.AttrList()
-            attr = ibus.AttributeUnderline(ibus.ATTR_UNDERLINE_SINGLE, 0, len(preedit_string))
-            preedit_attrs.append(attr)
-
-        super(PinYinEngine, self).update_preedit_text(ibus.Text(preedit_string, preedit_attrs), cursor_pos, visible)
-
-    def update_aux_string(self, aux_string, aux_attrs, visible):
-        super(PinYinEngine,self).update_auxiliary_text(ibus.Text(aux_string, aux_attrs), visible)
-
-    def page_up(self):
-        if self.__lookup_table.page_up():
-            self.update_lookup_table(self.__lookup_table, True, True)
-            return True
-
-        return True
-
-    def page_down(self):
-        if self.__lookup_table.page_down():
-            self.update_lookup_table(self.__lookup_table, True, True)
-            return True
-        return True
-
-    def cursor_up(self):
-        if len(self.__candidates) == 0:
-            return False
-
-        if self.__lookup_table.cursor_up():
-            self.update_lookup_table(self.__lookup_table, True, True)
-        return True
-
-    def cursor_down(self):
-        if len(self.__candidates) == 0:
-            return False
-
-        if self.__lookup_table.cursor_down():
-            self.update_lookup_table(self.__lookup_table, True, True)
-        return True
-
-    def candidate_clicked(self, index, button, state):
-        if button == 1:
-            self.process_key_event(keysyms._1 + index, state)
-
-    def reset(self):
-        self.__temp_english_mode = False
-        self.__i_mode = False
-        self.__user_input.clean()
-        self.__committed_phrases.clean()
-        self.__committed_special_phrase = u""
-        self.__preedit_string = u""
-        self.__special_candidates = []
-        self.__candidates = []
-        self.__english_candidates = []
-        self.__cursor = 0
-        self.__double_quotation_state = False
-        self.__single_quotation_state = False
-        self.__prev_key = None
-        self.__prev_char = None
-        self.__invalidate()
-
-    def focus_in(self):
-        self.register_properties(self.__prop_list)
-        self.__refresh_properties()
-        if PinYinEngine.__shuangpin:
-            self.__py_parser = pyparser.ShuangPinParser(PinYinEngine.__shuangpin_schema)
-        else:
-            self.__py_parser = pyparser.PinYinParser()
-        self.__lookup_table.set_page_size(PinYinEngine.__page_size)
-        self.__user_input.set_parser(self.__py_parser)
-        self.__user_input.set_gbk(PinYinEngine.__gbk)
-        self.__user_input.set_auto_correct(PinYinEngine.__auto_correct)
-        self.__invalidate()
-
-    def focus_out(self):
-        self.reset()
-
-    def enable(self):
-        self.focus_in()
-
-    def property_activate(self, prop_name, prop_state = ibus.PROP_STATE_UNCHECKED):
-        if prop_name == "status":
-            self.__change_mode()
-        elif prop_name == "full_letter":
-            self.__full_width_letter [self.__mode] = not self.__full_width_letter [self.__mode]
-            self.__refresh_properties()
-        elif prop_name == "full_punct":
-            self.__full_width_punct [self.__mode] = not self.__full_width_punct [self.__mode]
-            self.__refresh_properties()
-        # elif property == "shuangpin":
-        #     PinYinEngine.__shuangpin = not PinYinEngine.__shuangpin
-        #     self.reset()
-        #     if PinYinEngine.__shuangpin:
-        #         self.__py_parser = pyparser.ShuangPinParser(PinYinEngine.__shuangpin_schema)
-        #     else:
-        #         self.__py_parser = pyparser.PinYinParser()
-        #     self.__user_input.set_parser(self.__py_parser)
-        #     self.__config.write("engine/PinYin/ShuangPin", PinYinEngine.__shuangpin)
-        #     self.__refresh_properties()
-        # elif property == "gbk":
-        #     PinYinEngine.__gbk = not PinYinEngine.__gbk
-        #     self.reset()
-        #     self.__config.write("engine/PinYin/SupportGBK", PinYinEngine.__gbk)
-        #     self.__refresh_properties()
-
-        elif prop_name == "setup":
-            self.__start_setup()
-
-    def process_helper_event(self, helper_uuid, trans):
-        IMEngine.process_helper_event(self, helper_uuid, trans)
-
-    def update_client_capabilities(self, cap):
-        IMEngine.update_client_capabilities(self, cap)
-
-    @classmethod
-    def CONFIG_VALUE_CHANGED(cls, bus, section, name, value):
-        config = bus.get_config()
-
-        if section != "engine/PinYin":
-            return
-        if name == "ShuangPinSchema":
-            PinYinEngine.__shuangpin_schema = \
-                config.get_value("engine/PinYin", "ShuangPinSchema", "MSPY")
-            if PinYinEngine.__shuangpin_schema not in pydict.SHUANGPIN_SCHEMAS:
-                PinYinEngine.__shuangpin_schema = "MSPY"
-        elif name == "FuzzyPinYin":
-            PinYinEngine.__fuzzy_pinyin = \
-                config.get_value("engine/PinYin", "FuzzyPinYin", False)
-            PinYinEngine.__fuzzy_pinyin = False
-        elif name == "AutoCorrect":
-            PinYinEngine.__auto_correct = \
-                config.get_value("engine/PinYin", "AutoCorrect", True)
-        elif name == "SpellCheck":
-            PinYinEngine.__spell_check = \
-                config.get_value("engine/PinYin", "SpellCheck", True)
-        elif name == "PageSize":
-            PinYinEngine.__page_size = \
-                config.get_value("engine/PinYin", "PageSize", 5)
-            if PinYinEngine.__page_size < 1 or PinYinEngine.__page_size > 9:
-                PinYinEngine.__page_size = 5
-        elif name == "SupportGBK":
-            PinYinEngine.__gbk = \
-                config.get_value("engine/PinYin", "SupportGBK", False)
-        elif name == "ShuangPin":
-            PinYinEngine.__shuangpin = \
-                config.get_value("engine/PinYin", "ShuangPin", False)
-        elif name == "PhraseColor":
-            PinYinEngine.__phrase_color = \
-                config.get_value("engine/PinYin", "PhraseColor", PinYinEngine.__phrase_color)
-        elif name == "NewPhraseColor":
-            PinYinEngine.__new_phrase_color = \
-                config.get_value("engine/PinYin", "NewPhraseColor", PinYinEngine.__new_phrase_color)
-        elif name == "UserPhraseColor":
-            PinYinEngine.__user_phrase_color = \
-                config.get_value("engine/PinYin", "UserPhraseColor", PinYinEngine.__user_phrase_color)
-        elif name == "SpecialPhraseColor":
-            PinYinEngine.__special_phrase_color = \
-                config.get_value("engine/PinYin", "SpecialPhraseColor", PinYinEngine.__special_phrase_color)
-        elif name == "EnglishPhraseColor":
-            PinYinEngine.__english_phrase_color = \
-                config.get_value("engine/PinYin", "EnglishPhraseColor", PinYinEngine.__english_phrase_color)
-        elif name == "ErrorEnglishPhraseColor":
-            PinYinEngine.__error_eng_phrase_color = \
-                config.get_value("engine/PinYin", "ErrorEnglishPhraseColor", PinYinEngine.__error_eng_phrase_color)
-        elif name == "UVToTemp":
-            PinYinEngine.__uv_to_temp = \
-                config.get_value("engine/PinYin", "UVToTemp", PinYinEngine.__uv_to_temp)
-        elif name == "ShiftSelectCandidates":
-            PinYinEngine.__shift_select_canidates = \
-                config.get_value("engine/PinYin", "ShiftSelectCandidates", PinYinEngine.__shift_select_candidates)
-        elif name == "CommaPageDownUp":
-            PinYinEngine.__comma_page_down_up = \
-                config.get_value("engine/PinYin", "CommaPageDownUp", PinYinEngine.__comma_page_down_up)
-        elif name == "EqualPageDownUp":
-            PinYinEngine.__equal_page_down_up = \
-                config.get_value("engine/PinYin", "EqualPageDownUp", PinYinEngine.__equal_page_down_up)
-        elif name == "AutoCommit":
-            PinYinEngine.__auto_commit = \
-                config.get_value("engine/PinYin", "AutoCommit", PinYinEngine.__auto_commit)
-        elif name == "HalfPunctuations":
-            PinYinEngine.__half_puncts = \
-                config.get_value("engine/PinYin", "HalfPunctuations", PinYinEngine.__half_puncts)
-        else:
-            print "Unknow name(%s)" % name
-
-    @classmethod
-    def CONFIG_RELOADED(cls, bus):
-
-        config = bus.get_config()
-
-        PinYinEngine.__shuangpin_schema = \
-            config.get_value("engine/PinYin", "ShuangPinSchema", "MSPY")
-        if PinYinEngine.__shuangpin_schema not in pydict.SHUANGPIN_SCHEMAS:
-            PinYinEngine.__shuangpin_schema = "MSPY"
-
-        PinYinEngine.__fuzzy_pinyin = \
-            config.get_value("engine/PinYin", "FuzzyPinYin", False)
-        PinYinEngine.__fuzzy_pinyin = False
-        PinYinEngine.__auto_correct = \
-            config.get_value("engine/PinYin", "AutoCorrect", True)
-        PinYinEngine.__spell_check = \
-            config.get_value("engine/PinYin", "SpellCheck", True)
-        PinYinEngine.__page_size = \
-            config.get_value("engine/PinYin", "PageSize", 5)
-        if PinYinEngine.__page_size < 1 or PinYinEngine.__page_size > 9:
-            PinYinEngine.__page_size = 5
-        PinYinEngine.__gbk = \
-            config.get_value("engine/PinYin", "SupportGBK", False)
-        PinYinEngine.__shuangpin = \
-            config.get_value("engine/PinYin", "ShuangPin", False)
-
-        PinYinEngine.__phrase_color = \
-            config.get_value("engine/PinYin", "PhraseColor", PinYinEngine.__phrase_color)
-        PinYinEngine.__new_phrase_color = \
-            config.get_value("engine/PinYin", "NewPhraseColor", PinYinEngine.__new_phrase_color)
-        PinYinEngine.__user_phrase_color = \
-            config.get_value("engine/PinYin", "UserPhraseColor", PinYinEngine.__user_phrase_color)
-        PinYinEngine.__special_phrase_color = \
-            config.get_value("engine/PinYin", "SpecialPhraseColor", PinYinEngine.__special_phrase_color)
-        PinYinEngine.__english_phrase_color = \
-            config.get_value("engine/PinYin", "EnglishPhraseColor", PinYinEngine.__english_phrase_color)
-        PinYinEngine.__error_eng_phrase_color = \
-            config.get_value("engine/PinYin", "ErrorEnglishPhraseColor", PinYinEngine.__error_eng_phrase_color)
-        PinYinEngine.__uv_to_temp = \
-            config.get_value("engine/PinYin", "UVToTemp", PinYinEngine.__uv_to_temp)
-        PinYinEngine.__shift_select_canidates = \
-            config.get_value("engine/PinYin", "ShiftSelectCandidates", PinYinEngine.__shift_select_candidates)
-        PinYinEngine.__comma_page_down_up = \
-            config.get_value("engine/PinYin", "CommaPageDownUp", PinYinEngine.__comma_page_down_up)
-        PinYinEngine.__equal_page_down_up = \
-            config.get_value("engine/PinYin", "EqualPageDownUp", PinYinEngine.__equal_page_down_up)
-        PinYinEngine.__auto_commit = \
-            config.get_value("engine/PinYin", "AutoCommit", PinYinEngine.__auto_commit)
-        PinYinEngine.__half_puncts = \
-            config.get_value("engine/PinYin", "HalfPunctuations", PinYinEngine.__half_puncts)
-        PinYinEngine.__half_puncts = PinYinEngine.__half_puncts.replace(" ", "")
-
-class KeyEvent:
-    def __init__(self, keyval, is_press, state):
-        self.code = keyval
-        self.mask = state
-        if not is_press:
-            self.mask |= modifier.RELEASE_MASK
-    def __str__(self):
-        return "%s 0x%08x" % (keysyms.keycode_to_name(self.code), self.mask)
-
-
-class UserInput:
-    "UserInput holds user input chars"
-    def __init__(self, parser, max_length = __MAX_LEN__):
-        self.__parser = parser
-        self.__max_length = max_length
-        self.__auto_correct = True
-        self.__gbk = False
-        self.__chars =([], [])
-        self.__pinyin_list = []
-
-
-    def clean(self):
-        self.__chars =([], [])
-        self.__pinyin_list = []
-
-    def set_parser(self, parser):
-        self.clean()
-        self.__parser = parser
-
-    def set_gbk(self, gbk):
-        self.__gbk = gbk
-        self.clean()
-
-    def set_auto_correct(self, auto_correct):
-        self.__auto_correct = auto_correct
-        self.clean()
-
-    def get_pinyin_list(self):
-        return self.__pinyin_list
-
-    def get_chars(self):
-        return self.__chars[0] + self.__chars[1]
-
-    def get_invalid_chars(self):
-        return self.__chars[1]
-
-    def get_invalid_string(self):
-        return "".join(self.__chars[1])
-
-    def append(self, c):
-        if len(self.__chars[0]) + len(self.__chars[1])  == self.__max_length:
-            return
-
-        if self.__chars[1]:
-            self.__chars[1].append(c)
-        else:
-            try:
-                self.__pinyin_list = self.__parser.parse("".join(self.__chars[0] + [c]), self.__auto_correct, self.__gbk)
-                self.__chars[0].append(c)
-            except:
-                self.__chars[1].append(c)
-
-    def pop(self):
-        resutl = []
-        if len(self.__chars[1]) != 0:
-            return self.__chars[1].pop()
-        elif len(self.__chars[0]) != 0:
-            c = self.__chars[0].pop()
-            if len(self.__chars[0]) != 0:
-                self.__pinyin_list = self.__parser.parse("".join(self.__chars[0]), self.__auto_correct, self.__gbk)
-            else:
-                self.__pinyin_list = []
-            return c
-        else:
-            return ""
-
-    def __len__(self):
-        return len(self.__chars[0]) + len(self.__chars[1])
-
-class PhraseList:
-    """PhraseList contains phrases"""
-    def __init__(self):
-        self.__list = []
-        self.__length_of_chars = 0
-
-    def clean(self):
-        """Remove all phrases from the list"""
-        self.__list = []
-        self.__length_of_chars = 0
-
-    def append(self, phrase):
-        """Append a phrase into the list"""
-        self.__list.append(phrase)
-        self.__length_of_chars += phrase[pysqlitedb.YLEN]
-
-    def pop(self):
-        phrase = self.__list.pop()
-        self.__length_of_chars -= phrase[pysqlitedb.YLEN]
-        return phrase
-
-    def count(self):
-        """Return count of phrases in the list"""
-        return len(self.__list)
-
-    def length_of_chars(self):
-        """Return number of chars in all phrases in the list"""
-        return self.__length_of_chars
-
-    def get_phrases(self):
-        """Return all phrases"""
-        return self.__list
-
-    def get_string(self):
-        """Join all phrases into a string object and return it."""
-        get_phrase = lambda x: x[pysqlitedb.PHRASE]
-        return u"".join(map(get_phrase, self.__list))
-
-    def __str__(self):
-        return self.get_string().encode("utf8")
-
-    def __len__(self):
-        return len(self.__list)
-
-
diff --git a/engine/pycreatedb.py b/engine/pycreatedb.py
deleted file mode 100644 (file)
index e780faf..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim:set et sts=4 sw=4:
-#
-# ibus-pinyin - The PinYin engine for IBus
-#
-# Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-import sys, os, re
-import pysqlitedb
-import bz2
-
-def phrase_pinyin_parser(f):
-    for l in f:
-        pinyin, phrase, freq = unicode(l, "utf-8").strip().split()
-        pinyin = pinyin.replace(u"u:", u"v")
-        yield (phrase, pinyin, int(freq))
-
-def main():
-    srcdir = "."
-    if len(sys.argv) == 2:
-        srcdir = sys.argv[1]
-
-    filename = "py-new.db"
-    try:
-        os.unlink(filename)
-    except:
-        pass
-    
-    db = pysqlitedb.PYSQLiteDB(filename = filename)
-    db.create_tables()
-    db.init_pinyin_table()
-    db.init_shengmu_table()
-
-    for phrase_filename in sys.argv[1:]:
-        print "Loading %s" % phrase_filename
-        db.add_phrases(phrase_pinyin_parser(file(phrase_filename)))
-    
-    print "Optimizing database"
-    db.optimize_database()
-    
-if __name__ == "__main__":
-    main()
diff --git a/engine/pyparser.py b/engine/pyparser.py
deleted file mode 100644 (file)
index 5266c4c..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim:set et sts=4 sw=4:
-#
-# ibus-pinyin - The PinYin engine for IBus
-#
-# Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-import sys
-import pyutil
-import pydict
-
-class PinYinParser:
-    pinyin_dict = set (pydict.PINYIN_DICT.keys () + pydict.SHENGMU_DICT.keys ())
-    gb2312_pinyin_dict = pinyin_dict - set (["eng", "chua", "fe", "fiao", "liong"])
-    correct_yunmu = {
-        "ing" : ("ign", "img"), "ui" : ("uei", "iu", "i"),
-        "un" : ("uen",), "iu" : ("iou", "ui"),
-        "ao" : ("au", ), "ei" : ("i", ),
-        "iao" : ("ioa", "ia", "i"), "ian" : ("ia", "i"), "iang" : ("ian", "ia", "i")}
-
-    correct_table = {}
-
-    def __init__ (self):
-        self.init_corrent_table ()
-
-    def init_corrent_table (self):
-        if PinYinParser.correct_table:
-            return
-        for key, id in pydict.PINYIN_DICT.items ():
-            if key[-3:] in PinYinParser.correct_yunmu:
-                for yunmu in PinYinParser.correct_yunmu[key[-3:]]:
-                    pinyin = key[:-3] + yunmu
-                    if pinyin not in pydict.PINYIN_DICT:
-                        PinYinParser.correct_table [pinyin] = key
-            if key[-2:] in PinYinParser.correct_yunmu:
-                for yunmu in PinYinParser.correct_yunmu[key[-2:]]:
-                    pinyin = key[:-2] + yunmu
-                    if pinyin not in pydict.PINYIN_DICT:
-                        PinYinParser.correct_table [pinyin] = key
-
-    def parse_recursive (self, string, auto_correct = True, gbk = True):
-        l = min (6, len (string))
-        if l == 0:
-            return []
-        p = None
-        for i in range (l, 0, -1):
-            py = string[-i:]
-
-            if gbk:
-                if py in self.pinyin_dict:
-                    p = pyutil.PinYinWord (py)
-                    break
-            else:
-                if py in self.gb2312_pinyin_dict:
-                    p = pyutil.PinYinWord (py)
-                    break
-
-            if p == None and auto_correct and py in PinYinParser.correct_table:
-                py = PinYinParser.correct_table[py]
-                if gbk:
-                    if py in self.pinyin_dict:
-                        p = pyutil.PinYinWord (py)
-                        break
-                else:
-                    if py in self.gb2312_pinyin_dict:
-                        p = pyutil.PinYinWord (py)
-                        break
-        if p == None:
-            raise Exception ("can not parse '%s'" % string.encode ("utf-8"))
-        pys = self.parse_recursive (string[:-i], auto_correct, gbk)
-        pys.append (p)
-        return pys
-
-    def parse (self, string, auto_correct = True, gbk = True):
-        try:
-            pys = []
-            for py in string.split (u"'"):
-                pys += self.parse_recursive (py, auto_correct, gbk)
-            return pys
-        except Exception, e:
-            import traceback
-            traceback.print_exc ()
-            raise e
-
-class ShuangPinParser:
-    def __init__ (self, schema = "MSPY"):
-        self._gbk = True
-        self._schema = schema
-        self._shengmu_dict, self._yunmu_dict = pydict.SHUANGPIN_SCHEMAS[self._schema]
-
-    def parse_shuangpin_recursive (self, pys, string, auto_correct = True, gbk = True):
-        if len (string) == 0:
-            return []
-
-        if len (string) == 1:
-            try:
-                shengmu = self._shengmu_dict[string[0]]
-                if shengmu == "'":
-                    shengmu = ""
-            except:
-                raise Exception ("can not parse '%s'" % string.encode ("utf-8"))
-
-            return [pyutil.PinYinWord (shengmu)]
-
-        try:
-            shengmu = self._shengmu_dict[string[0]]
-            if shengmu == "'":
-                shengmu = ""
-            yunmu = self._yunmu_dict[string[1]]
-        except:
-            raise Exception ("can not parse '%s'" % string.encode ("utf-8"))
-
-        p = None
-
-        for i in yunmu:
-            pinyin = shengmu + i
-            if pinyin in PinYinParser.pinyin_dict:
-                p = pyutil.PinYinWord (pinyin)
-                break
-
-        if p == None:
-            raise Exception ("can not parse '%s'" % string.encode ("utf-8"))
-
-        pys.append (p)
-        pys = self.parse_shuangpin_recursive (pys, string[2:], auto_correct, gbk)
-
-        return pys
-
-    def parse (self, string, auto_correct = True, gbk = True):
-        pys = []
-        pys += self.parse_shuangpin_recursive (pys, string, auto_correct, gbk)
-        return pys
-
-if __name__ == "__main__":
-    # parser = PinYinParser ()
-    parser = ShuangPinParser ()
-    pys = parser.parse (sys.argv[1])
-    print "'".join (map (str, pys))
-
diff --git a/engine/pysqlitedb.py b/engine/pysqlitedb.py
deleted file mode 100644 (file)
index 399c14a..0000000
+++ /dev/null
@@ -1,538 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim:set et sts=4 sw=4:
-#
-# ibus-pinyin - The PinYin engine for IBus
-#
-# Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-import os
-import os.path as path
-import time
-import sys
-import sqlite3 as sqlite
-import re
-import uuid
-import traceback
-import pyutil
-import pydict
-import pyparser
-
-(YLEN, Y0, Y1, Y2, Y3, YX, S0, S1, S2, S3, PHRASE, FREQ, USER_FREQ) = range(13)
-
-FLUSH_PERIOD = 60 * 5 # 5 minute
-
-class PYSQLiteDB:
-    """phrase database that contains all phrases and phrases' pinyin"""
-    def __init__ (self, name = "py.db", user_db = None, filename = None):
-
-        # init last flush time
-        self._last_flush_time = None
-
-        if filename:
-            self.db = sqlite.connect (filename)
-            self.parser = pyparser.PinYinParser ()
-            return
-
-        dirname = path.dirname(__file__)
-
-        name = os.path.join (dirname, name)
-
-        # open system phrase database
-        self.db = sqlite.connect (name)
-
-        self.parser = pyparser.PinYinParser ()
-        # self.db.execute ("PRAGMA locking_mode = EXCLUSIVE;")
-        self.db.execute ("PRAGMA synchronous = NORMAL;")
-        self.db.execute ("PRAGMA temp_store = MEMORY;")
-
-        if user_db != None:
-            home_path = os.getenv ("HOME")
-            pinyin_path = path.join (home_path, ".ibus", "pinyin")
-            user_db = path.join (pinyin_path, user_db)
-            if not path.isdir (pinyin_path):
-                os.makedirs (pinyin_path)
-
-            try:
-                desc = get_database_desc (user_db)
-                if desc == None or desc["id"] != "0.1":
-                    new_name = "%s.%d" %(user_db, os.getpid())
-                    print >> sys.stderr, "Can not support the user db. We will rename it to %s" % new_name
-                    os.rename (user_db, new_name)
-            except:
-                pass
-        else:
-            user_db = ":memory:"
-
-
-        # open user phrase database
-        try:
-            self.db.execute ("ATTACH DATABASE \"%s\" AS user_db;" % user_db)
-        except:
-            print >> sys.stderr, "The user database was damaged. We will recreate it!"
-            os.rename (user_db, "%s.%d" % (user_db, os.getpid ()))
-            self.db.execute ("ATTACH DATABASE \"%s\" AS user_db;" % user_db)
-
-
-        # try create all tables in user database
-        self.create_tables ("user_db")
-        self.create_indexes ("user_db")
-        self.generate_userdb_desc ()
-
-        self.select_cache = Cache ()
-
-    def create_tables (self, database = "main"):
-        """create all phrases tables that contain all phrases"""
-
-        try:
-            self.db.executescript ("PRAGMA default_cache_size = 5000;")
-            self.flush (True)
-        except:
-            pass
-
-        # create pinyin table
-        sqlstring = "CREATE TABLE IF NOT EXISTS %s.py_pinyin (pinyin TEXT PREMARY KEY);" % database
-        self.db.execute (sqlstring)
-
-        # create pinyin table
-        sqlstring = "CREATE TABLE IF NOT EXISTS %s.py_shengmu (shengmu TEXT PREMARY KEY);" % database
-        self.db.execute (sqlstring)
-
-        # create phrase table
-        sqlstring = """CREATE TABLE IF NOT EXISTS %(database)s.py_phrase (
-                            ylen INTEGER,
-                            y0 INTEGER, y1 INTEGER, y2 INTEGER, y3 INTEGER, yx TEXT,
-                            s0 INTEGER, s1 INTEGER, s2 INTEGER, s3 INTEGER,
-                            phrase TEXT,
-                            freq INTEGER, user_freq INTEGER);"""
-
-        self.db.executescript (sqlstring % { "database":database })
-        self.flush (True)
-
-    def generate_userdb_desc (self):
-        try:
-            sqlstring = "CREATE TABLE user_db.desc (name PRIMARY KEY, value);"
-            self.db.executescript (sqlstring)
-            sqlstring = "INSERT INTO user_db.desc  VALUES (?, ?);"
-            self.db.execute (sqlstring, ("version", "0.1"))
-            self.db.execute (sqlstring, ("id", str (uuid.uuid4 ())))
-            sqlstring = "INSERT INTO user_db.desc  VALUES (?, DATETIME(\"now\", \"localtime\"));"
-            self.db.execute (sqlstring, ("create-time", ))
-            self.flush (True)
-        except:
-            print "desc table has been created."
-
-    def create_indexes (self, database = "main"):
-        # create indexes
-        sqlstring = """
-                /*
-                CREATE INDEX IF NOT EXISTS %(database)s.py_phrase_index_1 ON
-                    py_phrase (y0, y1, y2, y3);
-                */
-
-                CREATE INDEX IF NOT EXISTS %(database)s.py_phrase_index_2 ON
-                    py_phrase (ylen, y0, y1, y2, y3);
-                CREATE INDEX IF NOT EXISTS %(database)s.py_phrase_index_3 ON
-                    py_phrase (ylen, s0, s1, s2, s3);
-
-                /*
-                CREATE INDEX IF NOT EXISTS %(database)s.py_phrase_index_4 ON
-                    py_phrase (s0, s1, s2, s2, s3);
-                CREATE INDEX IF NOT EXISTS %(database)s.py_phrase_index_5 ON
-                    py_phrase (phrase);
-                */
-                """
-        self.db.executescript (sqlstring % { "database" : database })
-        self.flush (True)
-
-    def optimize_database (self):
-        sqlstring = """
-                CREATE TABLE tmp AS SELECT * FROM py_phrase;
-                DELETE FROM py_phrase;
-                INSERT INTO py_phrase SELECT * FROM tmp ORDER BY ylen, y0, y1, y2, y3, yx, phrase;
-                DROP TABLE tmp;
-                """
-        self.db.executescript (sqlstring)
-        self.db.executescript ("VACUUM;")
-
-    def init_pinyin_table (self):
-        """create table pinyin that contains all pinyin"""
-        sqlstring = "INSERT INTO py_pinyin (pinyin) VALUES (?)"
-        for py in pydict.PINYIN_DICT.keys ():
-            self.db.execute (sqlstring, (unicode (py),))
-        self.flush (True)
-
-    def init_shengmu_table (self):
-        """create table shengmu that contains all shengmu of pinyin"""
-        sqlstring = "INSERT INTO py_shengmu (shengmu) VALUES (?)"
-        for shengmu in pydict.SHENGMU_DICT.keys ():
-            self.db.execute (sqlstring, (unicode (shengmu),))
-        self.flush (True)
-
-    def add_phrases (self, phrases, database = "main"):
-        """ add phrases to database, phrases is a iterable object
-        Like: [(phrase, pinyin, freq), (phrase, pinyin, freq), ...]
-        """
-        sqlstring = """INSERT INTO %s.py_phrase (ylen, y0, y1, y2, y3, yx, s0, s1, s2, s3, phrase, freq, user_freq)
-            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"""
-        line = 1
-        for  phrase, pinyin, freq in phrases:
-            try:
-                py = self.parser.parse (pinyin)
-                if len (py) != len (phrase):
-                    error_message = u"%s %s: Can not parse pinyin." % (phrase, pinyin)
-                    raise Exception (error_message.encode ("utf8"))
-                record = [None, None, None, None, None, None, None, None, None, None, None, None, None]
-                record [YLEN] = len (py)
-                i = 0
-                for p in py[:4]:
-                    record[Y0 + i] = p.get_pinyin_id ()
-                    record[S0 + i] = p.get_sheng_mu_id ()
-                    i += 1
-                if len (py) > 4:
-                    record[YX] = "'".join (map (str, py[4:]))
-                record[PHRASE] = phrase
-                record[FREQ] = freq
-                record[USER_FREQ] = None
-                self.db.execute (sqlstring % database, record)
-            except Exception, e:
-                print line, ":", phrase.encode ("utf-8"), pinyin, freq
-                import traceback
-                traceback.print_exc ()
-                # print e
-            line += 1
-
-        self.flush (True)
-
-    def get_pinyin_table (self):
-        """get pinyin table"""
-        try:
-            return self._pinyin_table
-        except:
-            pass
-
-        sql = "SELECT phrase, y0, s0 FROM py_phrase WHERE ylen = 1"
-
-        pinyin_table = {}
-        result = self.db.execute (sql % i)
-        for phrase, y0, s0 in result:
-            if phrase not in pinyin_table:
-                pinyin_table [phrase] = []
-            pinyin_table [phrase].append ((y0, s0))
-        self._pinyin_table = pinyin_table
-
-        return pinyin_table
-
-    def select_words_by_pinyin_list (self, pys, mohu = False):
-        """select words from database by list that contains pyutil.PinYinWord objects"""
-
-        pinyin_string = u"'".join (map (str, pys))
-        result = self.select_cache [pinyin_string]
-        if result != None:
-            return result
-
-        tables_union = """( SELECT * FROM main.py_phrase WHERE %(conditions)s UNION ALL
-        SELECT * FROM user_db.py_phrase WHERE %(conditions)s )"""
-
-        if mohu:
-            sql_conditions = ["+ylen = %d" % len (pys) ]
-        else:
-            sql_conditions = ["ylen = %d" % len (pys) ]
-
-
-        i = 0
-        if mohu == False:
-            for py in pys[:4]:
-                if py.is_valid_pinyin ():
-                    sql_conditions.append ("y%d = %d" % (i, py.get_pinyin_id ()))
-                else:
-                    sql_conditions.append ("s%d = %d" % (i, py.get_sheng_mu_id ()))
-                i += 1
-        else:
-            for py in pys[:4]:
-                if py.is_valid_pinyin ():
-                    shengmu = py.get_shengmu ()
-                    yunmu = py.get_pinyin ()[len (shengmu):]
-                    if shengmu in pydict.MOHU_SHENGMU:
-                        shengmu_list = pydict.MOHU_SHENGMU[shengmu]
-                    else:
-                        shengmu_list = [shengmu]
-
-                    if yunmu in pydict.MOHU_YUNMU:
-                        yunmu_list = pydict.MOHU_YUNMU[yunmu]
-                    else:
-                        yunmu_list = [yunmu]
-
-                    pinyin_ids = []
-                    for s in shengmu_list:
-                        for y in yunmu_list:
-                            pinyin = s + y
-                            if pinyin in pydict.PINYIN_DICT:
-                                pinyin_ids.append (str (pydict.PINYIN_DICT[pinyin]))
-                    if len (pinyin_ids) > 1:
-                        sql_conditions.append ("y%d in (%s)" % (i, ",".join (pinyin_ids)))
-                    else:
-                        sql_conditions.append ("y%d == %s" % (i, pinyin_ids[0]))
-
-                else:
-                    shengmu = py.get_shengmu ()
-                    if shengmu in pydict.MOHU_SHENGMU:
-                        shengmu_ids = []
-                        for s in pydict.MOHU_SHENGMU[shengmu]:
-                            shengmu_ids.append (str (pydict.SHENGMU_DICT[s]))
-                        sql_conditions.append ("s%d in (%s)" % (i, ",".join (shengmu_ids)))
-                    else:
-                        sql_conditions.append ("s%d = %d" % (i, py.get_sheng_mu_id ()))
-                i += 1
-
-        if pys[4:]:
-            pp = lambda (x): x.get_pattern (mohu)
-            pattern = "'".join (map (pp, pys[4:]))
-            sql_conditions.append ("yx LIKE \"" + pattern + "\"")
-
-
-        tables_union = tables_union % { "conditions" : " AND ".join (sql_conditions) }
-        sql_prefix = "SELECT * FROM " + tables_union
-
-        sql_string = sql_prefix + " GROUP BY phrase ORDER BY user_freq DESC, freq DESC;"
-
-        result = list (self.db.execute (sql_string).fetchall ())
-
-        self.select_cache [pinyin_string] = result
-
-        return result
-
-    def select_words_by_pinyin_string (self, string, mohu = False):
-        """select words from the database by pinyin string"""
-
-        pys = self.parser.parse (string)
-        result = self.select_words_by_pinyin_list (pys, mohu)
-        return result
-
-    def commit_phrases (self, records):
-        """this function adjusts frequence of phrase in user database."""
-
-        for record in records:
-            if record [USER_FREQ] != None:
-                sql = "UPDATE user_db.py_phrase SET user_freq = user_freq + 1 WHERE ylen = ? AND y0 = ? AND phrase = ?;"
-                self.db.execute (sql, (record[YLEN], record[Y0], record[PHRASE]))
-            else:
-                sql = """INSERT INTO user_db.py_phrase (ylen, y0, y1, y2, y3, yx, s0, s1, s2, s3, phrase, freq, user_freq)
-                    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1);"""
-                self.db.execute (sql, record[:12])
-        self.flush ()
-        self.select_cache.clear ()
-
-    def commit_phrase (self, record):
-        self.commit_phrases ([record])
-
-    def commit_char (self, char, pinyin_id, shengmu_id):
-        sql = "SELECT * FROM main.py_phrase WHERE ylen = 1 AND y0 = ? AND phrase = ?"
-        records = self.db.execute (sql, (pinyin_id, char)).fetchall ()
-        self.commit_phrases (records)
-
-    def new_phrase (self, phrases, freq = None, user_freq = 1):
-        """this function create a new phrase from a phrase list and put it into user database."""
-        pinyin_ids = []
-        shengmu_ids = []
-        phrase = u""
-        phrase_length = 0
-        for p in phrases:
-            if phrase_length + p[YLEN] > 8:
-                break
-            phrase += p[PHRASE]
-            phrase_length += p[YLEN]
-            if p[YLEN] > 4:
-                ys = p[YX].split ("'")
-            for i in range (0, p[YLEN]):
-                if i < 4:
-                    pinyin_ids.append (p[Y0 + i])
-                    shengmu_ids.append (p[S0 + i])
-                else:
-                    w = pyutil.PinYinWord (ys[i - 4])
-                    pinyin_ids.append (w.get_pinyin_id ())
-                    shengmu_ids.append (w.get_sheng_mu_id ())
-
-        sql = """INSERT INTO user_db.py_phrase
-            (ylen, y0, y1, y2, y3, yx, s0, s1, s2, s3, phrase, freq, user_freq)
-            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"""
-
-        values = [phrase_length, None, None, None, None, None, None, None, None, None, phrase, freq, user_freq]
-
-        if phrase_length <=4:
-            values[1: 1 + phrase_length] = pinyin_ids [:phrase_length]
-            values[6: 6 + phrase_length] = shengmu_ids [:phrase_length]
-        else:
-            values[1: 5] = pinyin_ids [:4]
-            values[6: 10] = shengmu_ids [:4]
-            get_pinyin = lambda id: pydict.ID_PINYIN_DICT[id]
-            values[5] = "'".join (map (get_pinyin, pinyin_ids[4:]))
-
-        self.db.execute (sql, values)
-
-        self.flush ()
-        self.select_cache.clear ()
-
-    def remove_phrase (self, record):
-        "Remove phrase from user database"
-
-        sql = "DELETE FROM user_db.py_phrase WHERE ylen = ? AND y0 = ? AND phrase = ?"
-
-        self.db.execute (sql, (record[YLEN], record[Y0], record[PHRASE]))
-
-        self.flush ()
-        self.select_cache.clear ()
-
-    def flush (self, force = False):
-        if self._last_flush_time == None:
-            self._last_flush_time = time.time ()
-        if force or time.time() - self._last_flush_time >= FLUSH_PERIOD:
-            self.db.commit ()
-            self._last_flush_time = time.time ()
-
-
-class Cache:
-    """cache object for cache history queries"""
-
-    class Slot:
-        """Slot item of cache object"""
-        def __init__ (self):
-            self.time = -1
-            self.value = None
-            self.index = None
-
-    def __init__ (self, max_slot = 1024):
-        self._max_slot = max_slot
-        self.clear ()
-
-    def clear (self):
-        self._slots = []
-        self._dict = {}
-        self._time = 0
-
-    def __delitem__ (self, index):
-        if not self._dict.has_key (index):
-            return None
-        del self._dict [index]
-
-    def __getitem__ (self, index):
-        """return a vale associate with the giving index. It cache does not has this index,
-        it will retrun None."""
-        if not self._dict.has_key (index):
-            return None
-
-        slot = self._dict [index]
-        self._time += 1
-        slot.time = self._time
-        return slot.value
-
-    def __setitem__ (self, index, value):
-        if self._dict.has_key (index):
-            slot = self._dict[index]
-        else:
-            slot = self.get_slot ()
-        self._time += 1
-        slot.value = value
-        slot.time = self._time
-        slot.index = index
-        self._dict[index] = slot
-
-    def get_slot (self):
-        """get_slot will return a empty slot. If there is not any empty slot
-        it will find the oldest slot and return it."""
-        if len (self._slots) < self._max_slot:
-            slot = Cache.Slot ()
-            self._slots.append (slot)
-        else:
-            self._slots.sort (lambda x,y : x.time - y.time)
-            slot = self._slots[0]
-            del self._dict[slot.index]
-        return slot
-
-def get_database_desc (db_file):
-    if not path.exists (db_file):
-        raise Exception ("%s does not exist!" % dbname)
-    try:
-        desc = {}
-        db = sqlite.connect (db_file)
-        for row in db.executescript ("SELECT * FROM desc;"):
-            desc [row[0]] = row[1]
-        return desc
-    except:
-        return None
-
-def test_select_words ():
-    import time
-
-    db = PYSQLiteDB ()
-    while True:
-        l = raw_input ().strip ()
-        if not l:
-            break
-        t = time.time ()
-        res = db.select_words_by_pinyin_string (l)
-
-        t = time.time () - t
-
-        i = 0
-        for p in res:
-            print "%s = %s %s " % (i, str (p), p[PHRASE].encode ("utf8"))
-            i += 1
-        print "OK t =", t, " count =", len (res)
-        while True:
-            try:
-                commit = int (raw_input ("commit = ").strip ())
-                db.commit_phrase (res[commit])
-            except KeyboardInterrupt, e:
-                print "Exit"
-                sys.exit (0)
-            except:
-                print "Input is invalidate"
-                continue
-            break
-
-
-
-def test_case (string):
-    db = PYSQLiteDB ()
-    parser = pyparser.PinYinParser ()
-    pys = parser.parse (string)
-
-    result = u""
-
-    while len (result) != len (pys):
-        pps = pys[len (result):]
-        for x in range (len (pps), 0, -1):
-            candidates = db.select_words_by_pinyin_list (pps[:x])
-            if candidates:
-                result += candidates[0][PHRASE]
-                break
-    print "'".join (map (str, pys))
-    print result
-
-def test ():
-    test_case ("gaodangfangdichankaifashangdedongtianjiuyaolaile")
-    test_case ("huanyingshiyongwokaifadezhinengpinyinshurufa")
-    test_case ("beijingshirenminzhengfujuedingzaitongzhouqujianlizhengfuxingzhengjidi")
-    test_case ("woguojuminshoumingqiwangtigaodaoqishisansui")
-    test_case ("wgjmshmqwtgdqshss")
-    test_case ("xjinyhuiyouyongme")
-
-if __name__ == "__main__":
-    import timeit
-    t = timeit.Timer ("pysqlitedb.test ()", "import pysqlitedb")
-    print t.repeat (3,1)
-
diff --git a/engine/special_phrase b/engine/special_phrase
deleted file mode 100644 (file)
index b1076f6..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-# py   phrase
-hehe   :-)
-haha   ^_^
-haha   o(∩_∩)o...哈哈
-xixi   (*^__^*) 嘻嘻……
-bsn    ╭∩╮(︶︿︶)╭∩╮鄙视你!
-rq     #%(year)d年%(month)d月%(day)d日
-rq     #%(year)d-%(month)d-%(day)d
-sj     #%(hour_24)d时%(minute)d分%(second)d秒
-sj     #%(hour_24)d:%(minute)d:%(second)d
-xq     #星期%(week1)s
-xq     #星期%(week2)s
-xq     #礼拜%(week1)s
-xq     #礼拜%(week2)s
-lb     #礼拜%(week1)s
-lb     #礼拜%(week2)s
-lb     #星期%(week1)s
-lb     #星期%(week2)s
diff --git a/engine/specialphrase.py b/engine/specialphrase.py
deleted file mode 100644 (file)
index 5f2ac6c..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-# vim: set noet ts=4:
-# -*- coding: utf-8 -*-
-#
-# scim-python
-#
-# Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
-#
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the
-# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
-# Boston, MA  02111-1307  USA
-#
-# $Id: $
-#
-import os.path
-import time
-
-class SpecialPhrase:
-       _dict = None
-       def __init__ (self):
-               if SpecialPhrase._dict == None:
-                       self._load_table ()
-                       SpecialPhrase._dict = self._dict
-               else:
-                       self._dict = SpecialPhrase._dict        
-
-       def _load_table (self):
-               self._dict = {}
-               name = os.path.join (os.getenv("IBUS_PINYIN_LOCATION"), "engine", "special_phrase")
-               for l in file (name):
-                       l = l.strip ()
-                       if l == "" or l[0] == "#":
-                               continue
-                       py, phrase = l.split ("\t")
-                       phrase = unicode (phrase, "utf8")
-                       if py not in self._dict:
-                               self._dict[py] = []
-                       self._dict[py].append (phrase)
-
-       def lookup (self, py):
-               result = []
-               now = time.localtime ()
-               weeks1 = (u"一", u"二", u"三", u"四", u"五", u"六", u"日")
-               weeks2 = (u"一", u"二", u"三", u"四", u"五", u"六", u"天")
-               values = {
-                       "year" : now[0],
-                       "month" : now[1],
-                       "day" : now[2],
-                       "hour_24" : now[3],
-                       "minute" : now[4],
-                       "second" : now[5],
-                       "week1" : weeks1[now[6]],
-                       "week2" : weeks2[now[6]],
-               }
-               if py in self._dict:
-                       for phrase in self._dict[py]:
-                               if phrase[0] == "#":
-                                       phrase = phrase[1:] % values
-                               if phrase not in result:
-                                       result.append (phrase)
-               return result
-
-if __name__ == "__main__":
-       SpecialPhrase ()._load_table ()
-
diff --git a/engine/specialtable.py b/engine/specialtable.py
deleted file mode 100644 (file)
index cdabbe0..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-# vim: set noet ts=4:
-#
-# scim-python
-#
-# Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
-#
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the
-# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
-# Boston, MA  02111-1307  USA
-#
-# $Id: $
-#
-import os.path
-import time
-
-class SpecialTable:
-       _dict = None
-       def __init__ (self):
-               if SpecialTable._dict == None:
-                       self._load_table ()
-
-       def _load_table (self):
-               _dict = {}
-               def parse_table (name, _dict):
-                       if not os.path.isfile (name):
-                               return
-                       for l in file (name):
-                               l = l.strip ()
-                               if l == "" or l[0] == "#":
-                                       continue
-                               key, values = l.decode ("utf8").split (u"=")
-                               key = key.strip ()
-                               values = map (lambda x: x.decode ("utf8"), eval (values + u","))
-                               if key not in _dict:
-                                       _dict[key] = []
-                               _dict[key] += list (values)
-               name = os.path.join (os.getenv("IBUS_PINYIN_LOCATION"), "engine", "special_table")
-               try:
-                       parse_table (name, _dict)
-               except Exception, e:
-                       print e
-               name = os.path.expanduser ("~/.scim/scim-python/pinyin/special_table")
-               try:
-                       parse_table (name, _dict)
-               except Exception, e:
-                       print e
-               SpecialTable._dict = _dict
-
-       def lookup (self, key):
-               if key in SpecialTable._dict:
-                       return  SpecialTable._dict[key][:]
-               keys = SpecialTable._dict.keys ()
-               keys = filter (lambda k: k.startswith(key), keys)
-               if len (keys) == 1:
-                       return SpecialTable._dict.get (keys[0], [])[:]
-               else:
-                       return []
-
-if __name__ == "__main__":
-       SpecialTable ()._load_table ()
-       print SpecialTable._dict
-
index d3648a3..fca54f4 100644 (file)
@@ -1,26 +1,32 @@
 Name:       @PACKAGE_NAME@
 Version:    @PACKAGE_VERSION@
 Release:    1%{?dist}
-Summary:    The PinYin engine for IBus platform
+Summary:    The Chinese Pinyin engine for IBus input platform
 License:    GPLv2+
 Group:      System Environment/Libraries
 URL:        http://code.google.com/p/ibus/
 Source0:    http://ibus.googlecode.com/files/%{name}-%{version}.tar.gz
-Source1:    http://scim-python.googlecode.com/files/pinyin-database-0.1.10.6.tar.bz2
+Source1:    pinyin-database-1.2.99.tar.bz2
 
 BuildRoot:  %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
-BuildArch:  noarch
 
 BuildRequires:  gettext-devel
+BuildRequires:  libtool
+BuildRequires:  pkgconfig
+BuildRequires:  sqlite-devel
+BuildRequires:  libuuid-devel
+BuildRequires:  ibus-devel >= 1.2.0
 
-Requires:   ibus
+Requires(post): sqlite
+
+Requires:   ibus >= 1.2.0
 
 %description
-PinYin engine for IBus platform. It provides a Chinese PinYin input method.
+The Chinese Pinyin input method for IBus platform.
 
 %prep
 %setup -q
-cp %{SOURCE1} engine
+cp %{SOURCE1} data
 
 %build
 %configure --disable-static
@@ -37,17 +43,17 @@ make DESTDIR=${RPM_BUILD_ROOT} NO_INDEX=true install
 rm -rf $RPM_BUILD_ROOT
 
 %post
-cd /usr/share/ibus-pinyin/engine
-python -c "import pysqlitedb; db = pysqlitedb.PYSQLiteDB (); db.create_indexes ();" >/dev/null
+cd %{_datadir}/ibus-pinyin/db
+sqlite3 main.db ".read create_index.sql"
 
 %files -f %{name}.lang
 %defattr(-,root,root,-)
 %doc AUTHORS COPYING README
-%{_datadir}/ibus-pinyin
-%{_datadir}/ibus/component/*
 %{_libexecdir}/ibus-engine-pinyin
 %{_libexecdir}/ibus-setup-pinyin
+%{_datadir}/@PACKAGE@
+%{_datadir}/ibus/component/*
 
 %changelog
-* Wed Jun 25 2008 Huang Peng <shawn.p.huang@gmail.com> - @VERSION@-1
+* Fri Aug 08 2008 Huang Peng <shawn.p.huang@gmail.com> - @VERSION@-1
 - The first version.
index 4caba33..22bdb91 100644 (file)
@@ -1,3 +1,2 @@
-ja
 zh_CN
 
index 17701be..e249584 100644 (file)
@@ -1,12 +1,11 @@
-./engine/pydict.py
-./engine/main.py
-./engine/pysqlitedb.py
-./engine/specialtable.py
-./engine/pyparser.py
-./engine/pinyin.py
-./engine/pyutil.py
-./engine/specialphrase.py
-./engine/factory.py
-./setup/pydict.py
-./setup/main.py
-./setup/setup.glade
+src/Config.cc
+src/Database.cc
+src/Engine.cc
+src/HalfFullConverter.cc
+src/Main.cc
+src/PhraseEditor.cc
+src/PinyinEditor.cc
+src/PinyinEngine.cc
+src/PinyinParser.cc
+src/SpecialTable.cc
+setup/ibus-pinyin-preferences.glade
diff --git a/po/ja.po b/po/ja.po
deleted file mode 100644 (file)
index b72370d..0000000
--- a/po/ja.po
+++ /dev/null
@@ -1,245 +0,0 @@
-# Japanese translation of ibus-pinyin.
-# Copyright (C) 2008 Huang Peng <shawn.p.huang@gmail.com>
-# This file is distributed under the same license as the ibus-pinyin package.
-# UTUMI Hirosi <utuhiro78@yahoo.co.jp>, 2008.
-#
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: ibus-pinyin VERSION\n"
-"Report-Msgid-Bugs-To: http://code.google.com/p/ibus/issues/entry\n"
-"POT-Creation-Date: 2009-09-19 15:09+0800\n"
-"PO-Revision-Date: 2008-08-28 19:19+0900\n"
-"Last-Translator: UTUMI Hirosi <utuhiro78@yahoo.co.jp>\n"
-"Language-Team: Japanese <gnome-translation@gnome.gr.jp>\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-
-#: engine/pydict.py:358 setup/pydict.py:358
-msgid "MSPY"
-msgstr "MSPY"
-
-#: engine/pydict.py:359 setup/pydict.py:359
-msgid "ZRM"
-msgstr "ZRM"
-
-#: engine/pydict.py:360 setup/pydict.py:360
-msgid "ABC"
-msgstr "ABC"
-
-#: engine/pydict.py:361 setup/pydict.py:361
-msgid "ZGPY"
-msgstr "ZGPY"
-
-#: engine/pydict.py:362 setup/pydict.py:362
-msgid "PYJJ"
-msgstr "PYJJ"
-
-#: engine/pinyin.py:155
-msgid "Configure PinYin"
-msgstr "ピンインを設定"
-
-#: engine/pinyin.py:162
-msgid "CN"
-msgstr "中"
-
-#: engine/pinyin.py:163
-msgid "Switch to English mode"
-msgstr "英語モードに切替"
-
-#: engine/pinyin.py:166
-msgid "EN"
-msgstr "英"
-
-#: engine/pinyin.py:167
-msgid "Switch to Chinese mode"
-msgstr "中国語モードに切替"
-
-#: engine/pinyin.py:172
-msgid "Switch to half letter mode"
-msgstr "半角文字モードに切替"
-
-#: engine/pinyin.py:176
-msgid "Switch to full letter mode"
-msgstr "全角文字モードに切替"
-
-#: engine/pinyin.py:181
-msgid "Switch to half punctuation mode"
-msgstr "半角句読点モードに切替"
-
-#: engine/pinyin.py:185
-msgid "Switch to full punctuation mode"
-msgstr "全角句読点モードに切替"
-
-#: engine/factory.py:33
-msgid "PinYin"
-msgstr "ピンイン"
-
-#: setup/main.py:216
-msgid "Are you sure to close Python PinYin Setup without save configure?"
-msgstr "設定を保存せずに Python ピンインセットアップを閉じますか?"
-
-#: setup/main.py:227
-msgid ""
-"The user phrases database will be reorganized! Please don't use python "
-"PinYin now."
-msgstr ""
-"ユーザーフレーズデータベースを再構築します。Python ピンインを使わないでくださ"
-"い"
-
-#: setup/main.py:249
-msgid "Reorganizing is over!"
-msgstr "再構築しました"
-
-#: setup/setup.glade:7
-msgid "Python PinYin Setup"
-msgstr "Python ピンインセットアップ"
-
-#: setup/setup.glade:43
-#, fuzzy
-msgid "Half punctuations"
-msgstr "半角句読点モードに切替"
-
-#: setup/setup.glade:54
-msgid "Press [u] or [v]  to temporary English mode"
-msgstr "[u] か [v] で一時的な英語モード"
-
-#: setup/setup.glade:118 setup/setup.glade:132
-msgid "1\n"
-msgstr "1\n"
-
-#: setup/setup.glade:147
-msgid "English spelling check"
-msgstr "英語スペルのチェック"
-
-#: setup/setup.glade:158
-msgid "Wrong PinYin auto correct"
-msgstr "誤ったピンインの自動修正"
-
-#: setup/setup.glade:169
-msgid "Lookup table page size"
-msgstr "ページ当たりの候補の数"
-
-#: setup/setup.glade:180
-msgid "ShuangPin Schema"
-msgstr "ShuangPin スキーマ"
-
-#: setup/setup.glade:191
-msgid "ShuangPin"
-msgstr "ShuangPin"
-
-#: setup/setup.glade:202
-msgid "Support GBK"
-msgstr "GBK をサポート"
-
-#: setup/setup.glade:243
-msgid "Press [shift] to select candidates"
-msgstr "[shift] で候補を選択"
-
-#: setup/setup.glade:271
-msgid "Press [-] [=] to page down up."
-msgstr "[-] [=] でページを切替"
-
-#: setup/setup.glade:333
-msgid "Auto commit"
-msgstr "自動確定"
-
-#: setup/setup.glade:344
-msgid "Press [,] [.] to page down up."
-msgstr "[,] [.] でページを切替"
-
-#: setup/setup.glade:356
-#, fuzzy
-msgid "General"
-msgstr "一般"
-
-#: setup/setup.glade:373
-msgid "Enable Fuzzy PinYin"
-msgstr "ファジーピンイン有効"
-
-#: setup/setup.glade:383
-msgid "s <=> sh"
-msgstr "s <=> sh"
-
-#: setup/setup.glade:398
-msgid "c <=> ch"
-msgstr "c <=> ch"
-
-#: setup/setup.glade:413
-msgid "z <=> zh"
-msgstr "z <=> zh"
-
-#: setup/setup.glade:428
-msgid "l <=> n"
-msgstr "l <=> n"
-
-#: setup/setup.glade:443
-msgid "in <=> ing"
-msgstr "in <=> ing"
-
-#: setup/setup.glade:460
-msgid "en <=> eng"
-msgstr "en <=> eng"
-
-#: setup/setup.glade:477
-msgid "an <=> ang"
-msgstr "an <=> ang"
-
-#: setup/setup.glade:547
-msgid "Fuzzy PinYin"
-msgstr "ファジーピンイン"
-
-#: setup/setup.glade:567
-msgid "Color of Spelling Error"
-msgstr "スペルエラーの色"
-
-#: setup/setup.glade:578
-msgid "Color of English Candidates"
-msgstr "英語候補の色"
-
-#: setup/setup.glade:589
-msgid "Color of Special Phrases"
-msgstr "特殊語句の色"
-
-#: setup/setup.glade:600
-msgid "Color of User Phrases"
-msgstr "ユーザー語句の色"
-
-#: setup/setup.glade:611
-msgid "Color of New Phrases"
-msgstr "新規語句の色"
-
-#: setup/setup.glade:622
-msgid "Color of Normal Phrases"
-msgstr "一般語句の色"
-
-#: setup/setup.glade:745
-msgid "Colors"
-msgstr "配色"
-
-#: setup/setup.glade:784
-msgid "Optimize User DB"
-msgstr "ユーザーDBを最適化"
-
-#: setup/setup.glade:858
-msgid "User DB"
-msgstr "ユーザーDB"
-
-#: setup/setup.glade:869
-msgid ""
-"Python PinYin\n"
-"\n"
-"provided by\n"
-"\n"
-"Huang Peng <shawn.p.huang@gmail.com>\n"
-msgstr ""
-"Python PinYin\n"
-"\n"
-"provided by\n"
-"\n"
-"Huang Peng <shawn.p.huang@gmail.com>\n"
-
-#: setup/setup.glade:883
-msgid "About"
-msgstr "About"
diff --git a/po/zh_CN.gmo b/po/zh_CN.gmo
new file mode 100644 (file)
index 0000000..a0147ff
Binary files /dev/null and b/po/zh_CN.gmo differ
index a6efd4c..b62e0b9 100644 (file)
-# Translation for ibus-pinyin
+# SOME DESCRIPTIVE TITLE.
 # Copyright (C) YEAR Huang Peng <shawn.p.huang@gmail.com>
-# This file is distributed under the same license as the ibus-pinyin package.
-# Huang Peng <shawn.p.huang@gmail.com>, 2008.
+# This file is distributed under the same license as the PACKAGE package.
+# Huang Peng <shawn.p.huang@gmail.com>, 2009.
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: 0.1.1.20080813\n"
+"Project-Id-Version: ibus-pinyin 1.3.0\n"
 "Report-Msgid-Bugs-To: http://code.google.com/p/ibus/issues/entry\n"
-"POT-Creation-Date: 2009-09-19 15:09+0800\n"
-"PO-Revision-Date: 2008-08-13 22:52+0800\n"
-"Last-Translator: Huang Peng <shawn.p.huang@gmail.com>\n"
-"Language-Team: Huang Peng <shawn.p.huang@gmail.com>\n"
+"POT-Creation-Date: 2009-09-22 17:10+0800\n"
+"PO-Revision-Date: 2009-09-20 16:05+8\n"
+"Last-Translator: Peng Huang <shawn.p.huang@gmail.com>\n"
+"Language-Team: Peng Huang <shawn.p.huang@gmail.com>\n"
 "MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=utf-8\n"
+"Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: engine/pydict.py:358 setup/pydict.py:358
-msgid "MSPY"
-msgstr "微软拼音"
+#: src/Main.cc:50 src/Main.cc:59 src/Main.cc:60
+msgid "Pinyin input method"
+msgstr "拼音输入法"
 
-#: engine/pydict.py:359 setup/pydict.py:359
-msgid "ZRM"
-msgstr "自然码"
+#: src/PinyinEngine.cc:44 setup/ibus-pinyin-preferences.glade:188
+msgid "Chinese"
+msgstr "中文"
 
-#: engine/pydict.py:360 setup/pydict.py:360
-msgid "ABC"
-msgstr "智能ABC"
+#: src/PinyinEngine.cc:57
+msgid "Full/Half width"
+msgstr "全角/半角"
 
-#: engine/pydict.py:361 setup/pydict.py:361
-msgid "ZGPY"
-msgstr "紫光拼音"
+#: src/PinyinEngine.cc:70
+msgid "Full/Half width punctuation"
+msgstr "半角符号"
 
-#: engine/pydict.py:362 setup/pydict.py:362
-msgid "PYJJ"
-msgstr "拼音加加"
-
-#: engine/pinyin.py:155
-msgid "Configure PinYin"
+#: src/PinyinEngine.cc:79 src/PinyinEngine.cc:81
+#: setup/ibus-pinyin-preferences.glade:7
+msgid "Pinyin preferences"
 msgstr "拼音设置"
 
-#: engine/pinyin.py:162
-msgid "CN"
-msgstr "中"
-
-#: engine/pinyin.py:163
-msgid "Switch to English mode"
-msgstr "切换到英语"
-
-#: engine/pinyin.py:166
-msgid "EN"
-msgstr "英"
-
-#: engine/pinyin.py:167
-msgid "Switch to Chinese mode"
-msgstr "切换到中文"
-
-#: engine/pinyin.py:172
-msgid "Switch to half letter mode"
-msgstr "字母切换到半角"
+#: setup/ibus-pinyin-preferences.glade:51
+msgid "Full pinyin"
+msgstr "全拼"
 
-#: engine/pinyin.py:176
-msgid "Switch to full letter mode"
-msgstr "字母切换到全角"
-
-#: engine/pinyin.py:181
-msgid "Switch to half punctuation mode"
-msgstr "标点切换到半角"
-
-#: engine/pinyin.py:185
-msgid "Switch to full punctuation mode"
-msgstr "标点切换到全角"
+#: setup/ibus-pinyin-preferences.glade:65
+msgid "Double pinyin"
+msgstr "双拼"
 
-#: engine/factory.py:33
-msgid "PinYin"
-msgstr "拼音"
+#: setup/ibus-pinyin-preferences.glade:79
+msgid "Simple pinyin"
+msgstr "简拼"
 
-#: setup/main.py:216
-msgid "Are you sure to close Python PinYin Setup without save configure?"
-msgstr ""
+#: setup/ibus-pinyin-preferences.glade:99
+msgid "Schema:"
+msgstr "双拼方案:"
 
-#: setup/main.py:227
-msgid ""
-"The user phrases database will be reorganized! Please don't use python "
-"PinYin now."
-msgstr "准备优化用户词库,请不要使用拼音输入法!"
+#: setup/ibus-pinyin-preferences.glade:132
+msgid "<b>Pinyin</b>"
+msgstr "<b>拼音</b>"
 
-#: setup/main.py:249
-msgid "Reorganizing is over!"
-msgstr "优化完毕!"
+#: setup/ibus-pinyin-preferences.glade:161
+msgid "Language:"
+msgstr "语言:"
 
-#: setup/setup.glade:7
-msgid "Python PinYin Setup"
-msgstr "拼音设置"
+#: setup/ibus-pinyin-preferences.glade:168
+msgid "Half/full with:"
+msgstr "全角/半角:"
 
-#: setup/setup.glade:43
-msgid "Half punctuations"
-msgstr "å\8d\8aè§\92æ \87ç\82¹"
+#: setup/ibus-pinyin-preferences.glade:179
+msgid "Half/full punctuation:"
+msgstr "å\85¨è§\92\8d\8aè§\92æ \87ç\82¹:"
 
-#: setup/setup.glade:54
-msgid "Press [u] or [v]  to temporary English mode"
-msgstr "使用[u]或者[v]自动进入临时英语模式"
+#: setup/ibus-pinyin-preferences.glade:203
+msgid "English"
+msgstr "英文"
 
-#: setup/setup.glade:118 setup/setup.glade:132
-msgid "1\n"
-msgstr ""
+#: setup/ibus-pinyin-preferences.glade:216
+#: setup/ibus-pinyin-preferences.glade:248
+msgid "Full"
+msgstr "全角"
 
-#: setup/setup.glade:147
-msgid "English spelling check"
-msgstr "英语单词拼写检查"
+#: setup/ibus-pinyin-preferences.glade:233
+#: setup/ibus-pinyin-preferences.glade:264
+msgid "Half"
+msgstr "半角"
 
-#: setup/setup.glade:158
-msgid "Wrong PinYin auto correct"
-msgstr "自动纠正错误拼音"
+#: setup/ibus-pinyin-preferences.glade:285
+msgid "<b>Initial state</b>"
+msgstr "<b>初始状态</b>"
 
-#: setup/setup.glade:169
-msgid "Lookup table page size"
-msgstr "候选词个数"
+#: setup/ibus-pinyin-preferences.glade:316
+msgid "Number of candidates:"
+msgstr "每页候选词个数:"
 
-#: setup/setup.glade:180
-msgid "ShuangPin Schema"
-msgstr "双拼方案"
+#: setup/ibus-pinyin-preferences.glade:335
+msgid "Press [Shift] key to select candidate"
+msgstr "按[Shift]键选词"
 
-#: setup/setup.glade:191
-msgid "ShuangPin"
-msgstr "双拼"
+#: setup/ibus-pinyin-preferences.glade:350
+msgid "Press [-] [=] key to flip page"
+msgstr "按[-][=]键翻页"
 
-#: setup/setup.glade:202
-msgid "Support GBK"
-msgstr "大字符集"
+#: setup/ibus-pinyin-preferences.glade:365
+msgid "Press [,] [.] key to flip page"
+msgstr "按[,][.]键翻页"
 
-#: setup/setup.glade:243
-msgid "Press [shift] to select candidates"
-msgstr "按 [shift] 选词"
+#: setup/ibus-pinyin-preferences.glade:380
+msgid "Auto commit phrase"
+msgstr "自动上词"
 
-#: setup/setup.glade:271
-msgid "Press [-] [=] to page down up."
-msgstr "按 [-] [=] 上下翻页。"
+#: setup/ibus-pinyin-preferences.glade:397
+msgid "Half width punctuations:"
+msgstr "半角符号:"
 
-#: setup/setup.glade:333
-msgid "Auto commit"
-msgstr "自动上词"
+#: setup/ibus-pinyin-preferences.glade:410
+msgid "+-*/=%"
+msgstr "+-*/=%"
 
-#: setup/setup.glade:344
-msgid "Press [,] [.] to page down up."
-msgstr "按 [,] [.] 上下翻页。"
+#: setup/ibus-pinyin-preferences.glade:426
+msgid "<b>Others</b>"
+msgstr "<b>其他</b>"
 
-#: setup/setup.glade:356
+#: setup/ibus-pinyin-preferences.glade:443
 msgid "General"
 msgstr "常规"
 
-#: setup/setup.glade:373
-msgid "Enable Fuzzy PinYin"
-msgstr "启动模糊拼音"
-
-#: setup/setup.glade:383
-msgid "s <=> sh"
-msgstr ""
-
-#: setup/setup.glade:398
-msgid "c <=> ch"
-msgstr ""
-
-#: setup/setup.glade:413
-msgid "z <=> zh"
-msgstr ""
-
-#: setup/setup.glade:428
-msgid "l <=> n"
-msgstr ""
-
-#: setup/setup.glade:443
-msgid "in <=> ing"
-msgstr ""
-
-#: setup/setup.glade:460
-msgid "en <=> eng"
-msgstr ""
+#: setup/ibus-pinyin-preferences.glade:463
+#: setup/ibus-pinyin-preferences.glade:595
+msgid "Correct pinyin"
+msgstr "拼音纠错"
 
-#: setup/setup.glade:477
-msgid "an <=> ang"
-msgstr ""
+#: setup/ibus-pinyin-preferences.glade:575
+msgid "<b>Correct pinyin</b>"
+msgstr "<b>拼音纠错</b>"
 
-#: setup/setup.glade:547
-msgid "Fuzzy PinYin"
+#: setup/ibus-pinyin-preferences.glade:616
+#: setup/ibus-pinyin-preferences.glade:1037
+msgid "Fuzzy pinyin"
 msgstr "模糊拼音"
 
-#: setup/setup.glade:567
-msgid "Color of Spelling Error"
-msgstr "错误拼写英文单词的颜色"
-
-#: setup/setup.glade:578
-msgid "Color of English Candidates"
-msgstr "英文单词的颜色"
-
-#: setup/setup.glade:589
-msgid "Color of Special Phrases"
-msgstr "特殊词语的颜色"
-
-#: setup/setup.glade:600
-msgid "Color of User Phrases"
-msgstr "用户自造词的颜色"
-
-#: setup/setup.glade:611
-msgid "Color of New Phrases"
-msgstr "系统自动生成的新候选词的颜色"
+#: setup/ibus-pinyin-preferences.glade:1017
+msgid "<b>Fuzzy pinyin</b>"
+msgstr "<b>模糊拼音</b>"
 
-#: setup/setup.glade:622
-msgid "Color of Normal Phrases"
-msgstr "普通候选词的颜色"
+#: setup/ibus-pinyin-preferences.glade:1074
+msgid "<big><b>IBus Pinyin 1.3.0</b></big>"
+msgstr "<big><b>IBus Pinyin 1.3.0</b></big>"
 
-#: setup/setup.glade:745
-msgid "Colors"
-msgstr "颜色"
+#: setup/ibus-pinyin-preferences.glade:1085
+msgid "Pinyin input method for IBus"
+msgstr "Pinyin input method for IBus"
 
-#: setup/setup.glade:784
-msgid "Optimize User DB"
-msgstr "优化用户词库"
-
-#: setup/setup.glade:858
-msgid "User DB"
-msgstr "用户词库"
-
-#: setup/setup.glade:869
+#: setup/ibus-pinyin-preferences.glade:1095
 msgid ""
-"Python PinYin\n"
-"\n"
-"provided by\n"
-"\n"
-"Huang Peng <shawn.p.huang@gmail.com>\n"
+"<small>Copyright (c) 2009 Huang Peng &lt;shawn.p.huang@gmail.com&gt;</small>"
 msgstr ""
+"<small>Copyright (c) 2009 Huang Peng &lt;shawn.p.huang@gmail.com&gt;</small>"
 
-#: setup/setup.glade:883
+#: setup/ibus-pinyin-preferences.glade:1105
+msgid "http://ibus.googlecode.com"
+msgstr "http://ibus.googlecode.com"
+
+#: setup/ibus-pinyin-preferences.glade:1135
 msgid "About"
 msgstr "关于"
+
+#~ msgid "gtk-close"
+#~ msgstr "gtk-close"
index 4a4b53a..a83dcb3 100644 (file)
@@ -19,9 +19,8 @@
 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
 setup_pinyin_PYTHON = \
-       pydict.py \
        main.py \
-       setup.glade \
+       ibus-pinyin-preferences.glade \
        $(NULL)
 setup_pinyindir = $(datadir)/ibus-pinyin/setup
 
diff --git a/setup/ibus-pinyin-preferences.glade b/setup/ibus-pinyin-preferences.glade
new file mode 100644 (file)
index 0000000..95eefd9
--- /dev/null
@@ -0,0 +1,1239 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkDialog" id="dialog">
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Pinyin preferences</property>
+    <property name="icon_name">gtk-preferences</property>
+    <property name="type_hint">normal</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GtkNotebook" id="notebook1">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <child>
+              <object class="GtkAlignment" id="alignment5">
+                <property name="visible">True</property>
+                <property name="top_padding">12</property>
+                <property name="bottom_padding">12</property>
+                <property name="left_padding">12</property>
+                <property name="right_padding">12</property>
+                <child>
+                  <object class="GtkVBox" id="vbox4">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <property name="spacing">12</property>
+                    <child>
+                      <object class="GtkFrame" id="frame3">
+                        <property name="visible">True</property>
+                        <property name="label_xalign">0</property>
+                        <property name="shadow_type">none</property>
+                        <child>
+                          <object class="GtkAlignment" id="alignment6">
+                            <property name="visible">True</property>
+                            <property name="top_padding">6</property>
+                            <property name="left_padding">12</property>
+                            <child>
+                              <object class="GtkTable" id="table2">
+                                <property name="visible">True</property>
+                                <property name="n_rows">2</property>
+                                <property name="n_columns">2</property>
+                                <property name="column_spacing">12</property>
+                                <property name="row_spacing">6</property>
+                                <child>
+                                  <object class="GtkRadioButton" id="FullPinyin">
+                                    <property name="label" translatable="yes">Full pinyin</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                    <property name="group">DoublePinyin</property>
+                                  </object>
+                                  <packing>
+                                    <property name="x_options">GTK_FILL</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkRadioButton" id="DoublePinyin">
+                                    <property name="label" translatable="yes">Double pinyin</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="top_attach">1</property>
+                                    <property name="bottom_attach">2</property>
+                                    <property name="x_options">GTK_FILL</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="SimplePinyin">
+                                    <property name="label" translatable="yes">Simple pinyin</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkHBox" id="hbox1">
+                                    <property name="visible">True</property>
+                                    <property name="spacing">6</property>
+                                    <child>
+                                      <object class="GtkLabel" id="labelDoublePinyinSchema">
+                                        <property name="visible">True</property>
+                                        <property name="xalign">0</property>
+                                        <property name="label" translatable="yes">Schema:</property>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="position">0</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkComboBox" id="DoublePinyinSchema">
+                                        <property name="visible">True</property>
+                                        <property name="sensitive">False</property>
+                                        <property name="model">liststoreDoublePinyin</property>
+                                        <property name="button_sensitivity">on</property>
+                                      </object>
+                                      <packing>
+                                        <property name="position">1</property>
+                                      </packing>
+                                    </child>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                    <property name="top_attach">1</property>
+                                    <property name="bottom_attach">2</property>
+                                  </packing>
+                                </child>
+                              </object>
+                            </child>
+                          </object>
+                        </child>
+                        <child type="label">
+                          <object class="GtkLabel" id="label6">
+                            <property name="visible">True</property>
+                            <property name="label" translatable="yes">&lt;b&gt;Pinyin&lt;/b&gt;</property>
+                            <property name="use_markup">True</property>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkFrame" id="frame4">
+                        <property name="visible">True</property>
+                        <property name="label_xalign">0</property>
+                        <property name="shadow_type">none</property>
+                        <child>
+                          <object class="GtkAlignment" id="alignment7">
+                            <property name="visible">True</property>
+                            <property name="top_padding">6</property>
+                            <property name="left_padding">12</property>
+                            <child>
+                              <object class="GtkTable" id="table4">
+                                <property name="visible">True</property>
+                                <property name="n_rows">3</property>
+                                <property name="n_columns">3</property>
+                                <child>
+                                  <object class="GtkLabel" id="label9">
+                                    <property name="visible">True</property>
+                                    <property name="xalign">0</property>
+                                    <property name="label" translatable="yes">Language:</property>
+                                  </object>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="label10">
+                                    <property name="visible">True</property>
+                                    <property name="xalign">0</property>
+                                    <property name="label" translatable="yes">Half/full with:</property>
+                                  </object>
+                                  <packing>
+                                    <property name="top_attach">1</property>
+                                    <property name="bottom_attach">2</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="label11">
+                                    <property name="visible">True</property>
+                                    <property name="xalign">0</property>
+                                    <property name="label" translatable="yes">Half/full punctuation:</property>
+                                  </object>
+                                  <packing>
+                                    <property name="top_attach">2</property>
+                                    <property name="bottom_attach">3</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkRadioButton" id="InitChinese">
+                                    <property name="label" translatable="yes">Chinese</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                    <property name="group">InitEnglish</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkRadioButton" id="InitEnglish">
+                                    <property name="label" translatable="yes">English</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">2</property>
+                                    <property name="right_attach">3</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkRadioButton" id="InitFull">
+                                    <property name="label" translatable="yes">Full</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                    <property name="group">InitHalf</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                    <property name="top_attach">1</property>
+                                    <property name="bottom_attach">2</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkRadioButton" id="InitHalf">
+                                    <property name="label" translatable="yes">Half</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">2</property>
+                                    <property name="right_attach">3</property>
+                                    <property name="top_attach">1</property>
+                                    <property name="bottom_attach">2</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkRadioButton" id="InitFullPunct">
+                                    <property name="label" translatable="yes">Full</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="draw_indicator">True</property>
+                                    <property name="group">InitHalfPunct</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                    <property name="top_attach">2</property>
+                                    <property name="bottom_attach">3</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkRadioButton" id="InitHalfPunct">
+                                    <property name="label" translatable="yes">Half</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">2</property>
+                                    <property name="right_attach">3</property>
+                                    <property name="top_attach">2</property>
+                                    <property name="bottom_attach">3</property>
+                                  </packing>
+                                </child>
+                              </object>
+                            </child>
+                          </object>
+                        </child>
+                        <child type="label">
+                          <object class="GtkLabel" id="label7">
+                            <property name="visible">True</property>
+                            <property name="label" translatable="yes">&lt;b&gt;Initial state&lt;/b&gt;</property>
+                            <property name="use_markup">True</property>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkFrame" id="frame5">
+                        <property name="visible">True</property>
+                        <property name="label_xalign">0</property>
+                        <property name="shadow_type">none</property>
+                        <child>
+                          <object class="GtkAlignment" id="alignment8">
+                            <property name="visible">True</property>
+                            <property name="top_padding">6</property>
+                            <property name="left_padding">12</property>
+                            <child>
+                              <object class="GtkTable" id="table3">
+                                <property name="visible">True</property>
+                                <property name="n_rows">6</property>
+                                <property name="n_columns">2</property>
+                                <property name="column_spacing">6</property>
+                                <property name="row_spacing">6</property>
+                                <child>
+                                  <object class="GtkLabel" id="label16">
+                                    <property name="visible">True</property>
+                                    <property name="xalign">0</property>
+                                    <property name="label" translatable="yes">Number of candidates:</property>
+                                    <property name="use_markup">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="x_options">GTK_FILL</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkComboBox" id="LookupTablePageSize">
+                                    <property name="visible">True</property>
+                                    <property name="model">liststorePageSize</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="ShiftSelectCandidate">
+                                    <property name="label" translatable="yes">Press [Shift] key to select candidate</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="right_attach">2</property>
+                                    <property name="top_attach">1</property>
+                                    <property name="bottom_attach">2</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="MinusEqualPage">
+                                    <property name="label" translatable="yes">Press [-] [=] key to flip page</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="right_attach">2</property>
+                                    <property name="top_attach">2</property>
+                                    <property name="bottom_attach">3</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="CommaPeriodPage">
+                                    <property name="label" translatable="yes">Press [,] [.] key to flip page</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="right_attach">2</property>
+                                    <property name="top_attach">3</property>
+                                    <property name="bottom_attach">4</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="AutoCommit">
+                                    <property name="label" translatable="yes">Auto commit phrase</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="right_attach">2</property>
+                                    <property name="top_attach">4</property>
+                                    <property name="bottom_attach">5</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="label17">
+                                    <property name="visible">True</property>
+                                    <property name="xalign">0</property>
+                                    <property name="label" translatable="yes">Half width punctuations:</property>
+                                  </object>
+                                  <packing>
+                                    <property name="top_attach">5</property>
+                                    <property name="bottom_attach">6</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkEntry" id="HalfWidthPuncts">
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="invisible_char">&#x25CF;</property>
+                                    <property name="text" translatable="yes">+-*/=%</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                    <property name="top_attach">5</property>
+                                    <property name="bottom_attach">6</property>
+                                  </packing>
+                                </child>
+                              </object>
+                            </child>
+                          </object>
+                        </child>
+                        <child type="label">
+                          <object class="GtkLabel" id="label8">
+                            <property name="visible">True</property>
+                            <property name="label" translatable="yes">&lt;b&gt;Others&lt;/b&gt;</property>
+                            <property name="use_markup">True</property>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="label1">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">General</property>
+              </object>
+              <packing>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkAlignment" id="alignment3">
+                <property name="visible">True</property>
+                <property name="top_padding">12</property>
+                <property name="bottom_padding">12</property>
+                <property name="left_padding">12</property>
+                <property name="right_padding">12</property>
+                <child>
+                  <object class="GtkVBox" id="vbox2">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <property name="spacing">12</property>
+                    <child>
+                      <object class="GtkCheckButton" id="CorrectPinyin">
+                        <property name="label" translatable="yes">Correct pinyin</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="active">True</property>
+                        <property name="draw_indicator">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkFrame" id="frame2">
+                        <property name="visible">True</property>
+                        <property name="label_xalign">0</property>
+                        <property name="shadow_type">none</property>
+                        <child>
+                          <object class="GtkAlignment" id="alignment4">
+                            <property name="visible">True</property>
+                            <property name="top_padding">6</property>
+                            <property name="left_padding">12</property>
+                            <child>
+                              <object class="GtkVBox" id="vbox3">
+                                <property name="visible">True</property>
+                                <property name="orientation">vertical</property>
+                                <property name="spacing">6</property>
+                                <child>
+                                  <object class="GtkCheckButton" id="CorrectPinyin_GN_NG">
+                                    <property name="label">gn =&gt; ng</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="CorrectPinyin_MG_NG">
+                                    <property name="label">mg =&gt; ng</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="CorrectPinyin_IOU_IU">
+                                    <property name="label">iou =&gt; iu</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="position">2</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="CorrectPinyin_UEI_UI">
+                                    <property name="label">uei =&gt; ui</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="position">3</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="CorrectPinyin_UEN_UN">
+                                    <property name="label">uen =&gt; un</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="position">4</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="CorrectPinyin_VE_UE">
+                                    <property name="label">ve =&gt; ue</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="position">5</property>
+                                  </packing>
+                                </child>
+                              </object>
+                            </child>
+                          </object>
+                        </child>
+                        <child type="label">
+                          <object class="GtkLabel" id="label5">
+                            <property name="visible">True</property>
+                            <property name="label" translatable="yes">&lt;b&gt;Correct pinyin&lt;/b&gt;</property>
+                            <property name="use_markup">True</property>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="label2">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Correct pinyin</property>
+              </object>
+              <packing>
+                <property name="position">1</property>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkAlignment" id="alignment1">
+                <property name="visible">True</property>
+                <property name="top_padding">12</property>
+                <property name="bottom_padding">12</property>
+                <property name="left_padding">12</property>
+                <property name="right_padding">12</property>
+                <child>
+                  <object class="GtkVBox" id="vbox1">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <property name="spacing">12</property>
+                    <child>
+                      <object class="GtkCheckButton" id="FuzzyPinyin">
+                        <property name="label" translatable="yes">Fuzzy pinyin</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="draw_indicator">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkFrame" id="frame1">
+                        <property name="visible">True</property>
+                        <property name="label_xalign">0</property>
+                        <property name="shadow_type">none</property>
+                        <child>
+                          <object class="GtkAlignment" id="alignment2">
+                            <property name="visible">True</property>
+                            <property name="top_padding">6</property>
+                            <property name="left_padding">12</property>
+                            <child>
+                              <object class="GtkTable" id="table1">
+                                <property name="visible">True</property>
+                                <property name="n_rows">12</property>
+                                <property name="n_columns">2</property>
+                                <property name="column_spacing">6</property>
+                                <property name="row_spacing">6</property>
+                                <property name="homogeneous">True</property>
+                                <child>
+                                  <object class="GtkCheckButton" id="FuzzyPinyin_C_CH">
+                                    <property name="label">c =&gt; ch</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="FuzzyPinyin_Z_ZH">
+                                    <property name="label">z =&gt; zh</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="top_attach">1</property>
+                                    <property name="bottom_attach">2</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="FuzzyPinyin_S_SH">
+                                    <property name="label">s =&gt; sh</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="top_attach">2</property>
+                                    <property name="bottom_attach">3</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="FuzzyPinyin_L_N">
+                                    <property name="label">l =&gt; n</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="top_attach">3</property>
+                                    <property name="bottom_attach">4</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="FuzzyPinyin_F_H">
+                                    <property name="label">f =&gt; h</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="top_attach">4</property>
+                                    <property name="bottom_attach">5</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="FuzzyPinyin_L_R">
+                                    <property name="label">l =&gt; r</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="top_attach">5</property>
+                                    <property name="bottom_attach">6</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="FuzzyPinyin_K_G">
+                                    <property name="label">k =&gt; g</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="top_attach">6</property>
+                                    <property name="bottom_attach">7</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="FuzzyPinyin_AN_ANG">
+                                    <property name="label">an =&gt; ang</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="top_attach">7</property>
+                                    <property name="bottom_attach">8</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="FuzzyPinyin_EN_ENG">
+                                    <property name="label">en =&gt; eng</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="top_attach">8</property>
+                                    <property name="bottom_attach">9</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="FuzzyPinyin_IN_ING">
+                                    <property name="label">in =&gt; ing</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="top_attach">9</property>
+                                    <property name="bottom_attach">10</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="FuzzyPinyin_CH_C">
+                                    <property name="label">ch =&gt; c</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="FuzzyPinyin_ZH_Z">
+                                    <property name="label">zh =&gt; z</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                    <property name="top_attach">1</property>
+                                    <property name="bottom_attach">2</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="FuzzyPinyin_SH_S">
+                                    <property name="label">sh =&gt; s</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                    <property name="top_attach">2</property>
+                                    <property name="bottom_attach">3</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="FuzzyPinyin_N_L">
+                                    <property name="label">n =&gt; l</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                    <property name="top_attach">3</property>
+                                    <property name="bottom_attach">4</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="FuzzyPinyin_H_F">
+                                    <property name="label">h =&gt; f</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                    <property name="top_attach">4</property>
+                                    <property name="bottom_attach">5</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="FuzzyPinyin_R_L">
+                                    <property name="label">r =&gt; l</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                    <property name="top_attach">5</property>
+                                    <property name="bottom_attach">6</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="FuzzyPinyin_G_K">
+                                    <property name="label">g =&gt; k</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                    <property name="top_attach">6</property>
+                                    <property name="bottom_attach">7</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="FuzzyPinyin_ANG_AN">
+                                    <property name="label">ang =&gt; an</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                    <property name="top_attach">7</property>
+                                    <property name="bottom_attach">8</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="FuzzyPinyin_ENG_EN">
+                                    <property name="label">eng =&gt; en</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                    <property name="top_attach">8</property>
+                                    <property name="bottom_attach">9</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="FuzzyPinyin_ING_IN">
+                                    <property name="label">ing =&gt; in</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                    <property name="top_attach">9</property>
+                                    <property name="bottom_attach">10</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="FuzzyPinyin_UAN_UANG">
+                                    <property name="label">uan =&gt; uang</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="top_attach">11</property>
+                                    <property name="bottom_attach">12</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="FuzzyPinyin_UANG_UAN">
+                                    <property name="label">uang =&gt; uan</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                    <property name="top_attach">11</property>
+                                    <property name="bottom_attach">12</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="FuzzyPinyin_IAN_IANG">
+                                    <property name="label">ian =&gt; iang</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="top_attach">10</property>
+                                    <property name="bottom_attach">11</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="FuzzyPinyin_IANG_IAN">
+                                    <property name="label">iang =&gt; ian</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                    <property name="top_attach">10</property>
+                                    <property name="bottom_attach">11</property>
+                                  </packing>
+                                </child>
+                              </object>
+                            </child>
+                          </object>
+                        </child>
+                        <child type="label">
+                          <object class="GtkLabel" id="label4">
+                            <property name="visible">True</property>
+                            <property name="label" translatable="yes">&lt;b&gt;Fuzzy pinyin&lt;/b&gt;</property>
+                            <property name="use_markup">True</property>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="label3">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Fuzzy pinyin</property>
+              </object>
+              <packing>
+                <property name="position">2</property>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkAlignment" id="alignment9">
+                <property name="visible">True</property>
+                <property name="yscale">0.30000001192092896</property>
+                <property name="top_padding">12</property>
+                <property name="bottom_padding">12</property>
+                <property name="left_padding">12</property>
+                <property name="right_padding">12</property>
+                <child>
+                  <object class="GtkVBox" id="vbox6">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <child>
+                      <object class="GtkVBox" id="vbox7">
+                        <property name="visible">True</property>
+                        <property name="orientation">vertical</property>
+                        <property name="spacing">6</property>
+                        <child>
+                          <object class="GtkImage" id="image1">
+                            <property name="visible">True</property>
+                            <property name="pixel_size">48</property>
+                            <property name="icon_name">gtk-about</property>
+                          </object>
+                          <packing>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="label13">
+                            <property name="visible">True</property>
+                            <property name="label" translatable="yes">&lt;big&gt;&lt;b&gt;IBus Pinyin 1.3.0&lt;/b&gt;&lt;/big&gt;</property>
+                            <property name="use_markup">True</property>
+                            <property name="selectable">True</property>
+                          </object>
+                          <packing>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="label14">
+                            <property name="visible">True</property>
+                            <property name="label" translatable="yes">Pinyin input method for IBus</property>
+                            <property name="selectable">True</property>
+                          </object>
+                          <packing>
+                            <property name="position">2</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="label15">
+                            <property name="visible">True</property>
+                            <property name="label" translatable="yes">&lt;small&gt;Copyright (c) 2009 Huang Peng &amp;lt;shawn.p.huang@gmail.com&amp;gt;&lt;/small&gt;</property>
+                            <property name="use_markup">True</property>
+                            <property name="selectable">True</property>
+                          </object>
+                          <packing>
+                            <property name="position">3</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkLinkButton" id="linkbutton1">
+                            <property name="label" translatable="yes">http://ibus.googlecode.com</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">True</property>
+                            <property name="has_tooltip">True</property>
+                            <property name="relief">none</property>
+                            <property name="uri">http://ibus.googlecode.com</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">4</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="position">3</property>
+              </packing>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="label12">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">About</property>
+              </object>
+              <packing>
+                <property name="position">3</property>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="buttonClose">
+                <property name="label">gtk-close</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="0">buttonClose</action-widget>
+    </action-widgets>
+  </object>
+  <object class="GtkListStore" id="liststoreDoublePinyin">
+    <columns>
+      <!-- column-name schema -->
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes">MSPY</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">ZRM</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">ABC</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">ZGPY</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">PYJJ</col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkListStore" id="liststorePageSize">
+    <columns>
+      <!-- column-name pageSize -->
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes">1</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">2</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">3</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">4</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">5</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">6</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">7</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">8</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">9</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">10</col>
+      </row>
+    </data>
+  </object>
+</interface>
index a7eb522..27c700c 100644 (file)
@@ -25,5 +25,6 @@ datarootdir=@datarootdir@
 export IBUS_PREFIX=@prefix@
 export IBUS_DATAROOTDIR=@datarootdir@
 export IBUS_LOCALEDIR=@localedir@
-exec python @prefix@/share/ibus-pinyin/setup/main.py $@
+cd @prefix@/share/ibus-pinyin/setup/
+exec python main.py $@
 
index 7f17f83..6396117 100644 (file)
-# vim:set et sts=4 sw=4:
-#
-# ibus-pinyin - The PinYin engine for IBus
-#
-# Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-import sys
-from os import path
-import os
-import signal
-import gobject
 import gtk
-import gtk.gdk as gdk
-import gtk.glade as glade
 import ibus
-import gettext
 import locale
-from pydict import SHUANGPIN_SCHEMAS
-
-from gettext import dgettext
-_ = lambda a : dgettext("ibus-pinyin", a)
-
-RGB_COLOR = lambda c : ((c.red & 0xff00) << 8) + (c.green & 0xff00) + ((c.blue & 0xff00) >> 8)
-GDK_COLOR = lambda c : gdk.Color(((c >> 16) & 0xff) * 256, ((c >> 8) & 0xff) * 256, (c & 0xff) * 256)
-RGB = lambda r, g, b : ((r & 0xff) << 16) + ((g & 0xff) << 8) + (b & 0xff)
+import os
+import gettext
 
+class PreferencesDialog:
+    def __init__(self):
+        locale.setlocale(locale.LC_ALL, "")
+        localedir = os.getenv("IBUS_LOCALEDIR")
+        gettext.bindtextdomain("ibus-pinyin", localedir)
+        gettext.bind_textdomain_codeset("ibus-pinyin", "UTF-8")
 
-class SetupUI ():
-    def __init__ (self):
-        self.__need_reload_config = False
         self.__bus = ibus.Bus()
         self.__config = self.__bus.get_config()
-
-        self.__options = {
-            "SupportGBK" :      [False, self.__checkbutton_op],
-            "ShuangPin" :       [False, self.__checkbutton_op],
-            "AutoCorrect" :     [True, self.__checkbutton_op],
-
-            "FuzzyPinYin" :     [False, self.__checkbutton_op],
-            "FuzzyS_Sh" :       [False, self.__checkbutton_op],
-            "FuzzyC_Ch" :       [False, self.__checkbutton_op],
-            "FuzzyZ_Zh" :       [False, self.__checkbutton_op],
-            "FuzzyL_N" :        [False, self.__checkbutton_op],
-            "FuzzyIn_Ing" :     [False, self.__checkbutton_op],
-            "FuzzyEn_Eng" :     [False, self.__checkbutton_op],
-            "FuzzyAn_Ang" :     [False, self.__checkbutton_op],
-
-            "SpellCheck" :      [True, self.__checkbutton_op],
-            "UVToTemp" :        [True, self.__checkbutton_op],
-            "ShiftSelectCandidates" :
-                                [True, self.__checkbutton_op],
-
-            "CommaPageDownUp" : [True, self.__checkbutton_op],
-            "EqualPageDownUp" : [True, self.__checkbutton_op],
-            "AutoCommit" :      [False, self.__checkbutton_op],
-
-            "PhraseColor" :     [RGB (0, 0, 0), self.__colorbutton_op],
-            "NewPhraseColor" :  [RGB (0xef, 0, 0), self.__colorbutton_op],
-            "UserPhraseColor" : [RGB (0, 0, 0xbf), self.__colorbutton_op],
-            "SpecialPhraseColor" :
-                                [RGB (0, 0xbf, 0), self.__colorbutton_op],
-            "EnglishPhraseColor" :
-                                [RGB (0, 0xbf, 0), self.__colorbutton_op],
-            "ErrorEnglishPhraseColor" :
-                                [RGB (0xef, 0, 0), self.__colorbutton_op],
-            "PageSize" :        [5, self.__combobox_op, range(1, 10)],
-            "ShuangPinSchema" : ["MSPY", self.__combobox_op, SHUANGPIN_SCHEMAS.keys()],
-            "HalfPunctuations" : ["+-*/=%", self.__entry_op],
-        }
+        self.__builder = gtk.Builder()
+        self.__builder.set_translation_domain("ibus-pinyin")
+        self.__builder.add_from_file("ibus-pinyin-preferences.glade")
+        self.__dialog = self.__builder.get_object("dialog")
+
+        self.__init_pinyin()
+        self.__init_init_state()
+        self.__init_others()
+        self.__init_correct_pinyin()
+        self.__init_fuzzy_pinyin()
+
+    def __init_pinyin(self):
+        # pinyin
+        self.__full_pinyin = self.__builder.get_object("FullPinyin")
+        self.__simple_pinyin = self.__builder.get_object("SimplePinyin")
+        self.__double_pinyin = self.__builder.get_object("DoublePinyin")
+        self.__double_pinyin_schema = self.__builder.get_object("DoublePinyinSchema")
+        self.__double_pinyin_schema_label = self.__builder.get_object("labelDoublePinyinSchema")
+
+        renderer = gtk.CellRendererText()
+        self.__double_pinyin_schema.pack_start(renderer)
+        self.__double_pinyin_schema.set_attributes(renderer, text=0)
+
+        # read value
+        self.__simple_pinyin.set_active(self.__get_value("SimplePinyin", True))
+        self.__full_pinyin.set_active(not self.__get_value("DoublePinyin", False))
+        self.__double_pinyin_schema.set_active(self.__get_value("DoublePinyinSchema", 0))
+        if self.__full_pinyin.get_active():
+            self.__simple_pinyin.set_sensitive(True)
+            self.__double_pinyin_schema.set_sensitive(False)
+            self.__double_pinyin_schema_label.set_sensitive(False)
+        else:
+            self.__simple_pinyin.set_sensitive(False)
+            self.__double_pinyin_schema.set_sensitive(True)
+            self.__double_pinyin_schema_label.set_sensitive(True)
+
+        def __full_pinyin_toggled_cb(widget):
+            val = widget.get_active()
+            self.__set_value("DoublePinyin", not val)
+            self.__simple_pinyin.set_sensitive(val)
+
+        def __double_pinyin_toggled_cb(widget):
+            val = widget.get_active()
+            self.__set_value("DoublePinyin", val)
+            self.__double_pinyin_schema.set_sensitive(val)
+            self.__double_pinyin_schema_label.set_sensitive(val)
+
+        def __double_pinyin_schema_changed_cb(widget):
+            self.__set_value("DoublePinyinSchema", widget.get_active())
+
+        # connect signals
+        self.__full_pinyin.connect("toggled", __full_pinyin_toggled_cb)
+        self.__double_pinyin.connect("toggled", __double_pinyin_toggled_cb)
+        self.__simple_pinyin.connect("toggled", self.__toggled_cb, "SimplePinyin")
+        self.__double_pinyin_schema.connect("changed", __double_pinyin_schema_changed_cb)
+
+    def __init_init_state(self):
+        # init state
+        self.__init_chinese = self.__builder.get_object("InitChinese")
+        self.__init_english = self.__builder.get_object("InitEnglish")
+        self.__init_full = self.__builder.get_object("InitFull")
+        self.__init_half = self.__builder.get_object("InitHalf")
+        self.__init_full_punct = self.__builder.get_object("InitFullPunct")
+        self.__init_half_punct = self.__builder.get_object("InitHalfPunct")
+
+        # read values
+        self.__init_chinese.set_active(self.__get_value("InitChinese", True))
+        self.__init_full.set_active(self.__get_value("InitFull", False))
+        self.__init_full_punct.set_active(self.__get_value("InitFullPunct", True))
+
+        # connect signals
+        self.__init_chinese.connect("toggled", self.__toggled_cb, "InitChinese")
+        self.__init_full.connect("toggled", self.__toggled_cb, "InitFull")
+        self.__init_full_punct.connect("toggled", self.__toggled_cb, "InitFullPunct")
+
+    def __init_others(self):
+        #others
+        self.__lookup_table_page_size = self.__builder.get_object("LookupTablePageSize")
+        renderer = gtk.CellRendererText()
+        self.__lookup_table_page_size.pack_start(renderer)
+        self.__lookup_table_page_size.set_attributes(renderer, text=0)
+
+        self.__shift_select_candidate = self.__builder.get_object("ShiftSelectCandidate")
+        self.__minus_equal_page = self.__builder.get_object("MinusEqualPage")
+        self.__comma_period_page = self.__builder.get_object("CommaPeriodPage")
+        self.__auto_commit = self.__builder.get_object("AutoCommit")
+        self.__half_width_puncts = self.__builder.get_object("HalfWidthPuncts")
+
+        # read values
+        self.__lookup_table_page_size.set_active(self.__get_value("LookupTablePageSize", 5) - 1)
+        self.__shift_select_candidate.set_active(self.__get_value("ShiftSelectCandidate", False))
+        self.__minus_equal_page.set_active(self.__get_value("MinusEqualPage", True))
+        self.__comma_period_page.set_active(self.__get_value("CommaPeriodPage", True))
+        self.__half_width_puncts.set_text(self.__get_value("HalfWidthPuncts", "+-*/=%"))
+
+        # connect signals
+        def __lookup_table_page_size_changed_cb(widget):
+            self.__set_value("LookupTablePageSize", widget.get_active() + 1)
+
+        self.__shift_select_candidate.connect("toggled", self.__toggled_cb, "ShiftSelectCandidate")
+        self.__minus_equal_page.connect("toggled", self.__toggled_cb, "MinusEqualPage")
+        self.__comma_period_page.connect("toggled", self.__toggled_cb, "CommaPeriodPage")
+        self.__lookup_table_page_size.connect("changed", __lookup_table_page_size_changed_cb)
+
+        def __entry_activate_cb(widget, name):
+            text = widget.get_text()
+            self.__set_value(name, text)
+        self.__half_width_puncts.connect("activate", __entry_activate_cb, "HalfWidthPuncts")
+
+    def __init_correct_pinyin(self):
+        # auto correct
+        self.__correct_pinyin = self.__builder.get_object("CorrectPinyin")
+        self.__correct_pinyin_widgets = [
+            ("CorrectPinyin_GN_NG", True),
+            ("CorrectPinyin_MG_NG", True),
+            ("CorrectPinyin_IOU_IU", True),
+            ("CorrectPinyin_UEI_UI", True),
+            ("CorrectPinyin_UEN_UN", True),
+            ("CorrectPinyin_VE_UE", True),
+        ]
+
+        def __correct_pinyin_toggled_cb(widget):
+            val = widget.get_active()
+            map(lambda w: self.__builder.get_object(w[0]).set_sensitive(val),
+                self.__correct_pinyin_widgets)
+        self.__correct_pinyin.connect("toggled", __correct_pinyin_toggled_cb)
+
+        # init value
+        self.__correct_pinyin.set_active(self.__get_value("CorrectPinyin", True))
+        for name, defval in self.__correct_pinyin_widgets:
+            widget = self.__builder.get_object(name)
+            widget.set_active(self.__get_value(name, defval))
+
+        self.__correct_pinyin.connect("toggled", self.__toggled_cb, "CorrectPinyin")
+        for name, defval in self.__correct_pinyin_widgets:
+            widget = self.__builder.get_object(name)
+            widget.connect("toggled", self.__toggled_cb, name)
+
+    def __init_fuzzy_pinyin(self):
+        # fuzzy pinyin
+        self.__fuzzy_pinyin = self.__builder.get_object("FuzzyPinyin")
+        self.__fuzzy_pinyin_widgets = [
+            ("FuzzyPinyin_C_CH", True),
+            ("FuzzyPinyin_Z_ZH", True),
+            ("FuzzyPinyin_S_SH", True),
+            ("FuzzyPinyin_CH_C", False),
+            ("FuzzyPinyin_ZH_Z", False),
+            ("FuzzyPinyin_SH_S", False),
+            ("FuzzyPinyin_L_N", True),
+            ("FuzzyPinyin_F_H", True),
+            ("FuzzyPinyin_L_R", False),
+            ("FuzzyPinyin_K_G", True),
+            ("FuzzyPinyin_N_L", False),
+            ("FuzzyPinyin_H_F", False),
+            ("FuzzyPinyin_R_L", False),
+            ("FuzzyPinyin_G_K", False),
+            ("FuzzyPinyin_AN_ANG", True),
+            ("FuzzyPinyin_EN_ENG", True),
+            ("FuzzyPinyin_IN_ING", True),
+            ("FuzzyPinyin_ANG_AN", True),
+            ("FuzzyPinyin_ENG_EN", True),
+            ("FuzzyPinyin_ING_IN", True),
+            ("FuzzyPinyin_IAN_IANG", False),
+            ("FuzzyPinyin_UAN_UANG", False),
+            ("FuzzyPinyin_IANG_IAN", False),
+            ("FuzzyPinyin_UANG_UAN", False),
+        ]
+
+        def __fuzzy_pinyin_toggled_cb(widget):
+            val = widget.get_active()
+            map(lambda w: self.__builder.get_object(w[0]).set_sensitive(val),
+                self.__fuzzy_pinyin_widgets)
+        self.__fuzzy_pinyin.connect("toggled", __fuzzy_pinyin_toggled_cb)
+
+        # init value
+        self.__fuzzy_pinyin.set_active(self.__get_value("FuzzyPinyin", False))
+        for name, defval in self.__fuzzy_pinyin_widgets:
+            widget = self.__builder.get_object(name)
+            widget.set_active(self.__get_value(name, defval))
+
+        self.__fuzzy_pinyin.connect("toggled", self.__toggled_cb, "FuzzyPinyin")
+        for name, defval in self.__fuzzy_pinyin_widgets:
+            widget = self.__builder.get_object(name)
+            widget.connect("toggled", self.__toggled_cb, name)
+
+    def __changed_cb(self, widget, name):
+        self.__set_value(name, widget.get_active())
+
+    def __toggled_cb(self, widget, name):
+        self.__set_value(name, widget.get_active ())
+
+    def __get_value(self, name, defval):
+        value = self.__config.get_value("engine/Pinyin", name, "test_default_value_9898")
+        if value != "test_default_value_9898":
+            return value
+        self.__set_value(name, defval)
+        return defval
+
+    def __set_value(self, name, val):
+        self.__config.set_value("engine/Pinyin", name, val)
 
     def run(self):
-        self.__init_ui()
-        self.__load_config()
-        signal.signal(signal.SIGUSR1, self.__sigusr1_cb)
-        gtk.main()
-
-    def __sigusr1_cb(self, *arg):
-        window = self.__xml.get_widget("window_main")
-        window.present()
-
-    def __entry_op(self, name, opt, info):
-        widget = self.__xml.get_widget(name)
-        if widget == None:
-            print >> sys.stderr, "Can not find widget %s" % name
-            return ""
-        if opt == "read":
-            info[0] = self.__read(name, info[0])
-            widget.set_text(info[0])
-            return True
-        if opt == "write":
-            info[0] = widget.get_text()
-            self.__write(name, info[0])
-            return True
-        if opt == "check":
-            return info[0] != widget.get_text()
-        return ""
-
-    def __combobox_op(self, name, opt, info):
-        widget = self.__xml.get_widget(name)
-        if widget == None:
-            print >> sys.stderr, "Can not find widget %s" % name
-            return False
-        if opt == "read":
-            info[0] = self.__read(name, info[0])
-            widget.set_active(info[2].index(info[0]))
-            return True
-        if opt == "write":
-            info[0] = info[2][widget.get_active()]
-            self.__write(name, info[0])
-            return True
-        if opt == "check":
-            return info[0] != info[2][widget.get_active()]
-
-        if opt == "init":
-            model = gtk.ListStore(str)
-            for v in info[2]:
-                model.append([_(str(v))])
-            widget.set_model(model)
-        return False
-
-    def __colorbutton_op(self, name, opt, info):
-        widget = self.__xml.get_widget(name)
-        if widget == None:
-            print >> sys.stderr, "Can not find widget %s" % name
-            return False
-        if opt == "read":
-            info[0] = self.__read(name, info[0])
-            widget.set_color(GDK_COLOR(info[0]))
-            return True
-        if opt == "write":
-            info[0] = RGB_COLOR (widget.get_color())
-            self.__write(name, info[0])
-            return True
-        if opt == "check":
-            return info[0] != RGB_COLOR(widget.get_color())
-        return False
-
-    def __checkbutton_op(self, name, opt, info):
-        widget = self.__xml.get_widget(name)
-        if widget == None:
-            print >> sys.stderr, "Can not find widget %s" % name
-            return False
-
-        if opt == "read":
-            info[0] = self.__read(name, info[0])
-            widget.set_active(info[0])
-            return True
-        if opt == "write":
-            info[0] = widget.get_active()
-            self.__write(name, info[0])
-            return True
-        if opt == "check":
-            return info[0] != widget.get_active()
-        return False
-
-    def __read(self, name, v):
-        return self.__config.get_value("engine/PinYin", name, v)
-
-    def __write(self, name, v):
-        return self.__config.set_value("engine/PinYin", name, v)
-
-    def __init_ui(self):
-
-        locale.setlocale(locale.LC_ALL, "")
-        localedir = os.getenv("IBUS_LOCALEDIR")
+        return self.__dialog.run()
 
-        gettext.bindtextdomain("ibus-pinyin", localedir)
-        gettext.bind_textdomain_codeset("ibus-pinyin", "UTF-8")
-        glade.bindtextdomain("ibus-pinyin", localedir)
-        glade.textdomain("ibus-pinyin")
-
-        glade_file = path.join(path.dirname(__file__), "setup.glade")
-        self.__xml = glade.XML (glade_file)
-        self.__window = self.__xml.get_widget("window_main")
-        for name, info in self.__options.items():
-            info[1] (name, "init", info)
-            info[1] (name, "read", info)
-        self.__xml.signal_autoconnect(self)
-        self.__window.show_all()
-
-    def __load_config(self):
-        for name, info in self.__options.items():
-            info[1] (name, "read", info)
-
-    def __save_config(self):
-        self.__need_reload_config = True
-        for name, info in self.__options.items():
-            info[1] (name, "write", info)
-
-    def __query_changed(self):
-        for name, info in self.__options.items():
-            if info[1] (name, "check", info):
-                return True
-        return False
-
-    def __quit(self, need_confirm ):
-        if need_confirm == False:
-            gtk.main_quit()
-            return True
-        else:
-            dlg = gtk.MessageDialog(self.__window, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION,
-                        gtk.BUTTONS_YES_NO, _("Are you sure to close Python PinYin Setup without save configure?"))
-            id = dlg.run()
-            dlg.destroy()
-            if id == gtk.RESPONSE_YES:
-                gtk.main_quit()
-                return True
-        return False
-
-    def __optimize_user_db(self):
-        import sqlite3
-        dlg = gtk.MessageDialog(self.__window, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO,
-                        gtk.BUTTONS_OK, _("The user phrases database will be reorganized! Please don't use python PinYin now."))
-        dlg.run()
-        dlg.destroy()
-
-        try:
-            db = sqlite3.connect(path.expanduser("~/.ibus/pinyin/user.db"))
-            sqlstring = """
-                BEGIN TRANSACTION;
-                CREATE TABLE tmp AS SELECT * FROM py_phrase;
-                DELETE FROM py_phrase;
-                INSERT INTO py_phrase SELECT * FROM tmp ORDER BY ylen, y0, y1, y2, y3, yx, phrase;
-                DROP TABLE tmp;
-                COMMIT;
-            """
-            db.executescript(sqlstring)
-            db.executescript("VACUUM;")
-        except:
-            import traceback
-            traceback.print_exc()
-
-        dlg.destroy()
-        dlg = gtk.MessageDialog(self.__window, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO,
-                                gtk.BUTTONS_OK, _("Reorganizing is over!"))
-        dlg.run()
-        dlg.destroy()
-
-    # events handlers
-    def on_window_main_delete_event(self, widget, event):
-        changed = self.__query_changed()
-        self.__quit(changed)
-
-    def on_button_ok_clicked(self, button):
-        changed = self.__query_changed()
-        if changed:
-            self.__save_config()
-        self.__quit(False)
-
-    def on_button_apply_clicked(self, button):
-        self.__save_config()
-
-    def on_button_cancel_clicked(self, button):
-        changed = self.__query_changed()
-        self.__quit(changed)
-
-    def on_button_optimize_db_clicked(self, button):
-        self.__optimize_user_db()
-
-    def on_value_changed(self, widget, data = None):
-        if self.__query_changed():
-            self.__xml.get_widget("button_apply").set_sensitive(True)
-        else:
-            self.__xml.get_widget("button_apply").set_sensitive(False)
+def main():
+    PreferencesDialog().run()
 
 
 if __name__ == "__main__":
-    ui = SetupUI()
-    ui.run()
-
+    main()
diff --git a/setup/pydict.py b/setup/pydict.py
deleted file mode 120000 (symlink)
index b106fef..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../engine/pydict.py
\ No newline at end of file
diff --git a/setup/setup.glade b/setup/setup.glade
deleted file mode 100644 (file)
index ad16a12..0000000
+++ /dev/null
@@ -1,958 +0,0 @@
-<?xml version="1.0"?>
-<glade-interface>
-  <!-- interface-requires gtk+ 2.16 -->
-  <!-- interface-naming-policy toplevel-contextual -->
-  <widget class="GtkWindow" id="window_main">
-    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-    <property name="title" translatable="yes">Python PinYin Setup</property>
-    <property name="window_position">center</property>
-    <child>
-      <widget class="GtkVBox" id="vbox1">
-        <property name="visible">True</property>
-        <child>
-          <widget class="GtkNotebook" id="notebook">
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="scrollable">True</property>
-            <child>
-              <widget class="GtkTable" id="table1">
-                <property name="visible">True</property>
-                <property name="n_rows">12</property>
-                <property name="n_columns">2</property>
-                <property name="column_spacing">4</property>
-                <property name="row_spacing">2</property>
-                <property name="homogeneous">True</property>
-                <child>
-                  <widget class="GtkEntry" id="HalfPunctuations">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="invisible_char">&#x25CF;</property>
-                    <signal name="changed" handler="on_value_changed"/>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">2</property>
-                    <property name="top_attach">11</property>
-                    <property name="bottom_attach">12</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="label12">
-                    <property name="visible">True</property>
-                    <property name="xalign">0.89999997615814209</property>
-                    <property name="label" translatable="yes">Half punctuations</property>
-                  </widget>
-                  <packing>
-                    <property name="top_attach">11</property>
-                    <property name="bottom_attach">12</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="label21">
-                    <property name="visible">True</property>
-                    <property name="xalign">0.89999997615814209</property>
-                    <property name="label" translatable="yes">Press [u] or [v]  to temporary English mode</property>
-                  </widget>
-                  <packing>
-                    <property name="top_attach">6</property>
-                    <property name="bottom_attach">7</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkCheckButton" id="UVToTemp">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="draw_indicator">True</property>
-                    <signal name="toggled" handler="on_value_changed"/>
-                    <child>
-                      <placeholder/>
-                    </child>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">2</property>
-                    <property name="top_attach">6</property>
-                    <property name="bottom_attach">7</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkCheckButton" id="SpellCheck">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="draw_indicator">True</property>
-                    <signal name="toggled" handler="on_value_changed"/>
-                    <child>
-                      <placeholder/>
-                    </child>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">2</property>
-                    <property name="top_attach">5</property>
-                    <property name="bottom_attach">6</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkCheckButton" id="AutoCorrect">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="draw_indicator">True</property>
-                    <signal name="toggled" handler="on_value_changed"/>
-                    <child>
-                      <placeholder/>
-                    </child>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">2</property>
-                    <property name="top_attach">4</property>
-                    <property name="bottom_attach">5</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkComboBox" id="PageSize">
-                    <property name="visible">True</property>
-                    <property name="items" translatable="yes">1
-</property>
-                    <signal name="changed" handler="on_value_changed"/>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">2</property>
-                    <property name="top_attach">3</property>
-                    <property name="bottom_attach">4</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkComboBox" id="ShuangPinSchema">
-                    <property name="visible">True</property>
-                    <property name="items" translatable="yes">1
-</property>
-                    <signal name="changed" handler="on_value_changed"/>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">2</property>
-                    <property name="top_attach">2</property>
-                    <property name="bottom_attach">3</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="label14">
-                    <property name="visible">True</property>
-                    <property name="xalign">0.89999997615814209</property>
-                    <property name="label" translatable="yes">English spelling check</property>
-                  </widget>
-                  <packing>
-                    <property name="top_attach">5</property>
-                    <property name="bottom_attach">6</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="label13">
-                    <property name="visible">True</property>
-                    <property name="xalign">0.89999997615814209</property>
-                    <property name="label" translatable="yes">Wrong PinYin auto correct</property>
-                  </widget>
-                  <packing>
-                    <property name="top_attach">4</property>
-                    <property name="bottom_attach">5</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="label11">
-                    <property name="visible">True</property>
-                    <property name="xalign">0.89999997615814209</property>
-                    <property name="label" translatable="yes">Lookup table page size</property>
-                  </widget>
-                  <packing>
-                    <property name="top_attach">3</property>
-                    <property name="bottom_attach">4</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="label10">
-                    <property name="visible">True</property>
-                    <property name="xalign">0.89999997615814209</property>
-                    <property name="label" translatable="yes">ShuangPin Schema</property>
-                  </widget>
-                  <packing>
-                    <property name="top_attach">2</property>
-                    <property name="bottom_attach">3</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="label16">
-                    <property name="visible">True</property>
-                    <property name="xalign">0.89999997615814209</property>
-                    <property name="label" translatable="yes">ShuangPin</property>
-                  </widget>
-                  <packing>
-                    <property name="top_attach">1</property>
-                    <property name="bottom_attach">2</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="label17">
-                    <property name="visible">True</property>
-                    <property name="xalign">0.89999997615814209</property>
-                    <property name="label" translatable="yes">Support GBK</property>
-                  </widget>
-                </child>
-                <child>
-                  <widget class="GtkCheckButton" id="ShuangPin">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="draw_indicator">True</property>
-                    <signal name="toggled" handler="on_value_changed"/>
-                    <child>
-                      <placeholder/>
-                    </child>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">2</property>
-                    <property name="top_attach">1</property>
-                    <property name="bottom_attach">2</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkCheckButton" id="SupportGBK">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="draw_indicator">True</property>
-                    <signal name="toggled" handler="on_value_changed"/>
-                    <child>
-                      <placeholder/>
-                    </child>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">2</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="label20">
-                    <property name="visible">True</property>
-                    <property name="xalign">0.89999997615814209</property>
-                    <property name="label" translatable="yes">Press [shift] to select candidates</property>
-                  </widget>
-                  <packing>
-                    <property name="top_attach">7</property>
-                    <property name="bottom_attach">8</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkCheckButton" id="ShiftSelectCandidates">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="draw_indicator">True</property>
-                    <child>
-                      <placeholder/>
-                    </child>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">2</property>
-                    <property name="top_attach">7</property>
-                    <property name="bottom_attach">8</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="label22">
-                    <property name="visible">True</property>
-                    <property name="xalign">0.89999997615814209</property>
-                    <property name="label" translatable="yes">Press [-] [=] to page down up.</property>
-                  </widget>
-                  <packing>
-                    <property name="top_attach">8</property>
-                    <property name="bottom_attach">9</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkCheckButton" id="EqualPageDownUp">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="draw_indicator">True</property>
-                    <child>
-                      <placeholder/>
-                    </child>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">2</property>
-                    <property name="top_attach">8</property>
-                    <property name="bottom_attach">9</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkCheckButton" id="CommaPageDownUp">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="draw_indicator">True</property>
-                    <child>
-                      <placeholder/>
-                    </child>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">2</property>
-                    <property name="top_attach">9</property>
-                    <property name="bottom_attach">10</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkCheckButton" id="AutoCommit">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="draw_indicator">True</property>
-                    <child>
-                      <placeholder/>
-                    </child>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">2</property>
-                    <property name="top_attach">10</property>
-                    <property name="bottom_attach">11</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="label23">
-                    <property name="visible">True</property>
-                    <property name="xalign">0.89999997615814209</property>
-                    <property name="label" translatable="yes">Auto commit</property>
-                  </widget>
-                  <packing>
-                    <property name="top_attach">10</property>
-                    <property name="bottom_attach">11</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="label24">
-                    <property name="visible">True</property>
-                    <property name="xalign">0.89999997615814209</property>
-                    <property name="label" translatable="yes">Press [,] [.] to page down up.</property>
-                  </widget>
-                  <packing>
-                    <property name="top_attach">9</property>
-                    <property name="bottom_attach">10</property>
-                  </packing>
-                </child>
-              </widget>
-            </child>
-            <child>
-              <widget class="GtkLabel" id="label1">
-                <property name="visible">True</property>
-                <property name="label" translatable="yes">General</property>
-              </widget>
-              <packing>
-                <property name="tab_fill">False</property>
-                <property name="type">tab</property>
-              </packing>
-            </child>
-            <child>
-              <widget class="GtkTable" id="table4">
-                <property name="no_show_all">True</property>
-                <property name="n_rows">12</property>
-                <property name="n_columns">2</property>
-                <property name="column_spacing">2</property>
-                <property name="row_spacing">2</property>
-                <property name="homogeneous">True</property>
-                <child>
-                  <widget class="GtkCheckButton" id="FuzzyPinYin">
-                    <property name="label" translatable="yes">Enable Fuzzy PinYin</property>
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="use_underline">True</property>
-                    <property name="draw_indicator">True</property>
-                  </widget>
-                </child>
-                <child>
-                  <widget class="GtkCheckButton" id="FuzzyS_Sh">
-                    <property name="label" translatable="yes">s &lt;=&gt; sh</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="use_underline">True</property>
-                    <property name="draw_indicator">True</property>
-                  </widget>
-                  <packing>
-                    <property name="top_attach">1</property>
-                    <property name="bottom_attach">2</property>
-                    <property name="x_options"></property>
-                    <property name="y_options"></property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkCheckButton" id="FuzzyC_Ch">
-                    <property name="label" translatable="yes">c &lt;=&gt; ch</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="use_underline">True</property>
-                    <property name="draw_indicator">True</property>
-                  </widget>
-                  <packing>
-                    <property name="top_attach">2</property>
-                    <property name="bottom_attach">3</property>
-                    <property name="x_options"></property>
-                    <property name="y_options"></property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkCheckButton" id="FuzzyZ_Zh">
-                    <property name="label" translatable="yes">z &lt;=&gt; zh</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="use_underline">True</property>
-                    <property name="draw_indicator">True</property>
-                  </widget>
-                  <packing>
-                    <property name="top_attach">3</property>
-                    <property name="bottom_attach">4</property>
-                    <property name="x_options"></property>
-                    <property name="y_options"></property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkCheckButton" id="FuzzyL_N">
-                    <property name="label" translatable="yes">l &lt;=&gt; n</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="use_underline">True</property>
-                    <property name="draw_indicator">True</property>
-                  </widget>
-                  <packing>
-                    <property name="top_attach">4</property>
-                    <property name="bottom_attach">5</property>
-                    <property name="x_options"></property>
-                    <property name="y_options"></property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkCheckButton" id="FuzzyIn_Ing">
-                    <property name="label" translatable="yes">in &lt;=&gt; ing</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="use_underline">True</property>
-                    <property name="draw_indicator">True</property>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">2</property>
-                    <property name="top_attach">1</property>
-                    <property name="bottom_attach">2</property>
-                    <property name="x_options"></property>
-                    <property name="y_options"></property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkCheckButton" id="FuzzyEn_Eng">
-                    <property name="label" translatable="yes">en &lt;=&gt; eng</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="use_underline">True</property>
-                    <property name="draw_indicator">True</property>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">2</property>
-                    <property name="top_attach">2</property>
-                    <property name="bottom_attach">3</property>
-                    <property name="x_options"></property>
-                    <property name="y_options"></property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkCheckButton" id="FuzzyAn_Ang">
-                    <property name="label" translatable="yes">an &lt;=&gt; ang</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="use_underline">True</property>
-                    <property name="draw_indicator">True</property>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">2</property>
-                    <property name="top_attach">3</property>
-                    <property name="bottom_attach">4</property>
-                    <property name="x_options"></property>
-                    <property name="y_options"></property>
-                  </packing>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-              </widget>
-              <packing>
-                <property name="position">1</property>
-              </packing>
-            </child>
-            <child>
-              <widget class="GtkLabel" id="Fuzzytab">
-                <property name="label" translatable="yes">Fuzzy PinYin</property>
-              </widget>
-              <packing>
-                <property name="position">1</property>
-                <property name="tab_fill">False</property>
-                <property name="type">tab</property>
-              </packing>
-            </child>
-            <child>
-              <widget class="GtkTable" id="table2">
-                <property name="visible">True</property>
-                <property name="n_rows">11</property>
-                <property name="n_columns">2</property>
-                <property name="column_spacing">2</property>
-                <property name="row_spacing">2</property>
-                <property name="homogeneous">True</property>
-                <child>
-                  <widget class="GtkLabel" id="label9">
-                    <property name="visible">True</property>
-                    <property name="xalign">0.89999997615814209</property>
-                    <property name="label" translatable="yes">Color of Spelling Error</property>
-                  </widget>
-                  <packing>
-                    <property name="top_attach">5</property>
-                    <property name="bottom_attach">6</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="label8">
-                    <property name="visible">True</property>
-                    <property name="xalign">0.89999997615814209</property>
-                    <property name="label" translatable="yes">Color of English Candidates</property>
-                  </widget>
-                  <packing>
-                    <property name="top_attach">4</property>
-                    <property name="bottom_attach">5</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="label7">
-                    <property name="visible">True</property>
-                    <property name="xalign">0.89999997615814209</property>
-                    <property name="label" translatable="yes">Color of Special Phrases</property>
-                  </widget>
-                  <packing>
-                    <property name="top_attach">3</property>
-                    <property name="bottom_attach">4</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="label6">
-                    <property name="visible">True</property>
-                    <property name="xalign">0.89999997615814209</property>
-                    <property name="label" translatable="yes">Color of User Phrases</property>
-                  </widget>
-                  <packing>
-                    <property name="top_attach">2</property>
-                    <property name="bottom_attach">3</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="label5">
-                    <property name="visible">True</property>
-                    <property name="xalign">0.89999997615814209</property>
-                    <property name="label" translatable="yes">Color of New Phrases</property>
-                  </widget>
-                  <packing>
-                    <property name="top_attach">1</property>
-                    <property name="bottom_attach">2</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="label4">
-                    <property name="visible">True</property>
-                    <property name="xalign">0.89999997615814209</property>
-                    <property name="label" translatable="yes">Color of Normal Phrases</property>
-                  </widget>
-                </child>
-                <child>
-                  <widget class="GtkColorButton" id="ErrorEnglishPhraseColor">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <signal name="color_set" handler="on_value_changed"/>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">2</property>
-                    <property name="top_attach">5</property>
-                    <property name="bottom_attach">6</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkColorButton" id="EnglishPhraseColor">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <signal name="color_set" handler="on_value_changed"/>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">2</property>
-                    <property name="top_attach">4</property>
-                    <property name="bottom_attach">5</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkColorButton" id="SpecialPhraseColor">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <signal name="color_set" handler="on_value_changed"/>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">2</property>
-                    <property name="top_attach">3</property>
-                    <property name="bottom_attach">4</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkColorButton" id="UserPhraseColor">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <signal name="color_set" handler="on_value_changed"/>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">2</property>
-                    <property name="top_attach">2</property>
-                    <property name="bottom_attach">3</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkColorButton" id="NewPhraseColor">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <signal name="color_set" handler="on_value_changed"/>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">2</property>
-                    <property name="top_attach">1</property>
-                    <property name="bottom_attach">2</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkColorButton" id="PhraseColor">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <signal name="color_set" handler="on_value_changed"/>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">2</property>
-                  </packing>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-              </widget>
-              <packing>
-                <property name="position">2</property>
-              </packing>
-            </child>
-            <child>
-              <widget class="GtkLabel" id="label2">
-                <property name="visible">True</property>
-                <property name="label" translatable="yes">Colors</property>
-              </widget>
-              <packing>
-                <property name="position">2</property>
-                <property name="tab_fill">False</property>
-                <property name="type">tab</property>
-              </packing>
-            </child>
-            <child>
-              <widget class="GtkTable" id="table3">
-                <property name="no_show_all">True</property>
-                <property name="n_rows">6</property>
-                <property name="n_columns">3</property>
-                <property name="homogeneous">True</property>
-                <child>
-                  <widget class="GtkButton" id="button_optimize_db">
-                    <property name="visible">True</property>
-                    <property name="sensitive">False</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <signal name="clicked" handler="on_button_optimize_db_clicked"/>
-                    <child>
-                      <widget class="GtkHBox" id="hbox1">
-                        <property name="visible">True</property>
-                        <child>
-                          <widget class="GtkImage" id="image1">
-                            <property name="visible">True</property>
-                            <property name="xalign">0.80000001192092896</property>
-                            <property name="stock">gtk-execute</property>
-                            <property name="icon-size">4</property>
-                          </widget>
-                          <packing>
-                            <property name="position">0</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <widget class="GtkLabel" id="label19">
-                            <property name="visible">True</property>
-                            <property name="xalign">0.10000000149011612</property>
-                            <property name="label" translatable="yes">Optimize User DB</property>
-                          </widget>
-                          <packing>
-                            <property name="position">1</property>
-                          </packing>
-                        </child>
-                      </widget>
-                    </child>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">2</property>
-                    <property name="top_attach">1</property>
-                    <property name="bottom_attach">2</property>
-                  </packing>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-              </widget>
-              <packing>
-                <property name="position">3</property>
-              </packing>
-            </child>
-            <child>
-              <widget class="GtkLabel" id="label3">
-                <property name="label" translatable="yes">User DB</property>
-              </widget>
-              <packing>
-                <property name="position">3</property>
-                <property name="tab_fill">False</property>
-                <property name="type">tab</property>
-              </packing>
-            </child>
-            <child>
-              <widget class="GtkLabel" id="label15">
-                <property name="visible">True</property>
-                <property name="label" translatable="yes">Python PinYin
-
-provided by
-
-Huang Peng &lt;shawn.p.huang@gmail.com&gt;
-</property>
-                <property name="justify">center</property>
-              </widget>
-              <packing>
-                <property name="position">4</property>
-              </packing>
-            </child>
-            <child>
-              <widget class="GtkLabel" id="label18">
-                <property name="label" translatable="yes">About</property>
-              </widget>
-              <packing>
-                <property name="position">4</property>
-                <property name="tab_fill">False</property>
-                <property name="type">tab</property>
-              </packing>
-            </child>
-          </widget>
-          <packing>
-            <property name="position">0</property>
-          </packing>
-        </child>
-        <child>
-          <widget class="GtkHButtonBox" id="hbuttonbox1">
-            <property name="visible">True</property>
-            <property name="spacing">12</property>
-            <property name="layout_style">end</property>
-            <child>
-              <widget class="GtkButton" id="button_apply">
-                <property name="label">gtk-apply</property>
-                <property name="visible">True</property>
-                <property name="sensitive">False</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">False</property>
-                <property name="use_stock">True</property>
-                <signal name="clicked" handler="on_button_apply_clicked"/>
-              </widget>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-            <child>
-              <widget class="GtkButton" id="button_cancel">
-                <property name="label">gtk-cancel</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">False</property>
-                <property name="use_stock">True</property>
-                <signal name="clicked" handler="on_button_cancel_clicked"/>
-              </widget>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">1</property>
-              </packing>
-            </child>
-            <child>
-              <widget class="GtkButton" id="button_ok">
-                <property name="label">gtk-ok</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">False</property>
-                <property name="use_stock">True</property>
-                <signal name="clicked" handler="on_button_ok_clicked"/>
-                <signal name="activate" handler="on_button_ok_activate"/>
-              </widget>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">2</property>
-              </packing>
-            </child>
-          </widget>
-          <packing>
-            <property name="expand">False</property>
-            <property name="padding">7</property>
-            <property name="position">1</property>
-          </packing>
-        </child>
-      </widget>
-    </child>
-  </widget>
-</glade-interface>
diff --git a/src/Array.h b/src/Array.h
new file mode 100644 (file)
index 0000000..535ced8
--- /dev/null
@@ -0,0 +1,108 @@
+#ifndef __PY_ARRAY_H_
+#define __PY_ARRAY_H_
+
+namespace PY {
+
+template<typename T>
+class Array {
+public:
+    Array (guint init_size = 0) {
+        m_array = g_array_sized_new (FALSE, FALSE, sizeof (T), init_size);
+    }
+
+    ~Array () {
+        g_array_free (m_array, TRUE);
+    }
+
+    T & get (guint i) {
+        return g_array_index (m_array, T, i);
+    }
+
+    const T & get (guint i) const {
+        return g_array_index (m_array, T, i);
+    }
+
+    guint length (void) const {
+        return m_array->len;
+    }
+
+    gboolean isEmpty (void) const {
+        return length () == 0;
+    }
+
+    Array<T> & setSize (guint size) {
+        g_array_set_size (m_array, size);
+        return *this;
+    }
+
+    Array<T> & removeAll () {
+        setSize (0);
+        return *this;
+    }
+
+    Array<T> & append (const T & v) {
+        g_array_append_val (m_array, v);
+        return *this;
+    }
+
+    Array<T> & append (const Array<T> & a) {
+        for (guint i = 0; i < a.length (); i++)
+            append (a[i]);
+        return *this;
+    }
+
+    Array<T> & push (const T & v) {
+        append (v);
+        return *this;
+    }
+
+    T & pop (void) {
+        T & v = g_array_index (m_array, T, length () - 1);
+        g_array_set_size (m_array, length () - 1);
+        return v;
+    }
+
+    Array<T> & operator = (const Array<T> & v) {
+        removeAll ();
+        for (guint i = 0; i < v.length(); i++)
+            append (v[i]);
+        return *this;
+    }
+
+    gboolean operator == (const Array<T> &v) const {
+        if (length () != v.length ())
+            return FALSE;
+        for (guint i = 0; i < length (); i++) {
+            if (get (i) != v[i])
+                return FALSE;
+        }
+        return TRUE;
+    }
+
+    Array<T> & operator << (const T & v) {
+        return append (v);
+    }
+
+    Array<T> & operator << (const Array<T> & a) {
+        return append (a);
+    }
+
+    T & operator[] (guint i) {
+        return get (i);
+    }
+
+    const T & operator[] (guint i) const {
+        return get (i);
+    }
+
+    operator gboolean (void) const {
+        return length () != 0;
+    }
+
+private:
+    GArray *m_array;
+};
+
+};
+
+#endif
diff --git a/src/Bus.h b/src/Bus.h
new file mode 100644 (file)
index 0000000..be76894
--- /dev/null
+++ b/src/Bus.h
@@ -0,0 +1,17 @@
+#ifndef __PY_BUS_H_
+#define __PY_BUS_H_
+
+#include <ibus.h>
+#include "Pointer.h"
+
+namespace PY {
+
+class Bus : public Pointer <IBusBus> {
+public:
+    Bus (void) {
+        set (ibus_bus_new ());
+    }
+};
+
+};
+#endif
diff --git a/src/Config.cc b/src/Config.cc
new file mode 100644 (file)
index 0000000..a629c33
--- /dev/null
@@ -0,0 +1,203 @@
+#include "Types.h"
+#include "Config.h"
+#include "Util.h"
+
+namespace PY {
+
+guint Config::m_option = PINYIN_SIMPLE_PINYIN | PINYIN_CORRECT_ALL;
+guint Config::m_option_mask = PINYIN_SIMPLE_PINYIN | PINYIN_CORRECT_ALL;
+guint Config::m_page_size = 5;
+gboolean Config::m_minus_equal_page = TRUE;
+gboolean Config::m_comma_period_page = TRUE;
+gboolean Config::m_double_pinyin = FALSE;
+gint Config::m_double_pinyin_schema = 0;
+gboolean Config::m_init_chinese = TRUE;
+gboolean Config::m_init_full = FALSE;
+gboolean Config::m_init_full_punct = TRUE;
+
+static const StaticString engine_pinyin ("engine/Pinyin");
+static const StaticString correct_pinyin ("CorrectPinyin");
+static const StaticString fuzzy_pinyin ("FuzzyPinyin");
+static const StaticString page_size ("LookupTablePageSize");
+static const StaticString minus_equal_page ("MinusEqualPage");
+static const StaticString comma_period_page ("CommaPeriodPage");
+static const StaticString double_pinyin ("DoublePinyin");
+static const StaticString double_pinyin_schema ("DoublePinyinSchema");
+static const StaticString init_chinese ("InitChinese");
+static const StaticString init_full ("InitFull");
+static const StaticString init_full_punct ("InitFullPunct");
+
+static const struct {
+    StaticString name;
+    guint option;
+    bool defval;
+} options [] = {
+    { StaticString ("SimplePinyin"),       PINYIN_SIMPLE_PINYIN,       TRUE },
+    /* correct */
+    { StaticString ("CorrectPinyin_GN_NG"),    PINYIN_CORRECT_GN_TO_NG,    TRUE },
+    { StaticString ("CorrectPinyin_GN_NG"),    PINYIN_CORRECT_GN_TO_NG,    TRUE },
+    { StaticString ("CorrectPinyin_MG_NG"),    PINYIN_CORRECT_MG_TO_NG,    TRUE },
+    { StaticString ("CorrectPinyin_IOU_IU"),   PINYIN_CORRECT_IOU_TO_IU,   TRUE },
+    { StaticString ("CorrectPinyin_UEI_UI"),   PINYIN_CORRECT_UEI_TO_UI,   TRUE },
+    { StaticString ("CorrectPinyin_UEN_UN"),   PINYIN_CORRECT_UEN_TO_UN,   TRUE },
+    { StaticString ("CorrectPinyin_VE_UE"),    PINYIN_CORRECT_VE_TO_UE,    TRUE },
+    /* fuzzy pinyin */
+    { StaticString ("FuzzyPinyin_C_CH"),      PINYIN_FUZZY_C_CH,  FALSE },
+    { StaticString ("FuzzyPinyin_CH_C"),      PINYIN_FUZZY_CH_C,  FALSE },
+    { StaticString ("FuzzyPinyin_Z_ZH"),      PINYIN_FUZZY_Z_ZH,  FALSE },
+    { StaticString ("FuzzyPinyin_ZH_Z"),      PINYIN_FUZZY_ZH_Z,  FALSE },
+    { StaticString ("FuzzyPinyin_S_SH"),      PINYIN_FUZZY_S_SH,  FALSE },
+    { StaticString ("FuzzyPinyin_SH_S"),      PINYIN_FUZZY_SH_S,  FALSE },
+    { StaticString ("FuzzyPinyin_L_N"),       PINYIN_FUZZY_L_N,   FALSE },
+    { StaticString ("FuzzyPinyin_N_L"),       PINYIN_FUZZY_N_L,   FALSE },
+    { StaticString ("FuzzyPinyin_F_H"),       PINYIN_FUZZY_F_H,   FALSE },
+    { StaticString ("FuzzyPinyin_H_F"),       PINYIN_FUZZY_H_F,   FALSE },
+    { StaticString ("FuzzyPinyin_L_R"),       PINYIN_FUZZY_L_R,   FALSE },
+    { StaticString ("FuzzyPinyin_R_L"),       PINYIN_FUZZY_R_L,   FALSE },
+    { StaticString ("FuzzyPinyin_K_G"),       PINYIN_FUZZY_K_G,   FALSE },
+    { StaticString ("FuzzyPinyin_G_K"),       PINYIN_FUZZY_G_K,   FALSE },
+    { StaticString ("FuzzyPinyin_AN_ANG"),    PINYIN_FUZZY_AN_ANG,    FALSE },
+    { StaticString ("FuzzyPinyin_ANG_AN"),    PINYIN_FUZZY_ANG_AN,    FALSE },
+    { StaticString ("FuzzyPinyin_EN_ENG"),    PINYIN_FUZZY_EN_ENG,    FALSE },
+    { StaticString ("FuzzyPinyin_ENG_EN"),    PINYIN_FUZZY_ENG_EN,    FALSE },
+    { StaticString ("FuzzyPinyin_IN_ING"),    PINYIN_FUZZY_IN_ING,    FALSE },
+    { StaticString ("FuzzyPinyin_ING_IN"),    PINYIN_FUZZY_ING_IN,    FALSE },
+    { StaticString ("FuzzyPinyin_UAN_UANG"),  PINYIN_FUZZY_UAN_UANG,  FALSE },
+    { StaticString ("FuzzyPinyin_UANG_UAN"),  PINYIN_FUZZY_UANG_UAN,  FALSE },
+};
+
+void
+Config::readDefaultValues (void)
+{
+    /* double pinyin */
+    m_double_pinyin = read (engine_pinyin, double_pinyin, false);
+    m_double_pinyin_schema = read (engine_pinyin, double_pinyin_schema, 0);
+
+    /* init states */
+    m_init_chinese = read (engine_pinyin, init_chinese, true);
+    m_init_full = read (engine_pinyin, init_full, false);
+    m_init_full_punct = read (engine_pinyin, init_full_punct, true);
+    
+    /* others */
+    m_page_size = read (engine_pinyin, page_size, 5);
+    m_minus_equal_page = read (engine_pinyin, minus_equal_page, true);
+    m_comma_period_page = read (engine_pinyin, comma_period_page, true);
+
+    /* correct pinyin */
+    if (read (engine_pinyin, correct_pinyin, true))
+        m_option_mask |= PINYIN_CORRECT_ALL;
+    else
+        m_option_mask &= ~PINYIN_CORRECT_ALL;
+
+    /* fuzzy pinyin */
+    if (read (engine_pinyin, fuzzy_pinyin, false))
+        m_option_mask |= PINYIN_FUZZY_ALL;
+    else
+        m_option_mask &= ~PINYIN_FUZZY_ALL;
+
+    /* read values */
+    for (guint i = 0;i < sizeof (options) / sizeof (options[0]); i++) {
+        if (read (engine_pinyin, options[i].name, options[i].defval))
+            m_option |= options[i].option;
+        else
+            m_option &= ~options[i].option;
+    }
+}
+
+inline bool
+Config::read (const gchar *section, const gchar *name, bool defval)
+{
+    GValue value = {0};
+    if (ibus_config_get_value (m_config, section, name, &value)) {
+        if (G_VALUE_TYPE (&value) == G_TYPE_BOOLEAN)
+            return g_value_get_boolean (&value);
+    }
+    return defval;
+}
+
+inline gint
+Config::read (const gchar *section, const gchar *name, gint defval)
+{
+    GValue value = {0};
+    if (ibus_config_get_value (m_config, section, name, &value)) {
+        if (G_VALUE_TYPE (&value) == G_TYPE_INT)
+            return g_value_get_int (&value);
+    }
+    return defval;
+}
+
+static inline bool
+normalizeGValue (const GValue *value, bool defval)
+{
+    if (value == NULL || G_VALUE_TYPE (value) != G_TYPE_BOOLEAN)
+        return defval;
+    return g_value_get_boolean (value);
+}
+
+static inline gint
+normalizeGValue (const GValue *value, gint defval)
+{
+    if (value == NULL || G_VALUE_TYPE (value) != G_TYPE_INT)
+        return defval;
+    return g_value_get_int (value);
+}
+
+void
+Config::valueChangedCallback (IBusConfig    *config,
+                              const gchar   *section,
+                              const gchar   *name,
+                              const GValue  *value,
+                              Config        *self)
+{
+    if (engine_pinyin != section)
+        return;
+    
+    /* double pinyin */
+    if (double_pinyin == name)
+        m_double_pinyin = normalizeGValue (value, false);
+    else if (double_pinyin_schema == name)
+        m_double_pinyin_schema = normalizeGValue (value, 0);
+    /* init states */
+    else if (init_chinese == name)
+        m_init_chinese = normalizeGValue (value, true);
+    else if (init_full == name)
+        m_init_full = normalizeGValue (value, true);
+    else if (init_full_punct == name)
+        m_init_full_punct = normalizeGValue (value, true);
+    /* lookup table page size */
+    else if (page_size == name)
+        m_page_size = normalizeGValue (value, 5);
+    else if (minus_equal_page == name)
+        m_minus_equal_page = normalizeGValue (value, true);
+    else if (comma_period_page == name)
+        m_comma_period_page = normalizeGValue (value, true);
+    /* correct pinyin */
+    else if (correct_pinyin == name) {
+        if (normalizeGValue (value, TRUE))
+            m_option_mask |= PINYIN_CORRECT_ALL;
+        else
+            m_option_mask &= ~PINYIN_CORRECT_ALL;
+    }
+    /* fuzzy pinyin */
+    else if (fuzzy_pinyin == name) {
+        if (normalizeGValue (value, TRUE))
+            m_option_mask |= PINYIN_FUZZY_ALL;
+        else
+            m_option_mask &= ~PINYIN_FUZZY_ALL;
+    }
+    else {
+        for (guint i = 0;i < sizeof (options) / sizeof (options[0]); i++) {
+            if (G_LIKELY (options[i].name != name))
+                continue;
+            if (normalizeGValue (value, options[i].defval))
+                m_option |= options[i].option;
+            else
+                m_option &= ~options[i].option;
+            break;
+        }
+    }
+
+}
+
+
+};
diff --git a/src/Config.h b/src/Config.h
new file mode 100644 (file)
index 0000000..cd7630d
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef __PY_CONFIG_H_
+#define __PY_CONFIG_H_
+
+#include <glib.h>
+#include <glib-object.h>
+#include <ibus.h>
+#include "Pointer.h"
+
+namespace PY {
+
+class Config {
+public:
+    Config (Pointer<IBusBus> & bus) {
+        m_config = ibus_bus_get_config (bus);
+        readDefaultValues ();
+        g_signal_connect ((IBusConfig *) m_config, "value-changed", G_CALLBACK (valueChangedCallback), this);
+    }
+
+    static guint option (void) { return m_option & m_option_mask; }
+    static guint pageSize (void) { return m_page_size; }
+    static gboolean minusEqualPage (void) { return m_minus_equal_page; }
+    static gboolean commaPeriodPage (void) { return m_comma_period_page; }
+    static gboolean doublePinyin (void) { return m_double_pinyin; }
+    static gint doublePinyinSchema (void) { return m_double_pinyin_schema; }
+    static gboolean initChinese (void) { return m_init_chinese; }
+    static gboolean initFull (void) { return m_init_full; }
+    static gboolean initFullPunct (void) { return m_init_full_punct; }
+
+private:
+    bool read (const gchar *section, const gchar *name, bool defval);
+    int read (const gchar *section, const gchar *name, int defval);
+    void readDefaultValues (void);
+    static void valueChangedCallback (IBusConfig    *config,
+                                      const gchar   *section,
+                                      const gchar   *name,
+                                      const GValue  *value,
+                                      Config        *self);
+
+private:
+    Pointer<IBusConfig> m_config;
+
+private:
+    static guint m_option;
+    static guint m_option_mask;
+    static guint m_page_size;
+    static gboolean m_minus_equal_page;
+    static gboolean m_comma_period_page;
+    static gboolean m_double_pinyin;
+    static gint m_double_pinyin_schema;
+    static gboolean m_init_chinese;
+    static gboolean m_init_full;
+    static gboolean m_init_full_punct;
+};
+
+};
+#endif
diff --git a/src/Database.cc b/src/Database.cc
new file mode 100644 (file)
index 0000000..918cfd2
--- /dev/null
@@ -0,0 +1,583 @@
+/* vim:set et sts=4: */
+#include <string.h>
+#include <glib.h>
+#include <sqlite3.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include "Database.h"
+#include "Util.h"
+
+namespace PY {
+
+#define DB_CACHE_SIZE       "5000"
+#define DB_INDEX_SIZE       (3)
+/* define columns */
+#define DB_COLUMN_USER_FREQ (0)
+#define DB_COLUMN_PHRASE    (1)
+#define DB_COLUMN_FREQ      (2)
+#define DB_COLUMN_S0        (3)
+
+#define DB_PREFETCH_LEN     (6)
+
+Database::Database (void)
+    : m_db (NULL),
+      m_sql (1024),
+      m_buffer (1024),
+      m_conditions (32),
+      m_strings (32)
+{
+    init ();
+}
+
+Database::~Database (void)
+{
+    for (guint i = 0; i < m_strings.length (); i++) {
+        delete m_strings[i];
+    }
+
+    if (m_db) {
+        sqlite3_close (m_db);
+        m_db = NULL;
+    }
+}
+
+gboolean
+Database::init (void)
+{
+    gchar *errmsg;
+    gchar *userdb;
+    gboolean retval;
+
+    sqlite3_initialize ();
+
+    if (sqlite3_open_v2 (PKGDATADIR"/db/main.db", &m_db,
+            SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL) != SQLITE_OK) {
+        if (sqlite3_open_v2 ("main.db", &m_db,
+                SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL) != SQLITE_OK)
+            goto _failed;
+    }
+    
+    if (sqlite3_exec (m_db, "PRAGMA cache_size=" DB_CACHE_SIZE, NULL, NULL, &errmsg) != SQLITE_OK) {
+        g_debug ("%s", errmsg);
+        sqlite3_free (errmsg);
+        goto _failed;
+    }
+
+    userdb = g_build_path (G_DIR_SEPARATOR_S, g_get_home_dir (), ".ibus", "pinyin", NULL);
+    g_mkdir_with_parents (userdb, 0750);
+    g_free (userdb);
+    userdb = g_build_path (G_DIR_SEPARATOR_S, g_get_home_dir (), ".ibus", "pinyin", "user-1.3.db", NULL);
+    retval = initUserDatabase (userdb);
+    if (!retval) {
+        g_free (userdb);
+        g_warning ("can not open user database %s", userdb);
+        if (!initUserDatabase (":memory:"))
+            goto _failed;
+    }
+    g_free (userdb);
+
+    prefetch ();
+
+    return TRUE;
+
+_failed:
+    if (m_db) {
+        sqlite3_close (m_db);
+        m_db = NULL;
+    }
+    return FALSE;
+}
+
+gboolean
+Database::initUserDatabase (const gchar *userdb)
+{
+    gchar *errmsg;
+
+    m_sql.printf ("ATTACH DATABASE \"%s\" AS userdb;", userdb);
+    if (sqlite3_exec (m_db, m_sql, NULL, NULL, &errmsg) != SQLITE_OK) {
+        g_debug ("%s", errmsg);
+        sqlite3_free (errmsg);
+        return FALSE;
+    }
+
+    m_sql = "BEGIN TRANSACTION;\n";
+    /* create desc table*/
+    m_sql << "CREATE TABLE IF NOT EXISTS userdb.desc (name PRIMARY KEY, value TEXT);\n";
+    m_sql << "INSERT OR IGNORE INTO userdb.desc VALUES " << "('version', '1.2.0');\n"
+          << "INSERT OR IGNORE INTO userdb.desc VALUES " << "('uuid', '" << UUID () << "');\n"
+          << "INSERT OR IGNORE INTO userdb.desc VALUES " << "('hostname', '" << Hostname () << "');\n"
+          << "INSERT OR IGNORE INTO userdb.desc VALUES " << "('username', '" << getenv ("USERNAME") << "');\n"
+          << "INSERT OR IGNORE INTO userdb.desc VALUES " << "('create-time', datetime());\n"
+          << "INSERT OR IGNORE INTO userdb.desc VALUES " << "('attach-time', datetime());\n";
+
+    /* create phrase tables */
+    for (guint i = 0; i < MAX_PHRASE_LEN; i++) {
+        m_sql.appendPrintf ("CREATE TABLE IF NOT EXISTS userdb.py_phrase_%d (user_freq, phrase TEXT, freq INTEGER ", i);
+        for (guint j = 0; j <= i; j++)
+            m_sql.appendPrintf (",s%d INTEGER, y%d INTEGER", j, j);
+        m_sql << ");\n";
+    }
+
+    /* create index */
+    m_sql << "CREATE UNIQUE INDEX IF NOT EXISTS " << "userdb.index_0_0 ON py_phrase_0(s0,y0,phrase);\n";
+    m_sql << "CREATE UNIQUE INDEX IF NOT EXISTS " << "userdb.index_1_0 ON py_phrase_1(s0,y0,s1,y1,phrase);\n";
+    m_sql << "CREATE INDEX IF NOT EXISTS " << "userdb.index_1_1 ON py_phrase_1(s0,s1,y1);\n";
+    for (guint i = 2; i < MAX_PHRASE_LEN; i++) {
+        m_sql << "CREATE UNIQUE INDEX IF NOT EXISTS " << "userdb.index_" << i << "_0 ON py_phrase_" << i
+              << "(s0,y0";
+        for (guint j = 1; j <= i; j++)
+            m_sql << ",s" << j << ",y" << j;
+        m_sql << ",phrase);\n";
+        m_sql << "CREATE INDEX IF NOT EXISTS " << "userdb.index_" << i << "_1 ON py_phrase_" << i << "(s0,s1,s2,y2);\n";
+    }
+    m_sql << "COMMIT;\n";
+
+    if (sqlite3_exec (m_db, m_sql, NULL, NULL, &errmsg) != SQLITE_OK) {
+        g_debug ("%s", errmsg);
+        sqlite3_free (errmsg);
+        goto _failed;
+    }
+
+    m_sql  = "UPDATE userdb.desc SET value=datetime() WHERE name='attach-time';\n";
+
+    if (sqlite3_exec (m_db, m_sql, NULL, NULL, &errmsg) != SQLITE_OK) {
+        g_debug ("%s", errmsg);
+        sqlite3_free (errmsg);
+        goto _failed;
+    }
+    return TRUE;
+
+_failed:
+    m_sql = "DETACH DATABASE userdb;\n";
+    if (sqlite3_exec (m_db, m_sql, NULL, NULL, &errmsg) != SQLITE_OK) {
+        g_debug ("%s", errmsg);
+        sqlite3_free (errmsg);
+    }
+    return FALSE;
+}
+
+void
+Database::prefetch (void)
+{
+    for (guint i = 0; i < DB_PREFETCH_LEN; i++) {
+        gchar *errmsg;
+        m_sql = "SELECT * FROM py_phrase_";
+        m_sql << i;
+        if (sqlite3_exec (m_db, m_sql, NULL, NULL, &errmsg) != SQLITE_OK) {
+            g_debug ("%s", errmsg);
+            sqlite3_free (errmsg);
+        }
+    }
+}
+
+gint
+Database::query (const PinyinArray &pinyin,
+                 guint              m,
+                 guint              option,
+                 PhraseArray       &result)
+{
+    gint len;
+    gint i;
+    gint row;
+    gint ret;
+
+    len = MIN (pinyin.length (), MAX_PHRASE_LEN);
+
+    row = 0;
+    for (i = len; i > 0; i--) {
+        if (m < 0) {
+            ret = query (pinyin, 0, i, -1, option, result);
+            if (ret < 0)
+                return ret;
+            row += ret;
+        }
+        else {
+            ret = query (pinyin, 0, i, m - result.length (), option, result);
+            if (ret < 0)
+                return ret;
+            row += ret;
+            if (result.length () >= m)
+                break;
+        }
+    }
+    return row;
+}
+
+
+
+inline static void
+_conditions_append_vprintf (Array<String *> &array,
+                            gint             begin,
+                            gint             end,
+                            const gchar     *fmt,
+                            va_list          args)
+{
+    gchar str[64];
+    g_vsnprintf (str, sizeof(str), fmt, args);
+
+    for (gint i = begin; i < end; i++) {
+        (*array[i]) << str;
+    }
+}
+
+inline static void
+_conditions_append_printf (Array<String *> &array,
+                           gint             begin,
+                           gint             end,
+                           const gchar     *fmt,
+                           ...)
+{
+    va_list args;
+    va_start (args, fmt);
+    _conditions_append_vprintf (array, begin, end, fmt, args);
+    va_end (args);
+}
+
+#define CONDITION_INIT_SIZE (256)
+
+inline void
+Database::conditionsDouble (void)
+{
+    gint i, len;
+
+    len = m_conditions.length ();
+
+    for (i = 0; i < len; i++) {
+        String *new_str;
+        new_str = string (len + i);
+        *new_str = *m_conditions[i];
+        m_conditions << new_str;
+    }
+}
+
+inline void
+Database::conditionsTriple (void)
+{
+    gint i, len;
+
+    len = m_conditions.length ();
+
+    for (i = 0; i < len; i++) {
+        String *new_str;
+        new_str = string ((i << 1) + len);
+        *new_str = *m_conditions[i];
+        m_conditions << new_str;
+        new_str = string ((i << 1) + len + 1);
+        *new_str = *m_conditions[i];
+        m_conditions << new_str;
+    }
+}
+
+inline static gboolean
+pinyin_option_check_sheng (guint option, gint id, gint fid)
+{
+    switch ((id << 16) | fid) {
+    case (PINYIN_ID_C << 16) | PINYIN_ID_CH:
+        return (option & PINYIN_FUZZY_C_CH);
+    case (PINYIN_ID_CH << 16) | PINYIN_ID_C:
+        return (option & PINYIN_FUZZY_CH_C);
+    case (PINYIN_ID_Z << 16) | PINYIN_ID_ZH:
+        return (option & PINYIN_FUZZY_Z_ZH);
+    case (PINYIN_ID_ZH << 16) | PINYIN_ID_Z:
+        return (option & PINYIN_FUZZY_ZH_Z);
+    case (PINYIN_ID_S << 16) | PINYIN_ID_SH:
+        return (option & PINYIN_FUZZY_S_SH);
+    case (PINYIN_ID_SH << 16) | PINYIN_ID_S:
+        return (option & PINYIN_FUZZY_SH_S);
+    case (PINYIN_ID_L << 16) | PINYIN_ID_N:
+        return (option & PINYIN_FUZZY_L_N);
+    case (PINYIN_ID_N << 16) | PINYIN_ID_L:
+        return (option & PINYIN_FUZZY_N_L);
+    case (PINYIN_ID_F << 16) | PINYIN_ID_H:
+        return (option & PINYIN_FUZZY_F_H);
+    case (PINYIN_ID_H << 16) | PINYIN_ID_F:
+        return (option & PINYIN_FUZZY_H_F);
+    case (PINYIN_ID_L << 16) | PINYIN_ID_R:
+        return (option & PINYIN_FUZZY_L_R);
+    case (PINYIN_ID_R << 16) | PINYIN_ID_L:
+        return (option & PINYIN_FUZZY_R_L);
+    case (PINYIN_ID_K << 16) | PINYIN_ID_G:
+        return (option & PINYIN_FUZZY_K_G);
+    case (PINYIN_ID_G << 16) | PINYIN_ID_K:
+        return (option & PINYIN_FUZZY_G_K);
+    default: return FALSE;
+    }
+}
+
+inline static gboolean
+pinyin_option_check_yun (guint option, gint id, gint fid)
+{
+    switch ((id << 16) | fid) {
+    case (PINYIN_ID_AN << 16) | PINYIN_ID_ANG:
+        return (option & PINYIN_FUZZY_AN_ANG);
+    case (PINYIN_ID_ANG << 16) | PINYIN_ID_AN:
+        return (option & PINYIN_FUZZY_ANG_AN);
+    case (PINYIN_ID_EN << 16) | PINYIN_ID_ENG:
+        return (option & PINYIN_FUZZY_EN_ENG);
+    case (PINYIN_ID_ENG << 16) | PINYIN_ID_EN:
+        return (option & PINYIN_FUZZY_ENG_EN);
+    case (PINYIN_ID_IN << 16) | PINYIN_ID_ING:
+        return (option & PINYIN_FUZZY_IN_ING);
+    case (PINYIN_ID_ING << 16) | PINYIN_ID_IN:
+        return (option & PINYIN_FUZZY_ING_IN);
+    case (PINYIN_ID_IAN << 16) | PINYIN_ID_IANG:
+        return (option & PINYIN_FUZZY_IAN_IANG);
+    case (PINYIN_ID_IANG << 16) | PINYIN_ID_IAN:
+        return (option & PINYIN_FUZZY_IANG_IAN);
+    case (PINYIN_ID_UAN << 16) | PINYIN_ID_UANG:
+        return (option & PINYIN_FUZZY_UAN_UANG);
+    case (PINYIN_ID_UANG << 16) | PINYIN_ID_UAN:
+        return (option & PINYIN_FUZZY_UANG_UAN);
+    default: return FALSE;
+    }
+}
+
+gint
+Database::query (const PinyinArray &pinyin,
+                 guint              pinyin_begin,
+                 guint              pinyin_len,
+                 gint               m,
+                 guint              option,
+                 PhraseArray       &result)
+{
+    if (G_UNLIKELY (pinyin_begin > pinyin.length ()))
+        pinyin_begin = pinyin.length ();
+
+    if (G_UNLIKELY (pinyin_len > pinyin.length () - pinyin_begin))
+        pinyin_len = pinyin.length () - pinyin_begin;
+
+    if (G_UNLIKELY (pinyin_len > MAX_PHRASE_LEN))
+        return -1;
+
+    /* prepare sql */
+    m_conditions.setSize (1);
+    m_conditions[0] = this->string (0);
+
+    for (guint i = 0; i < pinyin_len; i++) {
+        const Pinyin *p;
+        gboolean fs1, fs2;
+        p = pinyin[i + pinyin_begin];
+
+        fs1 = pinyin_option_check_sheng (option, p->sheng_id, p->fsheng_id);
+        fs2 = pinyin_option_check_sheng (option, p->sheng_id, p->fsheng_id_2);
+
+        if (G_LIKELY (i > 0))
+            _conditions_append_printf (m_conditions,
+                                       0, m_conditions.length (),
+                                       " AND ");
+
+        if (fs1 || fs2) {
+            if (G_LIKELY (i < DB_INDEX_SIZE)) {
+                if (fs1 && fs2 == 0) {
+                    conditionsDouble ();
+                    _conditions_append_printf (m_conditions,
+                                               0, m_conditions.length ()  >> 1,
+                                               "s%d=%d", i, p->sheng_id);
+                    _conditions_append_printf (m_conditions,
+                                               m_conditions.length () >> 1, m_conditions.length (),
+                                               "s%d=%d", i, p->fsheng_id);
+                }
+                else if (fs1 == 0 && fs2) {
+                    conditionsDouble ();
+                    _conditions_append_printf (m_conditions,
+                                               0, m_conditions.length ()  >> 1,
+                                               "s%d=%d", i, p->sheng_id);
+                    _conditions_append_printf (m_conditions,
+                                               m_conditions.length () >> 1, m_conditions.length (),
+                                               "s%d=%d", i, p->fsheng_id_2);
+                }
+                else {
+                    gint len = m_conditions.length ();
+                    conditionsTriple ();
+                    _conditions_append_printf (m_conditions,
+                                               0, len,
+                                               "s%d=%d", i, p->sheng_id);
+                    _conditions_append_printf (m_conditions,
+                                               len, len << 1,
+                                               "s%d=%d", i, p->fsheng_id);
+                    _conditions_append_printf (m_conditions,
+                                               len << 1, m_conditions.length (),
+                                               "s%d=%d", i, p->fsheng_id_2);
+                }
+            }
+            else {
+                if (fs1 && fs2 == 0) {
+                    _conditions_append_printf (m_conditions,
+                                               0, m_conditions.length (),
+                                               "s%d IN (%d,%d)", i, p->sheng_id, p->fsheng_id);
+                }
+                else if (fs1 == 0 && fs2) {
+                    _conditions_append_printf (m_conditions,
+                                               0, m_conditions.length (),
+                                               "s%d IN (%d,%d)", i, p->sheng_id, p->fsheng_id_2);
+                }
+                else {
+                    _conditions_append_printf (m_conditions,
+                                               0, m_conditions.length (),
+                                               "s%d IN (%d,%d,%d)", i, p->sheng_id, p->fsheng_id, p->fsheng_id_2);
+                }
+            }
+        }
+        else {
+            _conditions_append_printf (m_conditions,
+                                       0, m_conditions.length (),
+                                       "s%d=%d", i, p->sheng_id);
+        }
+
+        if (p->yun_id != PINYIN_ID_ZERO) {
+            if (pinyin_option_check_yun (option, p->yun_id, p->fyun_id)) {
+                if (G_LIKELY (i < DB_INDEX_SIZE)) {
+                    conditionsDouble ();
+                    _conditions_append_printf (m_conditions,
+                                               0, m_conditions.length ()  >> 1,
+                                               " AND y%d=%d", i, p->yun_id);
+                    _conditions_append_printf (m_conditions,
+                                               m_conditions.length () >> 1, m_conditions.length (),
+                                               " and y%d=%d", i, p->fyun_id);
+                }
+                else {
+                    _conditions_append_printf (m_conditions,
+                                               0, m_conditions.length (),
+                                               " AND y%d IN (%d,%d)", i, p->yun_id, p->fyun_id);
+                }
+            }
+            else {
+                _conditions_append_printf (m_conditions,
+                                           0, m_conditions.length (),
+                                           " AND y%d=%d", i, p->yun_id);
+            }
+        }
+    }
+
+
+    m_buffer.truncate (0);
+    for (guint i = 0; i < m_conditions.length (); i++) {
+        if (G_UNLIKELY (i == 0))
+            m_buffer << "  (" << (*m_conditions[i]) << ")\n";
+        else
+            m_buffer << "  OR (" << (*m_conditions[i]) << ")\n";
+    }
+    m_conditions.removeAll ();
+
+    m_sql.printf ("SELECT * FROM ("
+                  "SELECT 0 AS user_freq, * FROM main.py_phrase_%d WHERE %s UNION ALL "
+                  "SELECT * FROM userdb.py_phrase_%d WHERE %s) "
+                  "GROUP BY phrase ORDER BY user_freq DESC, freq DESC ",
+                  pinyin_len - 1, (const gchar *) m_buffer, pinyin_len - 1, (const gchar *)m_buffer);
+    if (m > 0)
+        m_sql << "LIMIT " << m;
+#if 0
+    g_debug ("sql =\n%s", (const gchar *)m_sql);
+#endif
+
+    /* query database */
+    sqlite3_stmt *stmt;
+    if (sqlite3_prepare (m_db,
+                         (const gchar *) m_sql,
+                         -1,
+                         &stmt,
+                         NULL) != SQLITE_OK) {
+        g_debug ("parse sql failed!\n %s", (const gchar *)m_sql);
+        return -1;
+    }
+
+    gint row = 0;
+    while (sqlite3_step (stmt) == SQLITE_ROW) {
+        result.setSize (result.length () + 1);
+        Phrase &p = result[result.length() - 1];
+
+        strcpy (p.phrase, (gchar *) sqlite3_column_text (stmt, DB_COLUMN_PHRASE));
+        p.freq = sqlite3_column_int (stmt, DB_COLUMN_FREQ);
+        p.user_freq = sqlite3_column_int (stmt, DB_COLUMN_USER_FREQ);
+        p.len = pinyin_len;
+
+        for (guint i = 0; i < pinyin_len; i++) {
+            p.pinyin_id[i][0] = sqlite3_column_int (stmt, (i << 1) + DB_COLUMN_S0);
+            p.pinyin_id[i][1] = sqlite3_column_int (stmt, (i << 1) + DB_COLUMN_S0 + 1);
+        }
+        row ++;
+    }
+
+    sqlite3_finalize (stmt);
+    return row;
+}
+
+inline void
+Database::phraseWhereSql (const Phrase & p, String & sql)
+{
+    sql << " WHERE";
+    sql << " s0=" << p.pinyin_id[0][0]
+        << " AND y0=" << p.pinyin_id[0][1];
+    for (guint i = 1; i < p.len; i++) {
+        sql << " AND s" << i << '=' << p.pinyin_id[i][0]
+            << " AND y" << i << '=' << p.pinyin_id[i][1];
+    }
+    sql << " AND phrase=\"" << p.phrase << "\"";
+
+}
+
+inline void
+Database::phraseSql (const Phrase & p, String & sql)
+{
+    sql << "INSERT OR IGNORE INTO userdb.py_phrase_" << p.len - 1
+        << " VALUES(" << 0                  /* user_freq */
+        << ",\"" << p.phrase << '"'         /* phrase */
+        << ','   << p.freq;                 /* freq */
+        for (guint i = 0; i < p.len; i++) {
+            sql << ',' << p.pinyin_id[i][0] << ',' << p.pinyin_id[i][1];
+        }
+    sql << ");\n";
+
+    sql << "UPDATE userdb.py_phrase_" << p.len - 1
+        << " SET user_freq=user_freq+1";
+
+    phraseWhereSql (p, sql);
+    sql << "\n;";
+}
+
+void
+Database::commit (const PhraseArray  &phrases)
+{
+    gchar *errmsg;
+    Phrase phrase = {""};
+
+    m_sql = "BEGIN TRANSACTION;\n";
+    for (guint i = 0; i < phrases.length (); i++) {
+        strcat (phrase.phrase, phrases[i].phrase);
+        for (guint j = 0; j < phrases[i].len; j++) {
+            phrase.pinyin_id[phrase.len + j][0] = phrases[i].pinyin_id[j][0];
+            phrase.pinyin_id[phrase.len + j][1] = phrases[i].pinyin_id[j][1];
+        }
+        phrase.len += phrases[i].len;
+        phraseSql (phrases[i], m_sql);
+    }
+    if (phrases.length () > 1)
+        phraseSql (phrase, m_sql);
+    m_sql << "COMMIT;";
+
+    if (sqlite3_exec (m_db, m_sql, NULL, NULL, &errmsg) != SQLITE_OK) {
+        g_debug ("%s", errmsg);
+        g_debug ("m_sql = %s", (const gchar *)m_sql);
+        sqlite3_free (errmsg);
+    }
+}
+
+void
+Database::remove (const Phrase & phrase)
+{
+    gchar *errmsg;
+    m_sql = "BEGIN TRANSACTION;\n";
+    m_sql << "DELETE FROM userdb.py_phrase_" << phrase.len - 1;
+    phraseWhereSql (phrase, m_sql);
+    m_sql << ";\n";
+    m_sql << "COMMIT;\n";
+
+    if (sqlite3_exec (m_db, m_sql, NULL, NULL, &errmsg) != SQLITE_OK) {
+        g_debug ("%s", errmsg);
+        sqlite3_free (errmsg);
+    }
+
+}
+
+};
diff --git a/src/Database.h b/src/Database.h
new file mode 100644 (file)
index 0000000..f07f212
--- /dev/null
@@ -0,0 +1,60 @@
+/* vim:set et sts=4: */
+#ifndef __PY_DATABASE_H__
+#define __PY_DATABASE_H__
+
+#include <sqlite3.h>
+#include "Types.h"
+#include "Array.h"
+#include "String.h"
+#include "PinyinArray.h"
+#include "PhraseArray.h"
+
+namespace PY {
+
+class Database {
+public:
+    Database ();
+    ~Database ();
+    gint query (const PinyinArray   & pinyin,
+                guint                 m,
+                guint                 option,
+                PhraseArray         & result);
+
+    gint query (const PinyinArray   & pinyin,
+                guint                 pinyin_begin,
+                guint                 pinyin_len,
+                gint                  m,
+                guint                 option,
+                PhraseArray         & result);
+    void commit (const PhraseArray  & phrases);
+    void remove (const Phrase & phrase);
+
+    String *string (guint i) {
+        guint j;
+        for (j = m_strings.length (); j <= i; j++) {
+            m_strings.append (new String (256));
+        }
+        return &(m_strings[i]->truncate (0));
+    }
+
+    void conditionsDouble (void);
+    void conditionsTriple (void);
+
+private:
+    gboolean init (void);
+    gboolean initUserDatabase (const gchar *userdb);
+    void prefetch (void);
+    void phraseSql (const Phrase & p, String & sql);
+    void phraseWhereSql (const Phrase & p, String & sql);
+
+private:
+    sqlite3 *m_db;                  /* sqlite3 database */
+    String   m_sql;                 /* sql stmt */
+    String   m_buffer;              /* temp buffer */
+    Array<String *> m_conditions;   /* select conditions */
+    Array<String *> m_strings;      /* strings */
+};
+
+};
+
+#endif
diff --git a/src/DoublePinyinEditor.cc b/src/DoublePinyinEditor.cc
new file mode 100644 (file)
index 0000000..eb872a9
--- /dev/null
@@ -0,0 +1,246 @@
+#include "Config.h"
+#include "DoublePinyinEditor.h"
+
+namespace PY {
+
+#include "DoublePinyinTable.h"
+
+DoublePinyinEditor::DoublePinyinEditor (void)
+{
+}
+
+static inline gint
+char_to_id (gint ch)
+{
+    switch (ch) {
+    case IBUS_a ... IBUS_z:
+        return ch - IBUS_a;
+    case IBUS_semicolon:
+        return 26;
+    default:
+        return -1;
+    }
+}
+
+inline const Pinyin *
+DoublePinyinEditor::isPinyin (gchar i, gchar j)
+{
+    const Pinyin *pinyin;
+    gint schema = Config::doublePinyinSchema ();
+    gint sheng = double_pinyin_map[schema].sheng[char_to_id(i)];
+    const gint *yun = double_pinyin_map[schema].yun[char_to_id(j)];
+
+    if (sheng == PINYIN_ID_VOID || yun[0] == PINYIN_ID_VOID)
+        return NULL;
+
+    if (sheng == PINYIN_ID_ZERO && yun[0] == PINYIN_ID_ZERO)
+        return NULL;
+
+    pinyin = m_parser.isPinyin (sheng, yun[0], Config::option () & PINYIN_FUZZY_ALL);
+    if (pinyin == NULL && yun[1] != PINYIN_ID_ZERO)
+        pinyin = m_parser.isPinyin (sheng, yun[1], Config::option () & PINYIN_FUZZY_ALL);
+    return pinyin;
+}
+
+gboolean
+DoublePinyinEditor::insert (gint ch)
+{
+    /* is full */
+    if (G_UNLIKELY (m_text.length () >= MAX_PINYIN_LEN))
+        return FALSE;
+
+    gint i = char_to_id (ch);
+    if (i < 0)
+        return FALSE;
+
+    m_text.insert (m_cursor++, ch);
+
+    if (m_cursor != m_pinyin_len + 2)
+        return TRUE;
+
+    const Pinyin *pinyin = isPinyin (m_text[m_cursor - 2], ch);
+    if (pinyin == NULL)
+        return TRUE;
+    m_pinyin << pinyin;
+    m_pinyin_len += 2;
+    return TRUE;
+}
+
+gboolean
+DoublePinyinEditor::removeCharBefore (void)
+{
+    if (G_UNLIKELY (m_cursor == 0))
+        return FALSE;
+
+    m_cursor --;
+    m_text.erase (m_cursor, 1);
+
+    if (m_cursor < m_pinyin_len) {
+        m_pinyin.pop ();
+        m_pinyin_len -= 2;
+    }
+
+    return TRUE;
+}
+
+gboolean
+DoublePinyinEditor::removeCharAfter (void)
+{
+    if (G_UNLIKELY (m_cursor == m_text.length ()))
+        return FALSE;
+
+    m_text.erase (m_cursor, 1);
+
+    return TRUE;
+}
+
+gboolean
+DoublePinyinEditor::removeWordBefore (void)
+{
+    if (G_UNLIKELY (m_cursor == 0))
+        return FALSE;
+
+    guint cursor;
+
+    if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
+        cursor = m_pinyin_len;
+    }
+    else {
+        m_pinyin.pop ();
+        cursor = m_cursor - 2;
+        m_pinyin_len -= 2;
+    }
+
+    m_text.erase (cursor, m_cursor - cursor);
+    m_cursor = cursor;
+    return TRUE;
+}
+
+gboolean
+DoublePinyinEditor::removeWordAfter (void)
+{
+    if (G_UNLIKELY (m_cursor == m_text.length ()))
+        return FALSE;
+
+    m_text.erase (m_cursor, -1);
+    return TRUE;
+}
+
+gboolean
+DoublePinyinEditor::moveCursorLeft (void)
+{
+    if (G_UNLIKELY (m_cursor == 0))
+        return FALSE;
+    m_cursor --;
+
+    if (m_cursor >= m_pinyin_len)
+        return TRUE;
+
+    m_pinyin.pop ();
+    m_pinyin_len -= 2;
+    return TRUE;
+}
+
+gboolean
+DoublePinyinEditor::moveCursorRight (void)
+{
+    if (G_UNLIKELY (m_cursor == m_text.length ()))
+        return FALSE;
+
+    m_cursor ++;
+    updatePinyin ();
+
+    return TRUE;
+}
+
+gboolean
+DoublePinyinEditor::moveCursorLeftByWord (void)
+{
+    if (G_UNLIKELY (m_cursor == 0))
+        return FALSE;
+
+    if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
+        m_cursor = m_pinyin_len;
+        return TRUE;
+    }
+
+    m_pinyin.pop ();
+    m_cursor -= 2;
+    m_pinyin_len -= 2;
+    return TRUE;
+}
+
+gboolean
+DoublePinyinEditor::moveCursorRightByWord (void)
+{
+    return moveCursorToEnd ();
+}
+
+gboolean
+DoublePinyinEditor::moveCursorToBegin (void)
+{
+    if (G_UNLIKELY (m_cursor == 0))
+        return FALSE;
+
+    m_cursor = 0;
+    m_pinyin.removeAll ();
+    m_pinyin_len = 0;
+
+    return TRUE;
+}
+
+gboolean
+DoublePinyinEditor::moveCursorToEnd (void)
+{
+    if (G_UNLIKELY (m_cursor == m_text.length ()))
+        return FALSE;
+
+    m_cursor = m_text.length ();
+    updatePinyin  ();
+
+    return TRUE;
+}
+gboolean
+DoublePinyinEditor::reset (void)
+{
+        gboolean retval = FALSE;
+        if (m_cursor != 0) {
+            m_cursor = 0;
+            retval = TRUE;
+        }
+
+        if (m_text.length () != 0) {
+            m_text.truncate (0);
+            retval = TRUE;
+        }
+
+        if (retval)
+            updatePinyin ();
+
+        return retval;
+    }
+
+
+void
+DoublePinyinEditor::updatePinyin (void)
+{
+    if (G_UNLIKELY (m_text.isEmpty ())) {
+        m_pinyin.removeAll ();
+        m_pinyin_len = 0;
+        return;
+    }
+
+    m_pinyin.removeAll ();
+    m_pinyin_len = 0;
+    for (guint i = 0; i + 1 < m_cursor; i+= 2) {
+        const Pinyin *pinyin = isPinyin (m_text[i], m_text[i + 1]);
+        if (pinyin == NULL)
+            break;
+        m_pinyin << pinyin;
+        m_pinyin_len += 2;
+    }
+}
+
+};
+
+
diff --git a/src/DoublePinyinEditor.h b/src/DoublePinyinEditor.h
new file mode 100644 (file)
index 0000000..75d419a
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef __PY_DOUBLE_PINYIN_EDITOR_H_
+#define __PY_DOUBLE_PINYIN_EDITOR_H_
+
+#include "PinyinEditor.h"
+
+namespace PY {
+
+class DoublePinyinEditor : public PinyinEditor {
+
+public:
+    DoublePinyinEditor (void);
+
+    gboolean insert (gint ch);
+
+    gboolean removeCharBefore (void);
+    gboolean removeCharAfter (void);
+    gboolean removeWordBefore (void);
+    gboolean removeWordAfter (void);
+
+    gboolean moveCursorLeft (void);
+    gboolean moveCursorRight (void);
+    gboolean moveCursorLeftByWord (void);
+    gboolean moveCursorRightByWord (void);
+    gboolean moveCursorToBegin (void);
+    gboolean moveCursorToEnd (void);
+
+    gboolean reset (void);
+private:
+    void updatePinyin (void);
+    const Pinyin *isPinyin (gchar i, gchar j);
+
+};
+
+};
+
+#endif
diff --git a/src/DoublePinyinTable.h b/src/DoublePinyinTable.h
new file mode 100644 (file)
index 0000000..f75f09d
--- /dev/null
@@ -0,0 +1,301 @@
+static const gint double_pinyin_mspy_sheng[] = {
+    PINYIN_ID_VOID, // A
+    PINYIN_ID_B,    // B
+    PINYIN_ID_C,    // C
+    PINYIN_ID_D,    // D
+    PINYIN_ID_VOID, // E
+    PINYIN_ID_F,    // F
+    PINYIN_ID_G,    // G
+    PINYIN_ID_H,    // H
+    PINYIN_ID_CH,   // I
+    PINYIN_ID_J,    // J
+    PINYIN_ID_K,    // K
+    PINYIN_ID_L,    // L
+    PINYIN_ID_M,    // M
+    PINYIN_ID_N,    // N
+    PINYIN_ID_ZERO, // O
+    PINYIN_ID_P,    // P
+    PINYIN_ID_Q,    // Q
+    PINYIN_ID_R,    // R
+    PINYIN_ID_S,    // S
+    PINYIN_ID_T,    // T
+    PINYIN_ID_SH,   // U
+    PINYIN_ID_ZH,   // V
+    PINYIN_ID_W,    // W
+    PINYIN_ID_X,    // X
+    PINYIN_ID_Y,    // Y
+    PINYIN_ID_Z,    // Z
+    PINYIN_ID_VOID, // ;
+};
+static const gint double_pinyin_mspy_yun[][2] = {
+    { PINYIN_ID_A,    PINYIN_ID_VOID }, // A
+    { PINYIN_ID_OU,   PINYIN_ID_VOID }, // B
+    { PINYIN_ID_IAO,  PINYIN_ID_VOID }, // C
+    { PINYIN_ID_UANG, PINYIN_ID_IANG }, // D
+    { PINYIN_ID_E,    PINYIN_ID_VOID }, // E
+    { PINYIN_ID_EN,   PINYIN_ID_VOID }, // F
+    { PINYIN_ID_ENG,  PINYIN_ID_NG   }, // G
+    { PINYIN_ID_ANG,  PINYIN_ID_VOID }, // H
+    { PINYIN_ID_I,    PINYIN_ID_VOID }, // I
+    { PINYIN_ID_AN,   PINYIN_ID_VOID }, // J
+    { PINYIN_ID_AO,   PINYIN_ID_VOID }, // K
+    { PINYIN_ID_AI,   PINYIN_ID_VOID }, // L
+    { PINYIN_ID_IAN,  PINYIN_ID_VOID }, // M
+    { PINYIN_ID_IN,   PINYIN_ID_VOID }, // N
+    { PINYIN_ID_UO,   PINYIN_ID_O    }, // O
+    { PINYIN_ID_UN,   PINYIN_ID_VOID }, // P
+    { PINYIN_ID_IU,   PINYIN_ID_VOID }, // Q
+    { PINYIN_ID_UAN,  PINYIN_ID_ER   }, // R
+    { PINYIN_ID_ONG,  PINYIN_ID_IONG }, // S
+    { PINYIN_ID_UE,   PINYIN_ID_VOID }, // T
+    { PINYIN_ID_U,    PINYIN_ID_VOID }, // U
+    { PINYIN_ID_UI,   PINYIN_ID_UE   }, // V
+    { PINYIN_ID_IA,   PINYIN_ID_UA   }, // W
+    { PINYIN_ID_IE,   PINYIN_ID_VOID }, // X
+    { PINYIN_ID_UAI,  PINYIN_ID_V    }, // Y
+    { PINYIN_ID_EI,   PINYIN_ID_VOID }, // Z
+    { PINYIN_ID_ING,  PINYIN_ID_VOID }, // ;
+};
+static const gint double_pinyin_zrm_sheng[] = {
+    PINYIN_ID_VOID, // A
+    PINYIN_ID_B,    // B
+    PINYIN_ID_C,    // C
+    PINYIN_ID_D,    // D
+    PINYIN_ID_VOID, // E
+    PINYIN_ID_F,    // F
+    PINYIN_ID_G,    // G
+    PINYIN_ID_H,    // H
+    PINYIN_ID_CH,   // I
+    PINYIN_ID_J,    // J
+    PINYIN_ID_K,    // K
+    PINYIN_ID_L,    // L
+    PINYIN_ID_M,    // M
+    PINYIN_ID_N,    // N
+    PINYIN_ID_ZERO, // O
+    PINYIN_ID_P,    // P
+    PINYIN_ID_Q,    // Q
+    PINYIN_ID_R,    // R
+    PINYIN_ID_S,    // S
+    PINYIN_ID_T,    // T
+    PINYIN_ID_SH,   // U
+    PINYIN_ID_ZH,   // V
+    PINYIN_ID_W,    // W
+    PINYIN_ID_X,    // X
+    PINYIN_ID_Y,    // Y
+    PINYIN_ID_Z,    // Z
+    PINYIN_ID_VOID, // ;
+};
+static const gint double_pinyin_zrm_yun[][2] = {
+    { PINYIN_ID_A,    PINYIN_ID_VOID }, // A
+    { PINYIN_ID_OU,   PINYIN_ID_VOID }, // B
+    { PINYIN_ID_IAO,  PINYIN_ID_VOID }, // C
+    { PINYIN_ID_UANG, PINYIN_ID_IANG }, // D
+    { PINYIN_ID_E,    PINYIN_ID_VOID }, // E
+    { PINYIN_ID_EN,   PINYIN_ID_VOID }, // F
+    { PINYIN_ID_ENG,  PINYIN_ID_NG   }, // G
+    { PINYIN_ID_ANG,  PINYIN_ID_VOID }, // H
+    { PINYIN_ID_I,    PINYIN_ID_VOID }, // I
+    { PINYIN_ID_AN,   PINYIN_ID_VOID }, // J
+    { PINYIN_ID_AO,   PINYIN_ID_VOID }, // K
+    { PINYIN_ID_AI,   PINYIN_ID_VOID }, // L
+    { PINYIN_ID_IAN,  PINYIN_ID_VOID }, // M
+    { PINYIN_ID_IN,   PINYIN_ID_VOID }, // N
+    { PINYIN_ID_UO,   PINYIN_ID_O    }, // O
+    { PINYIN_ID_UN,   PINYIN_ID_VOID }, // P
+    { PINYIN_ID_IU,   PINYIN_ID_VOID }, // Q
+    { PINYIN_ID_UAN,  PINYIN_ID_ER   }, // R
+    { PINYIN_ID_ONG,  PINYIN_ID_IONG }, // S
+    { PINYIN_ID_UE,   PINYIN_ID_VOID }, // T
+    { PINYIN_ID_U,    PINYIN_ID_VOID }, // U
+    { PINYIN_ID_UI,   PINYIN_ID_V    }, // V
+    { PINYIN_ID_IA,   PINYIN_ID_UA   }, // W
+    { PINYIN_ID_IE,   PINYIN_ID_VOID }, // X
+    { PINYIN_ID_UAI,  PINYIN_ID_ING  }, // Y
+    { PINYIN_ID_EI,   PINYIN_ID_VOID }, // Z
+    { PINYIN_ID_VOID, PINYIN_ID_VOID }, // ;
+};
+static const gint double_pinyin_abc_sheng[] = {
+    PINYIN_ID_ZH,   // A
+    PINYIN_ID_B,    // B
+    PINYIN_ID_C,    // C
+    PINYIN_ID_D,    // D
+    PINYIN_ID_CH,   // E
+    PINYIN_ID_F,    // F
+    PINYIN_ID_G,    // G
+    PINYIN_ID_H,    // H
+    PINYIN_ID_VOID, // I
+    PINYIN_ID_J,    // J
+    PINYIN_ID_K,    // K
+    PINYIN_ID_L,    // L
+    PINYIN_ID_M,    // M
+    PINYIN_ID_N,    // N
+    PINYIN_ID_ZERO, // O
+    PINYIN_ID_P,    // P
+    PINYIN_ID_Q,    // Q
+    PINYIN_ID_R,    // R
+    PINYIN_ID_S,    // S
+    PINYIN_ID_T,    // T
+    PINYIN_ID_VOID, // U
+    PINYIN_ID_SH,   // V
+    PINYIN_ID_W,    // W
+    PINYIN_ID_X,    // X
+    PINYIN_ID_Y,    // Y
+    PINYIN_ID_Z,    // Z
+    PINYIN_ID_VOID, // ;
+};
+static const gint double_pinyin_abc_yun[][2] = {
+    { PINYIN_ID_A,    PINYIN_ID_VOID }, // A
+    { PINYIN_ID_OU,   PINYIN_ID_VOID }, // B
+    { PINYIN_ID_IN,   PINYIN_ID_UAI  }, // C
+    { PINYIN_ID_IA,   PINYIN_ID_UA   }, // D
+    { PINYIN_ID_E,    PINYIN_ID_VOID }, // E
+    { PINYIN_ID_EN,   PINYIN_ID_VOID }, // F
+    { PINYIN_ID_ENG,  PINYIN_ID_NG   }, // G
+    { PINYIN_ID_ANG,  PINYIN_ID_VOID }, // H
+    { PINYIN_ID_I,    PINYIN_ID_VOID }, // I
+    { PINYIN_ID_AN,   PINYIN_ID_VOID }, // J
+    { PINYIN_ID_AO,   PINYIN_ID_VOID }, // K
+    { PINYIN_ID_AI,   PINYIN_ID_VOID }, // L
+    { PINYIN_ID_UE,   PINYIN_ID_UI   }, // M
+    { PINYIN_ID_UN,   PINYIN_ID_VOID }, // N
+    { PINYIN_ID_UO,   PINYIN_ID_O    }, // O
+    { PINYIN_ID_UAN,  PINYIN_ID_VOID }, // P
+    { PINYIN_ID_EI,   PINYIN_ID_VOID }, // Q
+    { PINYIN_ID_ER,   PINYIN_ID_IU   }, // R
+    { PINYIN_ID_ONG,  PINYIN_ID_IONG }, // S
+    { PINYIN_ID_IANG, PINYIN_ID_UANG }, // T
+    { PINYIN_ID_U,    PINYIN_ID_VOID }, // U
+    { PINYIN_ID_V,    PINYIN_ID_UE   }, // V
+    { PINYIN_ID_IAN,  PINYIN_ID_VOID }, // W
+    { PINYIN_ID_IE,   PINYIN_ID_VOID }, // X
+    { PINYIN_ID_ING,  PINYIN_ID_VOID }, // Y
+    { PINYIN_ID_IAO,  PINYIN_ID_VOID }, // Z
+    { PINYIN_ID_VOID, PINYIN_ID_VOID }, // ;
+};
+static const gint double_pinyin_zgpy_sheng[] = {
+    PINYIN_ID_CH,   // A
+    PINYIN_ID_B,    // B
+    PINYIN_ID_C,    // C
+    PINYIN_ID_D,    // D
+    PINYIN_ID_VOID, // E
+    PINYIN_ID_F,    // F
+    PINYIN_ID_G,    // G
+    PINYIN_ID_H,    // H
+    PINYIN_ID_SH,   // I
+    PINYIN_ID_J,    // J
+    PINYIN_ID_K,    // K
+    PINYIN_ID_L,    // L
+    PINYIN_ID_M,    // M
+    PINYIN_ID_N,    // N
+    PINYIN_ID_ZERO, // O
+    PINYIN_ID_P,    // P
+    PINYIN_ID_Q,    // Q
+    PINYIN_ID_R,    // R
+    PINYIN_ID_S,    // S
+    PINYIN_ID_T,    // T
+    PINYIN_ID_ZH,   // U
+    PINYIN_ID_VOID, // V
+    PINYIN_ID_W,    // W
+    PINYIN_ID_X,    // X
+    PINYIN_ID_Y,    // Y
+    PINYIN_ID_Z,    // Z
+    PINYIN_ID_VOID, // ;
+};
+static const gint double_pinyin_zgpy_yun[][2] = {
+    { PINYIN_ID_A,    PINYIN_ID_VOID }, // A
+    { PINYIN_ID_IAO,  PINYIN_ID_VOID }, // B
+    { PINYIN_ID_VOID, PINYIN_ID_VOID }, // C
+    { PINYIN_ID_IE,   PINYIN_ID_VOID }, // D
+    { PINYIN_ID_E,    PINYIN_ID_VOID }, // E
+    { PINYIN_ID_IAN,  PINYIN_ID_VOID }, // F
+    { PINYIN_ID_IANG, PINYIN_ID_UANG }, // G
+    { PINYIN_ID_ONG,  PINYIN_ID_IONG }, // H
+    { PINYIN_ID_I,    PINYIN_ID_VOID }, // I
+    { PINYIN_ID_ER,   PINYIN_ID_IU   }, // J
+    { PINYIN_ID_EI,   PINYIN_ID_VOID }, // K
+    { PINYIN_ID_UAN,  PINYIN_ID_VOID }, // L
+    { PINYIN_ID_UN,   PINYIN_ID_VOID }, // M
+    { PINYIN_ID_UE,   PINYIN_ID_UI   }, // N
+    { PINYIN_ID_UO,   PINYIN_ID_O    }, // O
+    { PINYIN_ID_AI,   PINYIN_ID_VOID }, // P
+    { PINYIN_ID_AO,   PINYIN_ID_VOID }, // Q
+    { PINYIN_ID_AN,   PINYIN_ID_VOID }, // R
+    { PINYIN_ID_ANG,  PINYIN_ID_VOID }, // S
+    { PINYIN_ID_ENG,  PINYIN_ID_NG   }, // T
+    { PINYIN_ID_U,    PINYIN_ID_VOID }, // U
+    { PINYIN_ID_V,    PINYIN_ID_VOID }, // V
+    { PINYIN_ID_EN,   PINYIN_ID_VOID }, // W
+    { PINYIN_ID_IA,   PINYIN_ID_UA   }, // X
+    { PINYIN_ID_IN,   PINYIN_ID_UAI  }, // Y
+    { PINYIN_ID_OU,   PINYIN_ID_VOID }, // Z
+    { PINYIN_ID_ING,  PINYIN_ID_VOID }, // ;
+};
+static const gint double_pinyin_pyjj_sheng[] = {
+    PINYIN_ID_ZERO, // A
+    PINYIN_ID_B,    // B
+    PINYIN_ID_C,    // C
+    PINYIN_ID_D,    // D
+    PINYIN_ID_VOID, // E
+    PINYIN_ID_F,    // F
+    PINYIN_ID_G,    // G
+    PINYIN_ID_H,    // H
+    PINYIN_ID_SH,   // I
+    PINYIN_ID_J,    // J
+    PINYIN_ID_K,    // K
+    PINYIN_ID_L,    // L
+    PINYIN_ID_M,    // M
+    PINYIN_ID_N,    // N
+    PINYIN_ID_ZERO, // O
+    PINYIN_ID_P,    // P
+    PINYIN_ID_Q,    // Q
+    PINYIN_ID_R,    // R
+    PINYIN_ID_S,    // S
+    PINYIN_ID_T,    // T
+    PINYIN_ID_CH,   // U
+    PINYIN_ID_ZH,   // V
+    PINYIN_ID_W,    // W
+    PINYIN_ID_X,    // X
+    PINYIN_ID_Y,    // Y
+    PINYIN_ID_Z,    // Z
+    PINYIN_ID_VOID, // ;
+};
+static const gint double_pinyin_pyjj_yun[][2] = {
+    { PINYIN_ID_A,    PINYIN_ID_VOID }, // A
+    { PINYIN_ID_IA,   PINYIN_ID_UA   }, // B
+    { PINYIN_ID_UAN,  PINYIN_ID_VOID }, // C
+    { PINYIN_ID_AO,   PINYIN_ID_VOID }, // D
+    { PINYIN_ID_E,    PINYIN_ID_VOID }, // E
+    { PINYIN_ID_AN,   PINYIN_ID_VOID }, // F
+    { PINYIN_ID_ANG,  PINYIN_ID_VOID }, // G
+    { PINYIN_ID_IANG, PINYIN_ID_UANG }, // H
+    { PINYIN_ID_I,    PINYIN_ID_VOID }, // I
+    { PINYIN_ID_IAN,  PINYIN_ID_VOID }, // J
+    { PINYIN_ID_IAO,  PINYIN_ID_VOID }, // K
+    { PINYIN_ID_IN,   PINYIN_ID_VOID }, // L
+    { PINYIN_ID_IE,   PINYIN_ID_VOID }, // M
+    { PINYIN_ID_IU,   PINYIN_ID_VOID }, // N
+    { PINYIN_ID_UO,   PINYIN_ID_O    }, // O
+    { PINYIN_ID_OU,   PINYIN_ID_VOID }, // P
+    { PINYIN_ID_ER,   PINYIN_ID_ING  }, // Q
+    { PINYIN_ID_EN,   PINYIN_ID_VOID }, // R
+    { PINYIN_ID_AI,   PINYIN_ID_VOID }, // S
+    { PINYIN_ID_ENG,  PINYIN_ID_NG   }, // T
+    { PINYIN_ID_U,    PINYIN_ID_VOID }, // U
+    { PINYIN_ID_V,    PINYIN_ID_UI   }, // V
+    { PINYIN_ID_EI,   PINYIN_ID_VOID }, // W
+    { PINYIN_ID_UAI,  PINYIN_ID_UE   }, // X
+    { PINYIN_ID_ONG,  PINYIN_ID_IONG }, // Y
+    { PINYIN_ID_UN,   PINYIN_ID_VOID }, // Z
+    { PINYIN_ID_VOID, PINYIN_ID_VOID }, // ;
+};
+
+static const struct {
+    const gint  (&sheng)[27];
+    const gint  (&yun)[27][2];
+} double_pinyin_map [] = {
+    { double_pinyin_mspy_sheng, double_pinyin_mspy_yun},
+    { double_pinyin_zrm_sheng, double_pinyin_zrm_yun},
+    { double_pinyin_abc_sheng, double_pinyin_abc_yun},
+    { double_pinyin_zgpy_sheng, double_pinyin_zgpy_yun},
+    { double_pinyin_pyjj_sheng, double_pinyin_pyjj_yun},
+};
diff --git a/src/Engine.cc b/src/Engine.cc
new file mode 100644 (file)
index 0000000..f15ff81
--- /dev/null
@@ -0,0 +1,207 @@
+/* vim:set et sts=4: */
+
+#include <ibus.h>
+#include <string.h>
+#include "Engine.h"
+#include "PinyinEngine.h"
+
+namespace PY {
+/* code of engine class of GObject */
+#define IBUS_PINYIN_ENGINE(obj)             \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), IBUS_TYPE_PINYIN_ENGINE, IBusPinyinEngine))
+#define IBUS_PINYIN_ENGINE_CLASS(klass)     \
+    (G_TYPE_CHECK_CLASS_CAST ((klass), IBUS_TYPE_PINYIN_ENGINE, IBusPinyinEngineClass))
+#define IBUS_IS_PINYIN_ENGINE(obj)          \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IBUS_TYPE_PINYIN_ENGINE))
+#define IBUS_IS_PINYIN_ENGINE_CLASS(klass)  \
+    (G_TYPE_CHECK_CLASS_TYPE ((klass), IBUS_TYPE_PINYIN_ENGINE))
+#define IBUS_PINYIN_ENGINE_GET_CLASS(obj)   \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), IBUS_TYPE_PINYIN_ENGINE, IBusPinyinEngineClass))
+
+
+typedef struct _IBusPinyinEngine IBusPinyinEngine;
+typedef struct _IBusPinyinEngineClass IBusPinyinEngineClass;
+
+struct _IBusPinyinEngine {
+    IBusEngine parent;
+
+    /* members */
+    PinyinEngine *engine;
+};
+
+struct _IBusPinyinEngineClass {
+    IBusEngineClass parent;
+};
+
+/* functions prototype */
+static void     ibus_pinyin_engine_class_init   (IBusPinyinEngineClass  *klass);
+static void     ibus_pinyin_engine_init         (IBusPinyinEngine       *pinyin);
+static void     ibus_pinyin_engine_destroy      (IBusPinyinEngine       *pinyin);
+static gboolean ibus_pinyin_engine_process_key_event
+                                                (IBusEngine             *engine,
+                                                 guint                   keyval,
+                                                 guint                   keycode,
+                                                 guint                   modifiers);
+static void     ibus_pinyin_engine_focus_in     (IBusEngine             *engine);
+static void     ibus_pinyin_engine_focus_out    (IBusEngine             *engine);
+static void     ibus_pinyin_engine_reset        (IBusEngine             *engine);
+static void     ibus_pinyin_engine_enable       (IBusEngine             *engine);
+static void     ibus_pinyin_engine_disable      (IBusEngine             *engine);
+
+#if 0
+static void     ibus_engine_set_cursor_location (IBusEngine             *engine,
+                                                 gint                    x,
+                                                 gint                    y,
+                                                 gint                    w,
+                                                 gint                    h);
+static void ibus_pinyin_engine_set_capabilities (IBusEngine             *engine,
+                                                guint                   caps);
+#endif
+
+static void     ibus_pinyin_engine_page_up      (IBusEngine             *engine);
+static void     ibus_pinyin_engine_page_down    (IBusEngine             *engine);
+static void     ibus_pinyin_engine_cursor_up    (IBusEngine             *engine);
+static void     ibus_pinyin_engine_cursor_down  (IBusEngine             *engine);
+static void     ibus_pinyin_engine_property_activate
+                                                (IBusEngine             *engine,
+                                                 const gchar            *prop_name,
+                                                 guint                   prop_state);
+#if 0
+static void ibus_pinyin_engine_property_show    (IBusEngine             *engine,
+                                                 const gchar            *prop_name);
+static void ibus_pinyin_engine_property_hide    (IBusEngine             *engine,
+                                                 const gchar            *prop_name);
+static void ibus_config_value_changed           (IBusConfig             *config,
+                                                 const gchar            *section,
+                                                 const gchar            *name,
+                                                 GValue                 *value,
+                                                 gpointer                user_data);
+#endif
+
+static IBusEngineClass *parent_class = NULL;
+
+GType
+ibus_pinyin_engine_get_type (void)
+{
+    static GType type = 0;
+
+    static const GTypeInfo type_info = {
+        sizeof (IBusPinyinEngineClass),
+        (GBaseInitFunc) NULL,
+        (GBaseFinalizeFunc) NULL,
+        (GClassInitFunc) ibus_pinyin_engine_class_init,
+        NULL,
+        NULL,
+        sizeof (IBusPinyinEngine),
+        0,
+        (GInstanceInitFunc) ibus_pinyin_engine_init,
+    };
+
+    if (type == 0) {
+        type = g_type_register_static (IBUS_TYPE_ENGINE,
+                                       "IBusPinyinEngine",
+                                       &type_info,
+                                       (GTypeFlags) 0);
+    }
+
+    return type;
+}
+
+static void
+ibus_pinyin_engine_class_init (IBusPinyinEngineClass *klass)
+{
+    // GObjectClass *object_class = G_OBJECT_CLASS (klass);
+    IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (klass);
+    IBusEngineClass *engine_class = IBUS_ENGINE_CLASS (klass);
+
+    parent_class = (IBusEngineClass *) g_type_class_peek_parent (klass);
+
+    ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_pinyin_engine_destroy;
+
+    engine_class->process_key_event = ibus_pinyin_engine_process_key_event;
+
+    engine_class->reset = ibus_pinyin_engine_reset;
+    engine_class->enable = ibus_pinyin_engine_enable;
+    engine_class->disable = ibus_pinyin_engine_disable;
+
+    engine_class->focus_in = ibus_pinyin_engine_focus_in;
+    engine_class->focus_out = ibus_pinyin_engine_focus_out;
+
+    engine_class->page_up = ibus_pinyin_engine_page_up;
+    engine_class->page_down = ibus_pinyin_engine_page_down;
+
+    engine_class->cursor_up = ibus_pinyin_engine_cursor_up;
+    engine_class->cursor_down = ibus_pinyin_engine_cursor_down;
+
+    engine_class->property_activate = ibus_pinyin_engine_property_activate;
+}
+
+static void
+ibus_pinyin_engine_init (IBusPinyinEngine *pinyin)
+{
+    if (g_object_is_floating (pinyin))
+        g_object_ref_sink (pinyin);  // make engine sink
+    pinyin->engine = new PinyinEngine (IBUS_ENGINE (pinyin));
+}
+
+static void
+ibus_pinyin_engine_destroy (IBusPinyinEngine *pinyin)
+{
+    if (pinyin->engine) {
+        delete pinyin->engine;
+        pinyin->engine = NULL;
+    }
+    IBUS_OBJECT_CLASS (parent_class)->destroy ((IBusObject *)pinyin);
+}
+
+static gboolean
+ibus_pinyin_engine_process_key_event (IBusEngine     *engine,
+                                      guint           keyval,
+                                      guint           keycode,
+                                      guint           modifiers)
+{
+    IBusPinyinEngine *pinyin = (IBusPinyinEngine *) engine;
+    return pinyin->engine->processKeyEvent (keyval, keycode, modifiers);
+}
+
+static void
+ibus_pinyin_engine_property_activate (IBusEngine    *engine,
+                                      const gchar   *prop_name,
+                                      guint          prop_state)
+{
+    IBusPinyinEngine *pinyin = (IBusPinyinEngine *) engine;
+    pinyin->engine->propertyActivate (prop_name, prop_state);
+}
+#define FUNCTION(name, Name)                                        \
+    static void                                                     \
+    ibus_pinyin_engine_##name (IBusEngine *engine)                  \
+    {                                                               \
+        IBusPinyinEngine *pinyin = (IBusPinyinEngine *) engine;     \
+        pinyin->engine->Name ();                                    \
+        parent_class->name (engine);                                \
+    }
+FUNCTION(focus_in,    focusIn)
+FUNCTION(focus_out,   focusOut)
+FUNCTION(reset,       reset)
+FUNCTION(enable,      enable)
+FUNCTION(disable,     disable)
+FUNCTION(page_up,     pageUp)
+FUNCTION(page_down,   pageDown)
+FUNCTION(cursor_up,   cursorUp)
+FUNCTION(cursor_down, cursorDown)
+#undef FUNCTION
+
+
+#if 0
+static void
+ibus_config_value_changed (IBusConfig   *config,
+                           const gchar  *section,
+                           const gchar  *name,
+                           GValue       *value,
+                           gpointer      user_data)
+{
+}
+#endif
+
+};
+
diff --git a/src/Engine.h b/src/Engine.h
new file mode 100644 (file)
index 0000000..0b39081
--- /dev/null
@@ -0,0 +1,15 @@
+/* vim:set et sts=4: */
+#ifndef __PY_ENGINE_H__
+#define __PY_ENGINE_H__
+
+#include <ibus.h>
+
+namespace PY {
+
+#define IBUS_TYPE_PINYIN_ENGINE        \
+       (PY::ibus_pinyin_engine_get_type ())
+
+GType   ibus_pinyin_engine_get_type    (void);
+};
+
+#endif
diff --git a/src/FullPinyinEditor.cc b/src/FullPinyinEditor.cc
new file mode 100644 (file)
index 0000000..0514f8a
--- /dev/null
@@ -0,0 +1,182 @@
+#include "Config.h"
+#include "FullPinyinEditor.h"
+
+namespace PY {
+
+
+FullPinyinEditor::FullPinyinEditor (void)
+{
+}
+
+
+gboolean
+FullPinyinEditor::insert (gint ch)
+{
+    /* is full */
+    if (G_UNLIKELY (m_text.length () >= MAX_PINYIN_LEN))
+        return FALSE;
+
+    m_text.insert (m_cursor++, ch);
+
+    if (G_UNLIKELY ((Config::option () & PINYIN_SIMPLE_PINYIN) == 0)) {
+        updatePinyin ();
+    }
+    else {
+        if (G_LIKELY ((m_cursor - 1 == m_pinyin_len) ||
+                      (m_cursor - 2 == m_pinyin_len &&
+                       m_text[m_pinyin_len] == '\''))) {
+            updatePinyin ();
+        }
+    }
+    return TRUE;
+}
+
+gboolean
+FullPinyinEditor::removeCharBefore (void)
+{
+    if (G_UNLIKELY (m_cursor == 0))
+        return FALSE;
+
+    m_cursor --;
+    m_text.erase (m_cursor, 1);
+
+    updatePinyin ();
+
+    return TRUE;
+}
+
+gboolean
+FullPinyinEditor::removeCharAfter (void)
+{
+    if (G_UNLIKELY (m_cursor == m_text.length ()))
+        return FALSE;
+
+    m_text.erase (m_cursor, 1);
+
+    return TRUE;
+}
+
+gboolean
+FullPinyinEditor::removeWordBefore (void)
+{
+    if (G_UNLIKELY (m_cursor == 0))
+        return FALSE;
+
+    guint cursor;
+
+    if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
+        cursor = m_pinyin_len;
+    }
+    else {
+        const Pinyin * p = m_pinyin.pop ();
+        cursor = m_cursor - p->len;
+        m_pinyin_len -= p->len;
+    }
+
+    m_text.erase (cursor, m_cursor - cursor);
+    m_cursor = cursor;
+    return TRUE;
+}
+
+gboolean
+FullPinyinEditor::removeWordAfter (void)
+{
+    if (G_UNLIKELY (m_cursor == m_text.length ()))
+        return FALSE;
+
+    m_text.erase (m_cursor, -1);
+    return TRUE;
+}
+
+gboolean
+FullPinyinEditor::moveCursorLeft (void)
+{
+    if (G_UNLIKELY (m_cursor == 0))
+        return FALSE;
+
+    m_cursor --;
+    updatePinyin ();
+
+    return TRUE;
+}
+
+gboolean
+FullPinyinEditor::moveCursorRight (void)
+{
+    if (G_UNLIKELY (m_cursor == m_text.length ()))
+        return FALSE;
+
+    m_cursor ++;
+    updatePinyin ();
+
+    return TRUE;
+}
+
+gboolean
+FullPinyinEditor::moveCursorLeftByWord (void)
+{
+    if (G_UNLIKELY (m_cursor == 0))
+        return FALSE;
+
+    if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
+        m_cursor = m_pinyin_len;
+        return TRUE;
+    }
+
+    const Pinyin * p = m_pinyin.pop ();
+    m_cursor -= p->len;
+    m_pinyin_len -= p->len;
+
+    return TRUE;
+}
+
+gboolean
+FullPinyinEditor::moveCursorRightByWord (void)
+{
+    return moveCursorToEnd ();
+}
+
+gboolean
+FullPinyinEditor::moveCursorToBegin (void)
+{
+    if (G_UNLIKELY (m_cursor == 0))
+        return FALSE;
+
+    m_cursor = 0;
+    m_pinyin.removeAll ();
+    m_pinyin_len = 0;
+
+    return TRUE;
+}
+
+gboolean
+FullPinyinEditor::moveCursorToEnd (void)
+{
+    if (G_UNLIKELY (m_cursor == m_text.length ()))
+        return FALSE;
+
+    m_cursor = m_text.length ();
+    updatePinyin  ();
+
+    return TRUE;
+}
+
+void
+FullPinyinEditor::updatePinyin (void)
+{
+    if (G_UNLIKELY (m_text.isEmpty ())) {
+        m_pinyin.removeAll ();
+        m_pinyin_len = 0;
+    }
+    else {
+        m_pinyin_len = m_parser.parse (m_text,
+                                       m_cursor,
+                                       Config::option (),
+                                       m_pinyin,
+                                       MAX_PHRASE_LEN);
+    }
+}
+
+};
+
+
diff --git a/src/FullPinyinEditor.h b/src/FullPinyinEditor.h
new file mode 100644 (file)
index 0000000..6e7a253
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef __PY_FULL_PINYIN_EDITOR_H_
+#define __PY_FULL_PINYIN_EDITOR_H_
+
+#include "PinyinEditor.h"
+
+namespace PY {
+
+class FullPinyinEditor : public PinyinEditor {
+
+public:
+    FullPinyinEditor (void);
+
+    gboolean insert (gint ch);
+
+    gboolean removeCharBefore (void);
+    gboolean removeCharAfter (void);
+    gboolean removeWordBefore (void);
+    gboolean removeWordAfter (void);
+
+    gboolean moveCursorLeft (void);
+    gboolean moveCursorRight (void);
+    gboolean moveCursorLeftByWord (void);
+    gboolean moveCursorRightByWord (void);
+    gboolean moveCursorToBegin (void);
+    gboolean moveCursorToEnd (void);
+
+    gboolean reset (void) {
+        gboolean retval = FALSE;
+        if (m_cursor != 0) {
+            m_cursor = 0;
+            retval = TRUE;
+        }
+
+        if (m_text.length () != 0) {
+            m_text.truncate (0);
+            retval = TRUE;
+        }
+
+        if (retval)
+            updatePinyin ();
+
+        return retval;
+    }
+
+private:
+    void updatePinyin (void);
+
+};
+
+};
+
+#endif
diff --git a/src/HalfFullConverter.cc b/src/HalfFullConverter.cc
new file mode 100644 (file)
index 0000000..2d0b34e
--- /dev/null
@@ -0,0 +1,98 @@
+
+#include "HalfFullConverter.h"
+
+namespace PY {
+
+const guint
+HalfFullConverter::m_table[][3] = {
+    { 0x0020, 0x3000, 1 },
+    { 0x0021, 0xFF01, 94 },
+    { 0x00A2, 0xFFE0, 2 },
+    { 0x00A5, 0xFFE5, 1 },
+    { 0x00A6, 0xFFE4, 1 },
+    { 0x00AC, 0xFFE2, 1 },
+    { 0x00AF, 0xFFE3, 1 },
+    { 0x20A9, 0xFFE6, 1 },
+    { 0xFF61, 0x3002, 1 },
+    { 0xFF62, 0x300C, 2 },
+    { 0xFF64, 0x3001, 1 },
+    { 0xFF65, 0x30FB, 1 },
+    { 0xFF66, 0x30F2, 1 },
+    { 0xFF67, 0x30A1, 1 },
+    { 0xFF68, 0x30A3, 1 },
+    { 0xFF69, 0x30A5, 1 },
+    { 0xFF6A, 0x30A7, 1 },
+    { 0xFF6B, 0x30A9, 1 },
+    { 0xFF6C, 0x30E3, 1 },
+    { 0xFF6D, 0x30E5, 1 },
+    { 0xFF6E, 0x30E7, 1 },
+    { 0xFF6F, 0x30C3, 1 },
+    { 0xFF70, 0x30FC, 1 },
+    { 0xFF71, 0x30A2, 1 },
+    { 0xFF72, 0x30A4, 1 },
+    { 0xFF73, 0x30A6, 1 },
+    { 0xFF74, 0x30A8, 1 },
+    { 0xFF75, 0x30AA, 2 },
+    { 0xFF77, 0x30AD, 1 },
+    { 0xFF78, 0x30AF, 1 },
+    { 0xFF79, 0x30B1, 1 },
+    { 0xFF7A, 0x30B3, 1 },
+    { 0xFF7B, 0x30B5, 1 },
+    { 0xFF7C, 0x30B7, 1 },
+    { 0xFF7D, 0x30B9, 1 },
+    { 0xFF7E, 0x30BB, 1 },
+    { 0xFF7F, 0x30BD, 1 },
+    { 0xFF80, 0x30BF, 1 },
+    { 0xFF81, 0x30C1, 1 },
+    { 0xFF82, 0x30C4, 1 },
+    { 0xFF83, 0x30C6, 1 },
+    { 0xFF84, 0x30C8, 1 },
+    { 0xFF85, 0x30CA, 6 },
+    { 0xFF8B, 0x30D2, 1 },
+    { 0xFF8C, 0x30D5, 1 },
+    { 0xFF8D, 0x30D8, 1 },
+    { 0xFF8E, 0x30DB, 1 },
+    { 0xFF8F, 0x30DE, 5 },
+    { 0xFF94, 0x30E4, 1 },
+    { 0xFF95, 0x30E6, 1 },
+    { 0xFF96, 0x30E8, 6 },
+    { 0xFF9C, 0x30EF, 1 },
+    { 0xFF9D, 0x30F3, 1 },
+    { 0xFFA0, 0x3164, 1 },
+    { 0xFFA1, 0x3131, 30 },
+    { 0xFFC2, 0x314F, 6 },
+    { 0xFFCA, 0x3155, 6 },
+    { 0xFFD2, 0x315B, 9 },
+    { 0xFFE9, 0x2190, 4 },
+    { 0xFFED, 0x25A0, 1 },
+    { 0xFFEE, 0x25CB, 1 },
+    { 0, 0, 0 },
+};
+
+gunichar
+HalfFullConverter::toFull (gunichar ch)
+{
+    for (guint i = 0; m_table[i][0] != 0; i++) {
+        if (G_UNLIKELY (ch < m_table[i][0]))
+            return ch;
+        if (G_UNLIKELY (ch < m_table[i][0] + m_table[i][2]))
+            return ch + m_table[i][1] - m_table[i][0];
+    }
+    return ch;
+}
+
+gunichar
+HalfFullConverter::toHalf (gunichar ch)
+{
+    for (guint i = 0; m_table[i][0] != 0; i++) {
+        if (G_LIKELY (ch < m_table[i][1]))
+            continue;
+        if (G_LIKELY (ch >= m_table[i][1] + m_table[i][2]))
+            continue;
+        return ch + m_table[i][0] + m_table[i][1];
+    }
+    return ch;
+}
+
+};
+
diff --git a/src/HalfFullConverter.h b/src/HalfFullConverter.h
new file mode 100644 (file)
index 0000000..7a18f6b
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef __PY_HALF_FULL_CONVERTER_H_
+#define __PY_HALF_FULL_CONVERTER_H_
+
+#include <glib.h>
+
+namespace PY {
+
+class HalfFullConverter {
+
+public:
+    static gunichar toFull (gunichar ch);
+    static gunichar toHalf (gunichar ch);
+
+private:
+    const static guint m_table[][3];
+};
+
+};
+#endif
diff --git a/src/LookupTable.h b/src/LookupTable.h
new file mode 100644 (file)
index 0000000..53b9b51
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef __PY_LOOKUP_TABLE_H_
+#define __PY_LOOKUP_TABLE_H_
+
+#include <ibus.h>
+#include "Pointer.h"
+#include "Text.h"
+
+namespace PY {
+
+class LookupTable : public Pointer <IBusLookupTable> {
+public:
+    LookupTable (guint page_size = 10,
+                 guint cursor_pos = 0,
+                 gboolean cursor_visible = TRUE,
+                 gboolean round = FALSE)
+        : Pointer <IBusLookupTable> (ibus_lookup_table_new (page_size, cursor_pos, cursor_visible, round)) { }
+
+    guint pageSize (void) { return ibus_lookup_table_get_page_size (*this); }
+    guint cursorPos (void) { return ibus_lookup_table_get_cursor_pos (*this); }
+
+    gboolean pageUp (void) { return ibus_lookup_table_page_up (*this); }
+    gboolean pageDown (void) { return ibus_lookup_table_page_down (*this); }
+    gboolean cursorUp (void) { return ibus_lookup_table_cursor_up (*this); }
+    gboolean cursorDown (void) { return ibus_lookup_table_cursor_down (*this); }
+
+    void setPageSize (guint size) { ibus_lookup_table_set_page_size (*this, size); }
+    void clear (void) { ibus_lookup_table_clear (*this); }
+
+    void appendCandidate (Text & text) {
+        ibus_lookup_table_append_candidate (*this, text);
+    }
+};
+
+};
+
+#endif
diff --git a/src/Main.cc b/src/Main.cc
new file mode 100644 (file)
index 0000000..acf6c44
--- /dev/null
@@ -0,0 +1,100 @@
+/* vim:set et sts=4: */
+
+#include <ibus.h>
+#include <stdlib.h>
+#include <locale.h>
+#include "Engine.h"
+#include "Pointer.h"
+#include "Bus.h"
+#include "Config.h"
+
+using namespace PY;
+
+#define N_(text) text
+
+static Pointer<IBusFactory> factory;
+
+/* options */
+static gboolean ibus = FALSE;
+static gboolean verbose = FALSE;
+
+static const GOptionEntry entries[] =
+{
+    { "ibus", 'i', 0, G_OPTION_ARG_NONE, &ibus, "component is executed by ibus", NULL },
+    { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "verbose", NULL },
+    { NULL },
+};
+
+
+static void
+ibus_disconnected_cb (IBusBus  *bus,
+                      gpointer  user_data)
+{
+    g_debug ("bus disconnected");
+    ibus_quit ();
+}
+
+
+static void
+start_component (void)
+{
+    Pointer<IBusComponent> component;
+
+    ibus_init ();
+    Bus bus;
+    Config config (bus);
+
+    g_signal_connect (bus, "disconnected", G_CALLBACK (ibus_disconnected_cb), NULL);
+
+    component = ibus_component_new ("org.freedesktop.IBus.Pinyin",
+                                    N_("Pinyin input method"),
+                                    "0.1.0",
+                                    "GPL",
+                                    "Peng Huang <shawn.p.huang@gmail.com>",
+                                    "http://code.google.com/p/ibus/",
+                                    "",
+                                    "ibus-pinyin");
+    ibus_component_add_engine (component,
+                               ibus_engine_desc_new ("pinyin",
+                                                     N_("Pinyin input method"),
+                                                     N_("Pinyin input method"),
+                                                     "zh_CN",
+                                                     "GPL",
+                                                     "Peng Huang <shawn.p.huang@gmail.com>",
+                                                     PKGDATADIR"/icons/ibus-pinyin.svg",
+                                                     "us"));
+
+    factory = ibus_factory_new (ibus_bus_get_connection (bus));
+
+    ibus_factory_add_engine (factory, "pinyin", IBUS_TYPE_PINYIN_ENGINE);
+
+    if (ibus) {
+        ibus_bus_request_name (bus, "org.freedesktop.IBus.Pinyin", 0);
+    }
+    else {
+        ibus_bus_register_component (bus, component);
+    }
+
+    ibus_main ();
+}
+
+int
+main (gint argc, gchar **argv)
+{
+    GError *error = NULL;
+    GOptionContext *context;
+
+    setlocale (LC_ALL, "");
+
+    context = g_option_context_new ("- ibus pinyin engine component");
+
+    g_option_context_add_main_entries (context, entries, "ibus-pinyin");
+
+    if (!g_option_context_parse (context, &argc, &argv, &error)) {
+        g_print ("Option parsing failed: %s\n", error->message);
+        exit (-1);
+    }
+
+    start_component ();
+    return 0;
+}
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..39e6b53
--- /dev/null
@@ -0,0 +1,158 @@
+# vim:set noet ts=4:
+#
+# ibus-pinyin - The Chinese PinYin engine for IBus
+#
+# Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+@MAINTAINER_MODE_FALSE@skip_genpytable=test -f $@ ||
+GENPYTABLE = scripts/genpytable.py
+
+AM_CFLAGS = \
+       @IBUS_CFLAGS@ \
+       @SQLITE_CFLAGS@ \
+       -DPKGDATADIR=\"$(pkgdatadir)\" \
+       $(NULL)
+AM_LDFLAGS = \
+       @IBUS_LIBS@ \
+       @SQLITE_LIBS@ \
+       $(NULL)
+
+AM_CXXFLAGS = $(AM_CFLAGS)
+
+libexec_PROGRAMS = ibus-engine-pinyin
+
+ibus_engine_c_sources = \
+       Config.cc \
+       Database.cc \
+       DoublePinyinEditor.cc \
+       Engine.cc \
+       FullPinyinEditor.cc \
+       HalfFullConverter.cc \
+       Main.cc \
+       PhraseEditor.cc \
+       PinyinEditor.cc \
+       PinyinEngine.cc \
+       PinyinParser.cc \
+       SpecialTable.cc \
+       $(NULL)
+ibus_engine_h_sources = \
+       Array.h \
+       Bus.h \
+       Config.h \
+       Database.h \
+       DoublePinyinEditor.h \
+       DoublePinyinTable.h \
+       Engine.h \
+       FullPinyinEditor.h \
+       HalfFullConverter.h \
+       LookupTable.h \
+       PhraseArray.h \
+       PhraseEditor.h \
+       PinyinArray.h \
+       PinyinEditor.h \
+       PinyinEngine.h \
+       PinyinParser.h \
+       Pointer.h \
+       Property.h \
+       SpecialTable.h \
+       String.h \
+       Table.h \
+       Text.h \
+       Types.h \
+       Util.h \
+       $(NULL)
+ibus_engine_pinyin_SOURCES = \
+       $(ibus_engine_c_sources) \
+       $(ibus_engine_h_sources) \
+       $(NULL)
+ibus_engine_pinyin_CXXFLAGS = \
+       @IBUS_CFLAGS@ \
+       @SQLITE_CFLAGS@ \
+       @UUID_CFLAGS@ \
+       -DGETTEXT_PACKAGE=\"@GETTEXT_PACKAGE@\" \
+       -DPKGDATADIR=\"$(pkgdatadir)\" \
+       -DLIBEXECDIR=\"$(libexecdir)\" \
+       $(NULL)
+ibus_engine_pinyin_LDFLAGS = \
+       @IBUS_LIBS@ \
+       @SQLITE_LIBS@ \
+       @UUID_LIBS@ \
+       $(NULL)
+
+BUILT_SOURCES = \
+       $(ibus_engine_built_c_sources) \
+       $(ibus_engine_built_h_sources) \
+       $(NULL)
+
+# db_DATA = \
+#      py.db \
+#      $(NULL)
+# dbdir = $(pkgdatadir)
+
+component_DATA = \
+       pinyin.xml \
+       $(NULL)
+componentdir = @datadir@/ibus/component
+
+EXTRA_DIST = \
+       pinyin.xml.in \
+       $(NULL)
+
+CLEANFILES = \
+       pinyin.xml \
+       $(NULL)
+
+check_PROGRAMS =
+
+# check_PROGRAMS += test-parser
+# test_parser_SOURCES = \
+#      PinyinParser.cc \
+#      Table.h \
+#      $(NULL)
+# test_parser_CFLAGS = \
+#      $(AM_CFLAGS) \
+#      -DTEST \
+#      $(NULL)
+# 
+# check_PROGRAMS += test-pydatabase
+# test_pydatabase_SOURCES = \
+#      Database.cc \
+#      Database.h \
+#      $(NULL)
+# test_pydatabase_CFLAGS = \
+#      $(AM_CFLAGS) \
+#      -DTEST \
+#      $(NULL)
+
+TESTS = \
+       $(check_PROGRAMS) \
+       $(NULL)
+
+Table.h:
+       $(skip_genpytable) $(PYTHON) $(srcdir)/$(GENPYTABLE) > $@
+
+pinyin.xml: pinyin.xml.in
+       ( \
+               libexecdir=${libexecdir}; \
+               pkgdatadir=${pkgdatadir}; \
+               s=`cat $<`; \
+               eval "echo \"$${s}\""; \
+       ) > $@
+
+test: ibus-engine-pinyin
+       $(builddir)/ibus-engine-pinyin
+
diff --git a/src/PhraseArray.h b/src/PhraseArray.h
new file mode 100644 (file)
index 0000000..f19cd55
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __PY_PHRASE_ARRAY_H_
+#define __PY_PHRASE_ARRAY_H_
+
+#include "Types.h"
+#include "Array.h"
+
+namespace PY {
+
+typedef Array<Phrase> PhraseArray;
+
+};
+
+#endif
diff --git a/src/PhraseEditor.cc b/src/PhraseEditor.cc
new file mode 100644 (file)
index 0000000..83bb553
--- /dev/null
@@ -0,0 +1,157 @@
+#include "Config.h"
+#include "PhraseEditor.h"
+
+namespace PY {
+
+/* init static members */
+Database PhraseEditor::m_database;
+
+PhraseEditor::PhraseEditor (void)
+    : m_candidates (32),
+      m_phrases1 (8),
+      m_string1 (32),
+      m_phrases2 (8),
+      m_string2 (32),
+      m_pinyin (16),
+      m_cursor (0)
+{
+}
+
+PhraseEditor::~PhraseEditor (void)
+{
+}
+
+void
+PhraseEditor::update (const PinyinArray &pinyin)
+{
+    gboolean diff = FALSE;
+
+    if (m_cursor > pinyin.length ()) {
+        diff = TRUE;
+    }
+    else {
+        for (gint i = m_cursor - 1; i >= 0; i--) {
+            if (m_pinyin[i] != pinyin[i]) {
+                diff = TRUE;
+                break;
+            }
+        }
+    }
+
+    m_pinyin = pinyin;
+
+    if (diff) {
+        /* FIXME, should not remove all phrases1 */
+        m_phrases1.removeAll ();
+        m_string1.truncate (0);
+        m_cursor = 0;
+    }
+
+    updateCandidates ();
+    updatePhrases ();
+}
+
+gboolean
+PhraseEditor::resetCandidate (guint i)
+{
+    if (G_UNLIKELY (i >= m_candidates.length ()))
+        return FALSE;
+
+    if (G_UNLIKELY (i == 0 && m_phrases2.length () > 1))
+        return FALSE;
+
+    m_database.remove (m_candidates[i]);
+
+    updateCandidates ();
+    updatePhrases ();
+    return TRUE;
+}
+
+gboolean
+PhraseEditor::selectCandidate (guint i)
+{
+    if (G_LIKELY (i == 0)) {
+        m_phrases1 << m_phrases2;
+        m_string1 << m_string2;
+        m_cursor = m_pinyin.length ();
+    }
+    else {
+        if (m_phrases2.length() > 1)
+            i --;
+
+        if (G_UNLIKELY (i >= m_candidates.length ()))
+            return FALSE;
+
+        m_phrases1 << m_candidates[i];
+        m_string1 << m_candidates[i].phrase;
+        m_cursor += m_candidates[i].len;
+    }
+
+    updateCandidates ();
+    updatePhrases ();
+    return TRUE;
+}
+
+void
+PhraseEditor::updateCandidates (void)
+{
+    gboolean retval;
+    m_candidates.removeAll ();
+
+    guint len = MIN (MAX_PHRASE_LEN, m_pinyin.length () - m_cursor);
+    for (; len > 0; len--) {
+        retval = m_database.query (m_pinyin,
+                                   m_cursor,
+                                   len,
+                                   -1,
+                                   Config::option (),
+                                   m_candidates);
+    }
+}
+
+void
+PhraseEditor::updatePhrases (void)
+{
+    guint begin;
+    guint end;
+    gboolean retval;
+
+    m_phrases2.removeAll ();
+    m_string2.truncate (0);
+
+    if (G_UNLIKELY (m_pinyin.length () == 0))
+        return;
+
+    if (G_LIKELY (m_cursor < m_pinyin.length ())) {
+        m_phrases2 << m_candidates[0];
+
+        begin = m_phrases2[0].len + m_cursor;
+        end = m_pinyin.length ();
+
+        while (begin != end) {
+            for (guint i = MIN (end, begin + MAX_PHRASE_LEN); i > begin; i--) {
+                retval = m_database.query (m_pinyin,
+                                           begin,
+                                           i - begin,
+                                           1,
+                                           Config::option (),
+                                           m_phrases2);
+                if (G_LIKELY (retval > 0)) {
+                    begin += m_phrases2[m_phrases2.length () - 1].len;
+                    break;
+                }
+            }
+            if (retval <= 0)
+                g_debug ("%s", m_pinyin[begin]->text);
+            g_assert (retval > 0);
+        }
+    }
+
+    for (guint i = 0; i < m_phrases2.length (); i++) {
+        m_string2 << m_phrases2[i].phrase;
+    }
+}
+
+};
+
+
diff --git a/src/PhraseEditor.h b/src/PhraseEditor.h
new file mode 100644 (file)
index 0000000..d998e0c
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef __PY_PHRASE_EDITOR_H_
+#define __PY_PHRASE_EDITOR_H_
+
+#include "Database.h"
+#include "PhraseArray.h"
+
+namespace PY {
+
+class PhraseEditor {
+public:
+    PhraseEditor(void);
+    ~PhraseEditor(void);
+
+    const String & string1 (void) const { return m_string1; }
+    const String & string2 (void) const { return m_string2; }
+    const PinyinArray & pinyin (void) const { return m_pinyin; }
+    const PhraseArray & candidates (void) const { return m_candidates; }
+    guint cursor (void) const { return m_cursor; }
+
+    guint candidateNumber (void) const {
+        if (m_phrases2.length () > 1)
+            return m_candidates.length () + 1;
+        return m_candidates.length ();
+    }
+
+    const gchar * candidate (guint i) const {
+        if (G_UNLIKELY (i == 0))
+            return m_string2;
+        if (G_UNLIKELY (m_phrases2.length () > 1))
+            return m_candidates[i - 1].phrase;
+        return m_candidates[i].phrase;
+    }
+
+    gboolean candidateInUserPhease (guint i) const {
+        if (G_UNLIKELY (m_phrases2.length () > 1)) {
+            if (G_UNLIKELY (i == 0))
+                return FALSE;
+            else
+                return m_candidates[i - 1].user_freq > 0 && m_candidates[i - 1].freq == 0;
+        }
+        else {
+            return m_candidates[i].user_freq > 0 && m_candidates[i].freq == 0;
+        }
+    }
+
+    void reset (void) {
+        m_candidates.removeAll ();
+        m_phrases1.removeAll ();
+        m_string1.truncate (0);
+        m_phrases2.removeAll ();
+        m_string2.truncate (0);
+        m_pinyin.removeAll ();
+        m_cursor = 0;
+    }
+
+    void update (const PinyinArray &pinyin);
+    gboolean selectCandidate (guint i);
+    gboolean resetCandidate (guint i);
+    void commit (void) {
+        m_phrases1 << m_phrases2;
+        m_database.commit (m_phrases1);
+        reset ();
+    }
+
+    gboolean isEmpty (void) const {
+        return m_string1.isEmpty () && m_string2.isEmpty ();
+    }
+
+    operator gboolean (void) const {
+        return !isEmpty ();
+    }
+
+private:
+    void updateCandidates (void);
+    void updatePhrases (void);
+
+private:
+    PhraseArray m_candidates;   // candidates phrase array
+    PhraseArray m_phrases1;     // phrases before cursor
+    String      m_string1;      // phrases before cursor as string
+    PhraseArray m_phrases2;     // phrases after cursor
+    String      m_string2;      // phrases before cursor as string
+    PinyinArray m_pinyin;
+    guint m_cursor;
+
+private:
+    static Database m_database;
+};
+
+};
+
+#endif
diff --git a/src/PinyinArray.h b/src/PinyinArray.h
new file mode 100644 (file)
index 0000000..fb58fa6
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __PY_PINYIN_ARRAY_H_
+#define __PY_PINYIN_ARRAY_H_
+
+#include "Types.h"
+#include "Array.h"
+
+namespace PY {
+
+typedef Array<const Pinyin *> PinyinArray;
+
+};
+
+#endif
diff --git a/src/PinyinEditor.cc b/src/PinyinEditor.cc
new file mode 100644 (file)
index 0000000..fd4760c
--- /dev/null
@@ -0,0 +1,20 @@
+#include "Config.h"
+#include "PinyinEditor.h"
+
+namespace PY {
+
+#define MAX_PINYIN_LEN 64
+
+
+PinyinParser PinyinEditor::m_parser;
+
+PinyinEditor::PinyinEditor (void)
+    : m_text (MAX_PINYIN_LEN),
+      m_cursor (0),
+      m_pinyin (MAX_PHRASE_LEN),
+      m_pinyin_len (0)
+{
+}
+
+};
+
diff --git a/src/PinyinEditor.h b/src/PinyinEditor.h
new file mode 100644 (file)
index 0000000..3ad2405
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef __PY_PINYIN_EDITOR_H_
+#define __PY_PINYIN_EDITOR_H_
+
+#include <glib.h>
+#include "String.h"
+#include "PinyinParser.h"
+
+#define MAX_PINYIN_LEN 64
+
+namespace PY {
+
+class PinyinEditor {
+public:
+    PinyinEditor (void);
+    
+    const String & text (void) const { return m_text; }
+    const gchar * textAfterPinyin (void) const { return (const gchar *)m_text + m_pinyin_len; }
+    const gchar * textAfterCursor (void) const { return (const gchar *)m_text + m_cursor; }
+    guint cursor (void) const { return m_cursor; }
+    gboolean isEmpty (void) const { return m_text.isEmpty (); }
+    const PinyinArray & pinyin (void) const { return m_pinyin; }
+    guint pinyinLength (void) const { return m_pinyin_len; }
+    operator gboolean (void) const { return !isEmpty (); }
+
+    /* virtual functions */
+    virtual gboolean insert (gint ch) = 0;
+    virtual gboolean removeCharBefore (void) = 0;
+    virtual gboolean removeCharAfter (void) = 0;
+    virtual gboolean removeWordBefore (void) = 0;
+    virtual gboolean removeWordAfter (void) = 0;
+    virtual gboolean moveCursorLeft (void) = 0;
+    virtual gboolean moveCursorRight (void) = 0;
+    virtual gboolean moveCursorLeftByWord (void) = 0;
+    virtual gboolean moveCursorRightByWord (void) = 0;
+    virtual gboolean moveCursorToBegin (void) = 0;
+    virtual gboolean moveCursorToEnd (void) = 0;
+    virtual gboolean reset (void) = 0;
+
+protected:
+    String      m_text;         // text buffer
+    guint       m_cursor;       // cursor pos in char
+    PinyinArray m_pinyin;       // pinyin array
+    guint       m_pinyin_len;   // pinyin length in char
+
+protected:
+    static PinyinParser m_parser; 
+
+};
+
+};
+
+#endif
diff --git a/src/PinyinEngine.cc b/src/PinyinEngine.cc
new file mode 100644 (file)
index 0000000..9687410
--- /dev/null
@@ -0,0 +1,680 @@
+/* vim:set et sts=4: */
+
+#include <ibus.h>
+#include <string.h>
+#include <libintl.h>
+#include "FullPinyinEditor.h"
+#include "DoublePinyinEditor.h"
+#include "PinyinEngine.h"
+#include "HalfFullConverter.h"
+#include "Config.h"
+#include "Text.h"
+#include "Util.h"
+
+#define _(text) (dgettext (GETTEXT_PACKAGE, text))
+
+namespace PY {
+
+/* constructor */
+PinyinEngine::PinyinEngine (IBusEngine *engine)
+    : m_engine (engine),
+      m_pinyin_editor (NULL),
+      m_need_update (0),
+      m_lookup_table (Config::pageSize ()),
+      m_mode_chinese (Config::initChinese ()),
+      m_mode_full (Config::initFull ()),
+      m_mode_full_punct (Config::initFullPunct ()),
+      m_quote (TRUE),
+      m_double_quote (TRUE),
+      m_prev_pressed_key (0)
+{
+    /* */
+    if (Config::doublePinyin ())
+        m_pinyin_editor = new DoublePinyinEditor ();
+    else
+        m_pinyin_editor = new FullPinyinEditor ();
+
+    /* create properties */
+    m_prop_chinese = ibus_property_new ("mode.chinese",
+                                        PROP_TYPE_NORMAL,
+                                        Text ("CN"),
+                                        m_mode_chinese ?
+                                            PKGDATADIR"/icons/chinese.svg" :
+                                            PKGDATADIR"/icons/english.svg",
+                                        Text (_("Chinese")),
+                                        TRUE,
+                                        TRUE,
+                                        PROP_STATE_UNCHECKED,
+                                        NULL);
+    m_props.append (m_prop_chinese);
+
+    m_prop_full = ibus_property_new ("mode.full",
+                                     PROP_TYPE_NORMAL,
+                                     Text (m_mode_full? "Aa" : "Aa"),
+                                     m_mode_full ?
+                                        PKGDATADIR"/icons/full.svg" :
+                                        PKGDATADIR"/icons/half.svg",
+                                     Text (_("Full/Half width")),
+                                     TRUE,
+                                     TRUE,
+                                     PROP_STATE_UNCHECKED,
+                                     NULL);
+    m_props.append (m_prop_full);
+
+    m_prop_full_punct = ibus_property_new ("mode.full_punct",
+                                           PROP_TYPE_NORMAL,
+                                           Text (m_mode_full_punct ? ",。" : ",."),
+                                           m_mode_full_punct ?
+                                           PKGDATADIR"/icons/full-punct.svg" :
+                                                PKGDATADIR"/icons/half-punct.svg",
+                                           Text (_("Full/Half width punctuation")),
+                                           TRUE,
+                                           TRUE,
+                                           PROP_STATE_UNCHECKED,
+                                           NULL);
+    m_props.append (m_prop_full_punct);
+
+    m_prop_setup = ibus_property_new ("setup",
+                                      PROP_TYPE_NORMAL,
+                                      Text (_("Pinyin preferences")),
+                                      "gtk-preferences",
+                                      Text (_("Pinyin preferences")),
+                                      TRUE,
+                                      TRUE,
+                                      PROP_STATE_UNCHECKED,
+                                      NULL);
+    m_props.append (m_prop_setup);
+
+}
+
+/* destructor */
+PinyinEngine::~PinyinEngine (void)
+{
+    delete m_pinyin_editor;
+}
+
+#define MASK_FILTER(modifiers)          \
+    (modifiers & (IBUS_CONTROL_MASK |   \
+                  IBUS_MOD1_MASK |      \
+                  IBUS_SUPER_MASK |     \
+                  IBUS_HYPER_MASK |     \
+                  IBUS_META_MASK))
+
+/**
+ * process ascii letter
+ */
+inline gboolean
+PinyinEngine::processPinyin (guint keyval, guint keycode, guint modifiers)
+{
+    if (G_UNLIKELY (MASK_FILTER(modifiers) != 0))
+        return FALSE;
+
+    if (G_UNLIKELY (m_mode_chinese == FALSE)) {
+        if (G_LIKELY (m_mode_full))
+            commit (HalfFullConverter::toFull (keyval));
+        else
+            commit ((gchar) keyval);
+        return TRUE;
+    }
+
+    if (m_pinyin_editor->insert (keyval))
+        update (FALSE);
+    return TRUE;
+}
+
+inline gboolean
+PinyinEngine::processNumber (guint keyval, guint keycode, guint modifiers)
+{
+    /* English mode */
+    if (G_UNLIKELY (!m_mode_chinese)) {
+        commit ((gunichar) m_mode_full ? HalfFullConverter::toFull (keyval) : keyval);
+        return TRUE;
+    }
+
+    /* Chinese mode, if empty */
+    if (G_UNLIKELY (m_pinyin_editor->isEmpty ())) {
+        if (G_UNLIKELY (MASK_FILTER (modifiers) != 0))
+            return FALSE;
+        commit ((gunichar) m_mode_full ? HalfFullConverter::toFull (keyval) : keyval);
+        return TRUE;
+    }
+
+    /* Chinese mode, if has candidates */
+    guint i;
+    if (G_UNLIKELY (keyval == IBUS_0))
+        i = 10;
+    else
+        i = keyval - IBUS_1;
+
+    if (modifiers == 0)
+        selectCandidate (i);
+    else if ((modifiers & ~ IBUS_LOCK_MASK) == IBUS_CONTROL_MASK)
+        resetCandidate (i);
+    return TRUE;
+}
+
+inline gboolean
+PinyinEngine::processPunct (guint keyval, guint keycode, guint modifiers)
+{
+    if (G_UNLIKELY (MASK_FILTER(modifiers) != 0))
+        return FALSE;
+
+    /* English mode */
+    if (G_UNLIKELY (!m_mode_chinese)) {
+        if (G_UNLIKELY (m_mode_full))
+            commit (HalfFullConverter::toFull (keyval));
+        else
+            commit (keyval);
+        return TRUE;
+    }
+
+    /* Chinese mode */
+    if (G_UNLIKELY (isEmpty ())) {
+        if (m_mode_full_punct) {
+            switch (keyval) {
+            case '.':
+                commit ("。"); break;
+            case '\\':
+                commit ("、"); break;
+            case '^':
+                commit ("……"); break;
+            case '_':
+                commit ("——"); break;
+            case '$':
+                commit ("¥"); break;
+            case '<':
+                commit ("《"); break;
+            case '>':
+                commit ("》"); break;
+            case '"':
+                commit (m_double_quote ? "“" : "”");
+                m_double_quote = !m_double_quote;
+                break;
+            case '\'':
+                commit (m_quote ? "‘" : "’");
+                m_quote = !m_quote;
+                break;
+            default:
+                commit (HalfFullConverter::toFull (keyval));
+                break;
+            }
+        }
+        else {
+            commit (keyval);
+        }
+        return TRUE;
+    }
+
+    switch (keyval) {
+    case IBUS_space:
+        commit (); return TRUE;
+    case IBUS_apostrophe:
+        return processPinyin (keyval, keycode, modifiers);
+    case IBUS_comma:
+        if (Config::commaPeriodPage ())
+            pageUp ();
+        return TRUE;
+    case IBUS_minus:
+        if (Config::minusEqualPage ())
+            pageUp ();
+        return TRUE;
+    case IBUS_period:
+        if (Config::commaPeriodPage ())
+            pageDown ();
+        return TRUE;
+    case IBUS_equal:
+        if (Config::minusEqualPage ())
+            pageDown ();
+        return TRUE;
+    case IBUS_semicolon:
+        /* double pinyin need process ';' */
+        if (G_UNLIKELY (Config::doublePinyin ()))
+            return processPinyin (keyval, keycode, modifiers);
+        return TRUE;
+    default:
+        return TRUE;
+    }
+}
+
+inline gboolean
+PinyinEngine::processOthers (guint keyval, guint keycode, guint modifiers)
+{
+    if (G_UNLIKELY (isEmpty ()))
+        return FALSE;
+
+    /* process some cursor control keys */
+    gboolean _update = FALSE;
+    switch (keyval) {
+    case IBUS_Return:
+        if (G_UNLIKELY (m_mode_full)) {
+            m_buffer.truncate (0);
+            for (const gchar *p = m_pinyin_editor->text (); *p != 0; p++) {
+                m_buffer.appendUnichar (HalfFullConverter::toFull (*p));
+            }
+            commit (m_buffer);
+        }
+        else {
+            commit (m_pinyin_editor->text ());
+        }
+        m_pinyin_editor->reset ();
+        _update = TRUE;
+        break;
+
+    case IBUS_BackSpace:
+        if (G_LIKELY (modifiers == 0))
+            _update = m_pinyin_editor->removeCharBefore ();
+        else if (G_LIKELY (modifiers == IBUS_CONTROL_MASK))
+            _update = m_pinyin_editor->removeWordBefore ();
+        break;
+
+    case IBUS_Delete:
+        if (G_LIKELY (modifiers == 0))
+            _update = m_pinyin_editor->removeCharAfter ();
+        else if (G_LIKELY (modifiers == IBUS_CONTROL_MASK))
+            _update = m_pinyin_editor->removeWordAfter ();
+        break;
+
+    case IBUS_Left:
+        if (G_LIKELY (modifiers == 0)) {
+            // move left single char
+            _update = m_pinyin_editor->moveCursorLeft ();
+        }
+        else if (G_LIKELY (modifiers == IBUS_CONTROL_MASK)) {
+            // move left one pinyin
+            _update = m_pinyin_editor->moveCursorLeftByWord ();
+        }
+        break;
+
+    case IBUS_Right:
+        if (G_LIKELY (modifiers == 0)) {
+            // move right single char
+            _update = m_pinyin_editor->moveCursorRight ();
+        }
+        else if (G_LIKELY (modifiers == IBUS_CONTROL_MASK)) {
+            // move right to end
+            _update = m_pinyin_editor->moveCursorToEnd ();
+        }
+        break;
+
+    case IBUS_Home:
+        if (G_LIKELY (modifiers == 0)) {
+            // move to begin
+            _update = m_pinyin_editor->moveCursorToBegin ();
+        }
+        break;
+
+    case IBUS_End:
+        if (G_LIKELY (modifiers == 0)) {
+            // move to end
+            _update = m_pinyin_editor->moveCursorToEnd ();
+        }
+        break;
+
+    case IBUS_Up:
+        cursorUp (); break;
+    case IBUS_Down:
+        cursorDown (); break;
+    case IBUS_Page_Up:
+        pageUp (); break;
+    case IBUS_Page_Down:
+        pageDown (); break;
+    case IBUS_Escape:
+        reset (); break;
+    }
+    if (G_LIKELY (_update))
+        update (FALSE);
+    return TRUE;
+}
+
+gboolean
+PinyinEngine::processKeyEvent (guint keyval, guint keycode, guint modifiers)
+{
+    gboolean retval = FALSE;
+
+    // ignore release event
+    if (modifiers & IBUS_RELEASE_MASK) {
+        if (m_prev_pressed_key != keyval)
+            return TRUE;
+
+        switch (keyval) {
+        case IBUS_Shift_L:
+        case IBUS_Shift_R:
+            if (isEmpty ())
+                toggleModeChinese ();
+            return TRUE;
+        default:
+            return TRUE;
+        }
+    }
+
+    modifiers &= (IBUS_SHIFT_MASK |
+                  IBUS_CONTROL_MASK |
+                  IBUS_MOD1_MASK |
+                  IBUS_SUPER_MASK |
+                  IBUS_HYPER_MASK |
+                  IBUS_META_MASK |
+                  IBUS_LOCK_MASK);
+
+    switch (keyval) {
+    /* letters */
+    case IBUS_a ... IBUS_z:
+    case IBUS_A ... IBUS_Z:
+        retval = processPinyin (keyval, keycode, modifiers);
+        break;
+    /* numbers */
+    case IBUS_0 ... IBUS_9:
+        retval = processNumber (keyval, keycode, modifiers);
+        break;
+    /* punct */
+    case IBUS_space ... IBUS_slash:
+    case IBUS_colon ... IBUS_at:
+    case IBUS_bracketleft ... IBUS_quoteleft:
+    case IBUS_braceleft ... IBUS_asciitilde:
+        retval = processPunct (keyval, keycode, modifiers);
+        break;
+    /* others */
+    default:
+        retval = processOthers (keyval, keycode, modifiers);
+        break;
+    }
+
+    m_prev_pressed_key = keyval;
+    return retval;
+}
+
+void
+PinyinEngine::focusIn (void)
+{
+    if (Config::doublePinyin ()) {
+        if (dynamic_cast <DoublePinyinEditor *> (m_pinyin_editor) == NULL)
+            delete m_pinyin_editor;
+        m_pinyin_editor = new DoublePinyinEditor ();
+    }
+    else {
+        if (dynamic_cast <FullPinyinEditor *> (m_pinyin_editor) == NULL)
+            delete m_pinyin_editor;
+        m_pinyin_editor = new FullPinyinEditor ();
+    }
+
+    resetQuote ();
+    ibus_engine_register_properties (m_engine, m_props);
+}
+
+
+void
+PinyinEngine::pageUp (void)
+{
+    if (m_lookup_table.pageUp ()) {
+        ibus_engine_update_lookup_table_fast (m_engine, m_lookup_table, TRUE);
+    }
+}
+
+void
+PinyinEngine::pageDown (void)
+{
+    if (m_lookup_table.pageDown ()) {
+        ibus_engine_update_lookup_table_fast (m_engine, m_lookup_table, TRUE);
+    }
+}
+
+void
+PinyinEngine::cursorUp (void)
+{
+    if (m_lookup_table.cursorUp ()) {
+        ibus_engine_update_lookup_table_fast (m_engine, m_lookup_table, TRUE);
+    }
+}
+
+void
+PinyinEngine::cursorDown (void)
+{
+    if (m_lookup_table.cursorDown ()) {
+        ibus_engine_update_lookup_table_fast (m_engine, m_lookup_table, TRUE);
+    }
+}
+
+inline void
+PinyinEngine::toggleModeChinese (void)
+{
+    m_mode_chinese = ! m_mode_chinese;
+    m_prop_chinese.setLabel (m_mode_chinese ? "CN" : "EN");
+    m_prop_chinese.setIcon (m_mode_chinese ?
+                                PKGDATADIR"/icons/chinese.svg" :
+                                PKGDATADIR"/icons/english.svg");
+    ibus_engine_update_property (m_engine, m_prop_chinese);
+
+    m_prop_full_punct.setSensitive (m_mode_chinese);
+    ibus_engine_update_property (m_engine, m_prop_full_punct);
+}
+
+inline void
+PinyinEngine::toggleModeFull (void)
+{
+    m_mode_full = !m_mode_full;
+    m_prop_full.setLabel (m_mode_full ? "Aa" : "Aa");
+    m_prop_full.setIcon (m_mode_full ?
+                            PKGDATADIR"/icons/full.svg" :
+                            PKGDATADIR"/icons/half.svg");
+    ibus_engine_update_property (m_engine, m_prop_full);
+}
+
+inline void
+PinyinEngine::toggleModeFullPunct (void)
+{
+    m_mode_full_punct = !m_mode_full_punct;
+    m_prop_full_punct.setLabel (m_mode_full_punct ? ",。" : ",.");
+    m_prop_full_punct.setIcon (m_mode_full_punct ?
+                                    PKGDATADIR"/icons/full-punct.svg" :
+                                    PKGDATADIR"/icons/half-punct.svg");
+    ibus_engine_update_property (m_engine, m_prop_full_punct);
+}
+
+inline void
+PinyinEngine::showSetupDialog (void)
+{
+    g_spawn_command_line_async (LIBEXECDIR"/ibus-setup-pinyin", NULL);
+}
+
+void
+PinyinEngine::propertyActivate (const gchar *prop_name, guint prop_state)
+{
+    const static StaticString mode_chinese ("mode.chinese");
+    const static StaticString mode_full ("mode.full");
+    const static StaticString mode_full_punct ("mode.full_punct");
+    const static StaticString setup ("setup");
+
+    if (mode_chinese == prop_name) {
+        toggleModeChinese ();
+    }
+    else if (mode_full == prop_name) {
+        toggleModeFull ();
+    }
+    else if (mode_full_punct == prop_name) {
+        toggleModeFullPunct ();
+    }
+    else if (setup == prop_name) {
+        showSetupDialog ();
+    }
+}
+
+void
+PinyinEngine::updatePreeditText (void)
+{
+    if (G_UNLIKELY (m_phrase_editor.isEmpty () && m_pinyin_editor->isEmpty ())) {
+        ibus_engine_hide_preedit_text (m_engine);
+        return;
+    }
+
+    m_buffer.truncate (0);
+    if (G_UNLIKELY (m_phrase_editor.string1 ()))
+        m_buffer << m_phrase_editor.string1 () << ' ';
+
+    m_buffer << m_phrase_editor.string2 ()
+             << m_pinyin_editor->textAfterPinyin ();
+
+    Text preedit_text (m_buffer);
+    preedit_text.appendAttribute (IBUS_ATTR_TYPE_UNDERLINE, IBUS_ATTR_UNDERLINE_SINGLE, 0, -1);
+    ibus_engine_update_preedit_text (m_engine, preedit_text, m_buffer.length (), TRUE);
+}
+
+void
+PinyinEngine::updateAuxiliaryText (void)
+{
+
+    /* clear pinyin array */
+    if (G_UNLIKELY (isEmpty ())) {
+        ibus_engine_hide_auxiliary_text (m_engine);
+        return;
+    }
+
+    guint cursor_pos;
+
+    m_buffer.truncate (0);
+    if (G_UNLIKELY (m_phrase_editor.string1 ())) {
+        m_buffer << m_phrase_editor.string1 ();
+    }
+
+    for (guint i = m_phrase_editor.cursor (); i < m_pinyin_editor->pinyin().length (); ++i) {
+        if (G_LIKELY (i != m_phrase_editor.cursor ()))
+            m_buffer << '\'';
+        const Pinyin *p = m_pinyin_editor->pinyin()[i];
+        m_buffer << p->sheng;
+        m_buffer << p->yun;
+    }
+
+    if (G_UNLIKELY (m_pinyin_editor->pinyinLength () == m_pinyin_editor->cursor ())) {
+        /* aux = pinyin + non-pinyin */
+        cursor_pos =  m_buffer.utf8Length ();
+        m_buffer << '|' << m_pinyin_editor->textAfterPinyin ();
+    }
+    else {
+        /* aux = pinyin + non-pinyin before cursor + non-pinyin after cursor */
+        m_buffer.append (m_pinyin_editor->textAfterPinyin (),
+                     m_pinyin_editor->cursor () - m_pinyin_editor->pinyinLength ());
+        cursor_pos =  m_buffer.utf8Length ();
+        m_buffer  << '|' << m_pinyin_editor->textAfterCursor ();
+    }
+
+    Text aux_text (m_buffer);
+    /*
+    aux_text.appendAttribute (IBUS_ATTR_TYPE_FOREGROUND, 0x00afafaf, len, cursor_pos);
+    aux_text.appendAttribute (IBUS_ATTR_TYPE_FOREGROUND, 0x00afafaf, cursor_pos + 1, -1);
+    */
+    ibus_engine_update_auxiliary_text (m_engine, aux_text, TRUE);
+}
+
+void
+PinyinEngine::updateLookupTable (void)
+{
+    m_lookup_table.clear ();
+    m_lookup_table.setPageSize (Config::pageSize ());
+
+    guint candidate_nr = m_phrase_editor.candidateNumber ();
+
+    if (G_UNLIKELY (candidate_nr == 0)) {
+        ibus_engine_hide_lookup_table (m_engine);
+        return;
+    }
+
+    for (guint i = 0; i < candidate_nr; i++) {
+        //const Phrase &phrase = m_phrase_editor.candidates()[i];
+        Text text (m_phrase_editor.candidate (i));
+        if (m_phrase_editor.candidateInUserPhease (i))
+            text.appendAttribute (IBUS_ATTR_TYPE_FOREGROUND, 0x000000ef, 0, -1);
+        m_lookup_table.appendCandidate (text);
+    }
+
+    ibus_engine_update_lookup_table_fast (m_engine,
+                                          m_lookup_table,
+                                          TRUE);
+}
+
+void
+PinyinEngine::updatePhraseEditor (void)
+{
+    m_phrase_editor.update (m_pinyin_editor->pinyin ());
+}
+
+inline void
+PinyinEngine::commit (gchar ch)
+{
+    gchar str[2] = {ch, 0};
+    ibus_engine_commit_text (m_engine, Text (str));
+}
+
+inline void
+PinyinEngine::commit (gunichar ch)
+{
+    ibus_engine_commit_text (m_engine, Text (ch));
+}
+
+inline void
+PinyinEngine::commit (const gchar *str)
+{
+    ibus_engine_commit_text (m_engine, Text (str));
+}
+
+inline void
+PinyinEngine::commit (const String &str)
+{
+    commit ((const gchar *)str);
+}
+
+inline void
+PinyinEngine::commit (void)
+{
+    if (G_UNLIKELY (m_pinyin_editor->isEmpty ()))
+        return;
+
+    m_buffer.truncate (0);
+    m_buffer << m_phrase_editor.string1 () << m_phrase_editor.string2 ();
+    const gchar *p = m_pinyin_editor->textAfterPinyin ();
+    if (G_UNLIKELY (m_mode_full)) {
+        while (*p != 0)
+            m_buffer.appendUnichar (HalfFullConverter::toFull (*p++));
+    }
+    else {
+        m_buffer << p;
+    }
+    commit ((const gchar *)m_buffer);
+    m_phrase_editor.commit ();
+    reset ();
+}
+
+inline gboolean
+PinyinEngine::selectCandidate (guint i)
+{
+    guint page_size = m_lookup_table.pageSize ();
+    guint cursor_pos = m_lookup_table.cursorPos ();
+    i += (cursor_pos / page_size) * page_size;
+
+    if (m_phrase_editor.selectCandidate (i)) {
+        if (G_UNLIKELY (m_phrase_editor.cursor () == m_pinyin_editor->pinyin ().length ())) {
+            commit ();
+        }
+        else {
+            updatePreeditText ();
+            updateAuxiliaryText ();
+            updateLookupTable ();
+        }
+    }
+    return TRUE;
+}
+
+inline gboolean
+PinyinEngine::resetCandidate (guint i)
+{
+    guint page_size = m_lookup_table.pageSize ();
+    guint cursor_pos = m_lookup_table.cursorPos ();
+    i += (cursor_pos / page_size) * page_size;
+
+    if (m_phrase_editor.resetCandidate (i)) {
+        updatePreeditText ();
+        updateAuxiliaryText ();
+        updateLookupTable ();
+    }
+    return TRUE;
+}
+
+};
+
diff --git a/src/PinyinEngine.h b/src/PinyinEngine.h
new file mode 100644 (file)
index 0000000..6472302
--- /dev/null
@@ -0,0 +1,121 @@
+/* vim:set et sts=4: */
+#ifndef __PY_PIN_YIN_ENGINE_H__
+#define __PY_PIN_YIN_ENGINE_H__
+
+#include <ibus.h>
+#include "Pointer.h"
+#include "Database.h"
+#include "FullPinyinEditor.h"
+#include "PhraseEditor.h"
+#include "LookupTable.h"
+#include "Property.h"
+#include "Config.h"
+
+namespace PY {
+
+class PinyinEngine {
+public:
+    PinyinEngine (IBusEngine *engine);
+    ~PinyinEngine (void);
+
+    gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
+    void focusIn (void);
+    void focusOut (void) {}
+
+    void reset (gboolean need_update = TRUE) {
+        m_pinyin_editor->reset ();
+        update (need_update);
+    }
+
+    void resetQuote (void) {
+        m_quote = TRUE;
+        m_double_quote = TRUE;
+    }
+
+    void enable (void) {}
+    void disable (void) {}
+    void pageUp (void);
+    void pageDown (void);
+    void cursorUp (void);
+    void cursorDown (void);
+
+    void propertyActivate (const gchar *prop_name, guint prop_state);
+
+    void update (gboolean now = TRUE) {
+        if (G_UNLIKELY (now || m_need_update >= 4)) {
+            updatePhraseEditor ();
+            updateLookupTable ();
+            updateAuxiliaryText ();
+            updatePreeditText ();
+            m_need_update = 0;
+        } else {
+            if (m_need_update == 0) {
+                g_idle_add ((GSourceFunc) delayUpdateHandler, this);
+            }
+            m_need_update ++;
+        }
+    }
+
+private:
+    gboolean processPinyin (guint keyval, guint keycode, guint modifiers);
+    gboolean processNumber (guint keyval, guint keycode, guint modifiers);
+    gboolean processPunct (guint keyval, guint keycode, guint modifiers);
+    gboolean processOthers (guint keyval, guint keycode, guint modifiers);
+
+private:
+    gboolean isEmpty (void) { return m_pinyin_editor->isEmpty (); }
+
+    void commit (void);
+    void commit (gchar ch);
+    void commit (gunichar ch);
+    void commit (const gchar *str);
+    void commit (const String &str);
+
+    void toggleModeChinese (void);
+    void toggleModeFull (void);
+    void toggleModeFullPunct (void);
+    void showSetupDialog (void);
+
+    gboolean selectCandidate (guint i);
+    gboolean resetCandidate (guint i);
+    void updatePreeditText (void);
+    void updateAuxiliaryText (void);
+    void updateLookupTable (void);
+    void updatePhraseEditor (void);
+
+    static gboolean delayUpdateHandler (PinyinEngine *pinyin) {
+        if (pinyin->m_need_update > 0)
+            pinyin->update (TRUE);
+        return FALSE;
+    }
+
+private:
+    Pointer<IBusEngine>  m_engine;      // engine pointer
+
+    PinyinEditor *m_pinyin_editor;      // pinyin editor
+    PhraseEditor m_phrase_editor;       // phrase editor
+    String m_buffer;                    // string buffer
+
+    gint m_need_update;                 // need update preedit, aux, or lookup table
+
+    LookupTable m_lookup_table;
+    Property    m_prop_chinese;
+    Property    m_prop_full;
+    Property    m_prop_full_punct;
+    Property    m_prop_setup;
+    PropList    m_props;
+
+    gboolean m_mode_chinese;
+    gboolean m_mode_full;
+    gboolean m_mode_full_punct;
+
+    gboolean m_quote;
+    gboolean m_double_quote;
+
+    guint    m_prev_pressed_key;
+
+};
+
+};
+
+#endif
diff --git a/src/PinyinParser.cc b/src/PinyinParser.cc
new file mode 100644 (file)
index 0000000..2bdfa49
--- /dev/null
@@ -0,0 +1,243 @@
+/* vim:set et sts=4: */
+#include <string.h>
+#include <stdlib.h>
+#include <glib.h>
+#include "Table.h"
+#include "PinyinParser.h"
+
+namespace PY {
+
+static int
+py_cmp (const void *p1, const void *p2)
+{
+    const gchar *str = (const gchar *) p1;
+    const Pinyin *py = (const Pinyin *) p2;
+
+    return strcmp (str, py->text);
+}
+
+static const Pinyin *
+is_pinyin (const gchar *p,
+           const gchar *end,
+           gint         len,
+           guint        option)
+{
+    gchar buf[7];
+    const Pinyin *result;
+
+    if (G_UNLIKELY (len > 6))
+        return NULL;
+
+    if (G_UNLIKELY (len > end - p))
+        return NULL;
+
+    if (G_LIKELY (len > 0)) {
+        strncpy (buf, p, len);
+        buf[len] = 0;
+        result = (const Pinyin *) bsearch (buf, pinyin_table, PINYIN_TABLE_NR,
+                                            sizeof (Pinyin), py_cmp);
+        if (G_UNLIKELY (result == NULL))
+            return NULL;
+        if (G_LIKELY (result->flags == 0))
+            return result;
+        if(G_LIKELY (result->flags & option))
+            return result;
+        return NULL;
+    }
+
+    len = strnlen (p, 6);
+    len = MIN (len, end - p);
+    strncpy (buf, p, len);
+
+    for (; len > 0; len --) {
+        buf[len] = 0;
+        result = (const Pinyin *) bsearch (buf, pinyin_table, PINYIN_TABLE_NR,
+                                            sizeof (Pinyin), py_cmp);
+        if (G_UNLIKELY (result && ((result->flags == 0) || (result->flags & option)))) {
+            return result;
+        }
+    }
+
+    return NULL;
+}
+
+static int
+sp_cmp (const void *p1,
+        const void *p2)
+{
+    const Pinyin **pys = (const Pinyin **) p1;
+    const Pinyin **e = (const Pinyin **) p2;
+
+    return ((pys[0] - e[0]) << 16) + (pys[1] - e[1]);
+}
+
+static const Pinyin **
+need_resplit(const Pinyin *p1,
+             const Pinyin *p2)
+{
+    const Pinyin * pys[] = {p1, p2};
+
+    return (const Pinyin **) bsearch (pys, special_table, SPECIAL_TABLE_NR,
+                                        sizeof (special_table[0]), sp_cmp);
+}
+
+guint
+PinyinParser::parse (const String   &pinyin,
+                     gint            len,
+                     guint           option,
+                     PinyinArray    &result,
+                     guint           max)
+{
+
+    const gchar *p;
+    const gchar *end;
+    const Pinyin *py;
+    const Pinyin *prev_py;
+    gchar prev_c;
+
+    result.removeAll ();
+
+    if (G_UNLIKELY (len < 0))
+        len = pinyin.length ();
+
+    p = pinyin;
+    end = p + len;
+
+    prev_py = NULL;
+
+    prev_c = 0;
+    for (; p < end && result.length () < max; ) {
+        switch (prev_c) {
+        case 'r':
+        case 'n':
+        case 'g':
+        case 'e':
+            switch (*p) {
+            case 'i':
+            case 'u':
+            case 'v':
+            case 'a':
+            case 'e':
+            case 'o':
+            case 'r':
+                {
+                    const Pinyin **pp;
+                    const Pinyin *new_py1;
+                    const Pinyin *new_py2;
+
+                    py = is_pinyin (p, end, -1, option);
+
+                    if ((new_py1 = is_pinyin (prev_py->text,
+                                              prev_py->text + prev_py->len,
+                                              prev_py->len - 1,
+                                              option)) != NULL) {
+                        new_py2 = is_pinyin (p -1, end, -1, option);
+
+                        if (((new_py2 != NULL) && (new_py2->len > 1 )) &&
+                            (py == NULL || new_py2->len > py->len + 1)) {
+                            result[result.length () - 1] = new_py1;
+                            py = new_py2;
+                            p --;
+                            break;
+                        }
+                    }
+
+                    if ( py == NULL)
+                        break;
+
+                    pp = need_resplit (prev_py, py);
+                    if (pp != NULL) {
+                        result[result.length () - 1] = pp[2];
+                        py = pp[3];
+                        p --;
+                        break;
+                    }
+                }
+            default:
+                py = is_pinyin (p, end, -1, option);
+                break;
+            }
+            break;
+        default:
+            py = is_pinyin (p, end, -1, option);
+            break;
+        }
+
+        if (G_UNLIKELY (py == NULL))
+            break;
+
+        result << py;
+        p += py->len;
+        prev_c = py->text[py->len - 1];
+        prev_py = py;
+
+        if (G_UNLIKELY (*p == '\'')) {
+            prev_c = '\'';
+            p++;
+        }
+    }
+
+    if (G_UNLIKELY (p == (const gchar *)pinyin))
+        return 0;
+#if 0
+    if (G_UNLIKELY (*(p - 1) == '\''))
+        p --;
+#endif
+    return p - (const gchar *)pinyin;
+}
+
+static int
+py_id_cmp (const void *p1, const void *p2)
+{
+    const gint *id = (const gint *) p1;
+    const Pinyin *py = (const Pinyin *) p2;
+
+    return ((id[0] - py->sheng_id) << 16) + (id[1] - py->yun_id);
+}
+
+const Pinyin *
+PinyinParser::isPinyin (gint sheng, gint yun, guint option)
+{
+    const Pinyin *result;
+    gint buf[2] = {sheng, yun};
+
+    result = (const Pinyin *) bsearch (buf, pinyin_table, PINYIN_TABLE_NR,
+                                            sizeof (Pinyin), py_id_cmp);
+    if (result != NULL && result->flags != 0 && (result->flags & option) == 0)
+        return NULL;
+    return result;
+}
+
+};
+
+
+#ifdef TEST
+#include <glib/gprintf.h>
+int main(int argc, char **argv)
+{
+    gint len;
+    GArray *array;
+    Pinyin **p;
+    gchar *str;
+
+    str = "qinaide";
+
+    if (argc > 1)
+        str = argv[1];
+
+    array = g_array_new (TRUE, TRUE, sizeof (Pinyin *));
+
+    len = py_parse_pinyin (str, -1, 0xffffffff, array);
+
+    if (len) {
+        p = (Pinyin **) array->data;
+        while (*p) {
+            g_printf ("%s'", (*p)->text);
+            p ++;
+        }
+    }
+    g_printf ("%s\n", str + len);
+
+    return 0;
+}
+#endif
diff --git a/src/PinyinParser.h b/src/PinyinParser.h
new file mode 100644 (file)
index 0000000..c9ad552
--- /dev/null
@@ -0,0 +1,26 @@
+/* vim:set et sts=4: */
+#ifndef __PY_PARSER_H__
+#define __PY_PARSER_H__
+
+#include <glib.h>
+#include "String.h"
+#include "PinyinArray.h"
+
+namespace PY {
+
+class PinyinParser {
+
+public:
+    PinyinParser (void) {}
+    ~PinyinParser (void) {}
+
+    guint parse (const String &pinyin,      // pinyin string
+                 gint          len,         // length of pinyin string
+                 guint         option,      // option
+                 PinyinArray  &result,      // store pinyin in result
+                 guint         max);        // max length of the result
+    const Pinyin * isPinyin (gint sheng, gint yun, guint option);
+};
+
+};
+#endif
diff --git a/src/Pointer.h b/src/Pointer.h
new file mode 100644 (file)
index 0000000..05de8aa
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef __PY_POINTER_H_
+#define __PY_POINTER_H_
+
+#include <glib-object.h>
+
+namespace PY {
+
+template<typename T>
+class Pointer {
+public:
+    Pointer (T *p = NULL) : m_p (NULL) {
+        set (p);
+    }
+
+    ~Pointer (void) {
+        set (NULL);
+    }
+
+    void set (T * p) {
+        if (m_p) {
+            g_object_unref (m_p);
+        }
+
+        m_p = p;
+        if (p) {
+            // g_debug ("%s, floating = %d",G_OBJECT_TYPE_NAME (p), g_object_is_floating (p));
+            g_object_ref_sink (p);
+        }
+    }
+    
+    Pointer<T> &operator = (T *p) {
+        set (p);
+        return *this;
+    }
+
+    Pointer<T> &operator = (const Pointer<T> & p) {
+        set (p.m_p);
+        return *this;
+    }
+
+    operator T * (void) const {
+        return m_p;
+    }
+    
+    operator gboolean (void) const {
+        return m_p != NULL;
+    }
+
+private:
+    T *m_p;
+};
+
+};
+
+#endif
diff --git a/src/Property.h b/src/Property.h
new file mode 100644 (file)
index 0000000..5237cd7
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef __PY_PROPERTY_H_
+#define __PY_PROPERTY_H_
+
+#include <ibus.h>
+#include "Pointer.h"
+#include "Text.h"
+
+namespace PY {
+
+class Property : public Pointer<IBusProperty> {
+public:
+    Property & operator= (IBusProperty *p) {
+        set (p);
+        return *this;
+    }
+
+    void setLabel (const Text & text) {
+        ibus_property_set_label (*this, text);
+    }
+    void setLabel (const gchar *text) {
+        setLabel (Text (text));
+    }
+    void setIcon (const gchar *icon) {
+        ibus_property_set_icon (*this, icon);
+    }
+    void setSensitive (gboolean sensitive) {
+        ibus_property_set_sensitive (*this, sensitive);
+    }
+};
+
+
+class PropList : public Pointer<IBusPropList> {
+public:
+    PropList (void) : Pointer<IBusPropList> (ibus_prop_list_new ()) { }
+
+    void append (Property &prop) {
+        ibus_prop_list_append (*this, prop);
+    }
+};
+
+};
+
+#endif
diff --git a/src/SpecialTable.cc b/src/SpecialTable.cc
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/SpecialTable.h b/src/SpecialTable.h
new file mode 100644 (file)
index 0000000..43d9d92
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef __PY_SPECIAL_TABLE_H_
+#define __PY_SPECIAL_TABLE_H_
+
+#include <glib.h>
+
+namespace PY {
+
+class SpecialTable {
+public:
+    SpecialTable (void) {}
+private:
+    gboolean load (const gchar *file);
+};
+
+};
+
+#endif
diff --git a/src/String.h b/src/String.h
new file mode 100644 (file)
index 0000000..b473a48
--- /dev/null
@@ -0,0 +1,150 @@
+#ifndef __PY_STRING_H_
+#define __PY_STRING_H_
+#include <glib.h>
+#include <stdarg.h>
+
+namespace PY {
+
+class String {
+public:
+    String (const gchar *init) {
+        m_string = g_string_new (init);
+    }
+
+    String (const gchar *init, gssize len) {
+        m_string = g_string_new_len (init, len);
+    }
+
+    String (gsize init_size = 0) {
+        m_string = g_string_sized_new (init_size);
+    }
+
+    ~String (void) {
+        g_string_free (m_string, TRUE);
+    }
+
+    gsize length (void) const {
+        return m_string->len;
+    }
+
+    gsize utf8Length (void) const {
+        return g_utf8_strlen (m_string->str, m_string->len);
+    }
+
+    gboolean isEmpty (void) const {
+        return m_string->len == 0;
+    }
+
+    String & assign (const gchar *str) {
+        g_string_assign (m_string, str);
+        return *this;
+    }
+
+    String & assign (const String &str) {
+        return assign ((const gchar *) str);
+    }
+
+    String & insert (gint pos, gchar ch) {
+        g_string_insert_c (m_string, pos, ch);
+        return *this;
+    }
+
+    String & append (const gchar *str) {
+        g_string_append (m_string, str);
+        return *this;
+    }
+
+    String & appendUnichar (gunichar ch) {
+        g_string_append_unichar (m_string, ch);
+        return *this;
+    }
+
+    String & append (const gchar *str, gint len) {
+        g_string_append_len (m_string, str, len);
+        return *this;
+    }
+
+    String & printf (const gchar *fmt, ...) {
+        va_list args;
+
+        va_start (args, fmt);
+        g_string_vprintf (m_string, fmt, args);
+        va_end (args);
+
+        return *this;
+    }
+
+    String & appendPrintf (const gchar *fmt, ...) {
+        va_list args;
+
+        va_start (args, fmt);
+        g_string_append_vprintf (m_string, fmt, args);
+        va_end (args);
+
+        return *this;
+    }
+
+    String & truncate (gint len) {
+        g_string_truncate (m_string, len);
+        return *this;
+    }
+
+    String & erase (gint pos, gint len) {
+        g_string_erase (m_string, pos, len);
+        return *this;
+    }
+
+    String & operator = (const gchar *str) {
+        return assign (str);
+    }
+
+    String & operator = (const String &str) {
+        return assign (str);
+    }
+
+    String & operator += (const gchar *str) {
+        return append (str);
+    }
+
+    String & operator << (const gchar *str) {
+        return append (str);
+    }
+
+    String & operator << (const String &str) {
+        return append ((const gchar *) str);
+    }
+
+    String & operator << (gint d) {
+        g_string_append_printf (m_string, "%d", d);
+        return *this;
+    }
+
+    String & operator << (guint d) {
+        g_string_append_printf (m_string, "%u", d);
+        return *this;
+    }
+
+    String & operator << (gchar ch) {
+        g_string_append_c (m_string, ch);
+        return *this;
+    }
+
+    gchar operator[] (guint i) {
+        if (i >= length ())
+            return 0;
+        return m_string->str[i];
+    }
+
+    operator const gchar *() const {
+        return m_string->str;
+    }
+
+    operator gboolean () const {
+        return m_string->len != 0;
+    }
+
+private:
+    GString *m_string;
+};
+};
+#endif
diff --git a/src/Text.h b/src/Text.h
new file mode 100644 (file)
index 0000000..22a5aab
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef __PY_TEXT_H_
+#define __PY_TEXT_H_
+
+#include <ibus.h>
+#include "Pointer.h"
+
+namespace PY {
+
+class Text : public Pointer <IBusText> {
+public:
+    Text (const gchar *str)
+        : Pointer <IBusText> (ibus_text_new_from_static_string (str)) { }
+
+    Text (gunichar ch)
+        : Pointer <IBusText> (ibus_text_new_from_unichar (ch)) { }
+    
+    Text (const String & str)
+        : Pointer <IBusText> (ibus_text_new_from_static_string ((const gchar *) str)) { }
+
+    void appendAttribute (guint type, guint value, guint start, guint end) {
+        ibus_text_append_attribute (*this, type, value, start, end);
+    }
+};
+
+};
+
+#endif
diff --git a/src/Types.h b/src/Types.h
new file mode 100644 (file)
index 0000000..d083f50
--- /dev/null
@@ -0,0 +1,135 @@
+/* vim:set et sts=4: */
+#ifndef __PY_TYPE_H_
+#define __PY_TYPE_H_
+
+#include <glib.h>
+
+namespace PY {
+
+#define PINYIN_ID_VOID  (-1)
+#define PINYIN_ID_ZERO  (0)
+#define PINYIN_ID_B     (1)
+#define PINYIN_ID_C     (2)
+#define PINYIN_ID_CH    (3)
+#define PINYIN_ID_D     (4)
+#define PINYIN_ID_F     (5)
+#define PINYIN_ID_G     (6)
+#define PINYIN_ID_H     (7)
+#define PINYIN_ID_J     (8)
+#define PINYIN_ID_K     (9)
+#define PINYIN_ID_L     (10)
+#define PINYIN_ID_M     (11)
+#define PINYIN_ID_N     (12)
+#define PINYIN_ID_P     (13)
+#define PINYIN_ID_Q     (14)
+#define PINYIN_ID_R     (15)
+#define PINYIN_ID_S     (16)
+#define PINYIN_ID_SH    (17)
+#define PINYIN_ID_T     (18)
+#define PINYIN_ID_W     (19)
+#define PINYIN_ID_X     (20)
+#define PINYIN_ID_Y     (21)
+#define PINYIN_ID_Z     (22)
+#define PINYIN_ID_ZH    (23)
+#define PINYIN_ID_A     (24)
+#define PINYIN_ID_AI    (25)
+#define PINYIN_ID_AN    (26)
+#define PINYIN_ID_ANG   (27)
+#define PINYIN_ID_AO    (28)
+#define PINYIN_ID_E     (29)
+#define PINYIN_ID_EI    (30)
+#define PINYIN_ID_EN    (31)
+#define PINYIN_ID_ENG   (32)
+#define PINYIN_ID_ER    (33)
+#define PINYIN_ID_I     (34)
+#define PINYIN_ID_IA    (35)
+#define PINYIN_ID_IAN   (36)
+#define PINYIN_ID_IANG  (37)
+#define PINYIN_ID_IAO   (38)
+#define PINYIN_ID_IE    (39)
+#define PINYIN_ID_IN    (40)
+#define PINYIN_ID_ING   (41)
+#define PINYIN_ID_IONG  (42)
+#define PINYIN_ID_IU    (43)
+#define PINYIN_ID_O     (44)
+#define PINYIN_ID_ONG   (45)
+#define PINYIN_ID_OU    (46)
+#define PINYIN_ID_U     (47)
+#define PINYIN_ID_UA    (48)
+#define PINYIN_ID_UAI   (49)
+#define PINYIN_ID_UAN   (50)
+#define PINYIN_ID_UANG  (51)
+#define PINYIN_ID_UE    (52)
+#define PINYIN_ID_UI    (53)
+#define PINYIN_ID_UN    (54)
+#define PINYIN_ID_UO    (55)
+#define PINYIN_ID_V     (56)
+#define PINYIN_ID_NG    PINYIN_ID_VOID
+
+#define PINYIN_SIMPLE_PINYIN        (1 << 0)
+
+#define PINYIN_CORRECT_GN_TO_NG     (1 << 1)
+#define PINYIN_CORRECT_MG_TO_NG     (1 << 2)
+#define PINYIN_CORRECT_IOU_TO_IU    (1 << 3)
+#define PINYIN_CORRECT_UEI_TO_UI    (1 << 4)
+#define PINYIN_CORRECT_UEN_TO_UN    (1 << 5)
+#define PINYIN_CORRECT_VE_TO_UE     (1 << 6)
+#define PINYIN_CORRECT_ALL          (0x0000007e)
+
+#define PINYIN_FUZZY_C_CH           (1 << 7)
+#define PINYIN_FUZZY_CH_C           (1 << 8)
+#define PINYIN_FUZZY_Z_ZH           (1 << 9)
+#define PINYIN_FUZZY_ZH_Z           (1 << 10)
+#define PINYIN_FUZZY_S_SH           (1 << 11)
+#define PINYIN_FUZZY_SH_S           (1 << 12)
+#define PINYIN_FUZZY_L_N            (1 << 13)
+#define PINYIN_FUZZY_N_L            (1 << 14)
+#define PINYIN_FUZZY_F_H            (1 << 15)
+#define PINYIN_FUZZY_H_F            (1 << 16)
+#define PINYIN_FUZZY_L_R            (1 << 17)
+#define PINYIN_FUZZY_R_L            (1 << 18)
+#define PINYIN_FUZZY_K_G            (1 << 19)
+#define PINYIN_FUZZY_G_K            (1 << 20)
+
+#define PINYIN_FUZZY_AN_ANG         (1 << 21)
+#define PINYIN_FUZZY_ANG_AN         (1 << 22)
+#define PINYIN_FUZZY_EN_ENG         (1 << 23)
+#define PINYIN_FUZZY_ENG_EN         (1 << 24)
+#define PINYIN_FUZZY_IN_ING         (1 << 25)
+#define PINYIN_FUZZY_ING_IN         (1 << 26)
+#define PINYIN_FUZZY_IAN_IANG       (1 << 27)
+#define PINYIN_FUZZY_IANG_IAN       (1 << 28)
+#define PINYIN_FUZZY_UAN_UANG       (1 << 29)
+#define PINYIN_FUZZY_UANG_UAN       (1 << 30)
+#define PINYIN_FUZZY_ALL            (0x7fffff10)
+
+typedef struct _Pinyin Pinyin;
+struct _Pinyin {
+    const char *text;
+    const char *sheng;
+    const char *yun;
+    const char  sheng_id;
+    const char  yun_id;
+    const char  fsheng_id;
+    const char  fyun_id;
+    const char  fsheng_id_2;
+    const char  fyun_id_2;
+    const int   len;
+    const int   flags;
+};
+
+#define MAX_UTF8_LEN 6
+#define MAX_PHRASE_LEN 16
+
+typedef struct _Phrase Phrase;
+struct _Phrase {
+    gchar phrase[(MAX_PHRASE_LEN + 1) * MAX_UTF8_LEN];
+    guint  freq;
+    guint  user_freq;
+    guint  pinyin_id[MAX_PHRASE_LEN][2];
+    guint  len;
+};
+
+};
+
+#endif
diff --git a/src/Util.h b/src/Util.h
new file mode 100644 (file)
index 0000000..aaa0178
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef __PY_UTIL_H_
+#define __PY_UTIL_H_
+
+#include <uuid/uuid.h>
+#include <sys/utsname.h>
+
+namespace PY {
+
+class UUID {
+public:
+    UUID (void) {
+        uuid_t u;
+        uuid_generate (u);
+        uuid_unparse (u, m_uuid);
+    }
+
+    operator const gchar * (void) const {
+        return m_uuid;        
+    }
+
+private:
+    gchar m_uuid[40];
+};
+
+class Uname {
+public:
+    Uname (void) {
+        uname (&m_buf);
+    }
+
+    const gchar *hostname (void) const { return m_buf.nodename; }
+private:
+    struct utsname m_buf;
+};
+
+class Hostname : public Uname {
+public:
+    operator const gchar * (void) const {
+        return hostname ();
+    }
+};
+
+class StaticString {
+public:
+    StaticString (const gchar *str) : m_string (str) {}
+    gboolean operator == (const gchar *str) const {
+        if (G_UNLIKELY (m_string == str))
+            return TRUE;
+        return g_strcmp0 (m_string, str) == 0;
+    }
+    gboolean operator != (const gchar *str) const {
+        if (G_UNLIKELY (m_string == str))
+            return FALSE;
+        return g_strcmp0 (m_string, str) != 0;
+    }
+    operator const gchar * (void) const {
+        return m_string;
+    }
+private:
+    const gchar *m_string;
+};
+
+};
+#endif
diff --git a/src/main.db b/src/main.db
new file mode 120000 (symlink)
index 0000000..9cd4f3e
--- /dev/null
@@ -0,0 +1 @@
+../data/db/main.db
\ No newline at end of file
similarity index 72%
rename from engine/pinyin.xml.in.in
rename to src/pinyin.xml.in.in
index a7f7760..9e04313 100644 (file)
@@ -1,8 +1,8 @@
 <?xml version=\"1.0\" encoding=\"utf-8\"?>
 <!-- filename: pinyin.xml -->
 <component>
-       <name>org.freedesktop.IBus.PinYin</name>
-       <description>PinYin Component</description>
+       <name>org.freedesktop.IBus.Pinyin</name>
+       <description>Pinyin Component</description>
        <exec>${libexecdir}/ibus-engine-pinyin --ibus</exec>
        <version>@VERSION@</version>
        <author>Peng Huang &lt;shawn.p.huang@gmail.com&gt;</author>
        <homepage>http://code.google.com/p/ibus</homepage>
        <textdomain>ibus-pinyin</textdomain>
 
-       <!-- for static engines -->
        <engines>
                <engine>
                        <name>pinyin</name>
-                       <language>zh_CN</language>
+                       <language>zh</language>
                        <license>GPL</license>
                        <author>Peng Huang &lt;shawn.p.huang@gmail.com&gt;</author>
                        <icon>${pkgdatadir}/icons/ibus-pinyin.svg</icon>
                        <layout>us</layout>
-                       <longname>PinYin</longname>
-                       <description>PinYin Input Method</description>
+                       <longname>Pinyin</longname>
+                       <description>Pinyin input method</description>
                        <rank>99</rank>
                </engine>
        </engines>
+
 </component>
diff --git a/src/scripts/genpytable.py b/src/scripts/genpytable.py
new file mode 100644 (file)
index 0000000..c3d8cf3
--- /dev/null
@@ -0,0 +1,354 @@
+# vim:set et sts=4:
+
+from pydict import *
+
+def str_cmp(a, b):
+    if len(a) == len(b):
+        return cmp(a, b)
+    else:
+        return len(a) - len(b)
+
+pinyin_list = PINYIN_DICT.keys()
+pinyin_list.sort()
+
+shengmu_list = SHENGMU_DICT.keys()
+shengmu_list.remove("")
+shengmu_list.sort()
+
+auto_correct = [
+    ("ng", "gn"),
+    ("ng", "mg"),
+    ("iu", "iou"),
+    ("ui", "uei"),
+    ("un", "uen"),
+    ("ue", "ve")]
+
+fuzzy_shengmu = [
+    ("c", "ch"),
+    ("ch", "c"),
+    ("z", "zh"),
+    ("zh", "z"),
+    ("s", "sh"),
+    ("sh", "s"),
+    ("l", "n"),
+    ("n", "l"),
+    ("f", "h"),
+    ("h", "f"),
+    ("l", "r"),
+    ("r", "l"),
+    ("k", "g"),
+    ("g", "k"),
+    ]
+
+fuzzy_yunmu = [
+    ("an", "ang"),
+    ("ang", "an"),
+    ("en", "eng"),
+    ("eng", "en"),
+    ("in", "ing"),
+    ("ing", "in"),
+    ("ian", "iang"),
+    ("iang", "ian"),
+    ("uan", "uang"),
+    ("uang", "uan"),
+    ]
+
+def get_sheng_yun(pinyin):
+    if pinyin == None:
+        return None, None
+    if pinyin == "ng":
+        return "", "ng"
+    for i in range(2, 0, -1):
+        s = pinyin[:i]
+        if s in shengmu_list:
+            return s, pinyin[i:]
+    return "", pinyin
+
+yunmu_list = set([])
+for p in pinyin_list:
+    s, y = get_sheng_yun(p)
+    yunmu_list |= set([y])
+yunmu_list = list(yunmu_list)
+yunmu_list.sort()
+
+shengmu_yunmu_list = shengmu_list + yunmu_list
+id_dict = {}
+for i, y in enumerate(shengmu_yunmu_list):
+    id_dict[y] = i + 1
+
+fuzzy_shengmu_dict = {}
+for s1, s2 in fuzzy_shengmu:
+    if s1 not in fuzzy_shengmu_dict:
+        fuzzy_shengmu_dict[s1] = []
+    fuzzy_shengmu_dict[s1].append(s2)
+
+fuzzy_yunmu_dict = {}
+for y1, y2 in fuzzy_yunmu:
+    if y1 not in fuzzy_yunmu_dict:
+        fuzzy_yunmu_dict[y1] = []
+    fuzzy_yunmu_dict[y1].append(y2)
+
+def encode_pinyin(pinyin):
+    if pinyin == None or pinyin == "":
+        return 0
+    return id_dict[pinyin]
+
+    e = 0
+    for c in pinyin:
+        e = (e << 5) + (ord(c) - ord('a') + 1)
+    return e
+
+def get_pinyin():
+    for p in pinyin_list:
+        s, y = get_sheng_yun(p)
+        yield p, s, y, len(p), []
+
+    for s in shengmu_list:
+        yield s, s, "", len(s), ["PINYIN_SIMPLE_PINYIN"]
+
+    for c, w in auto_correct:
+        flag = "PINYIN_CORRECT_%s_TO_%s" % (w.upper(), c.upper())
+        for p in pinyin_list:
+            if p.endswith(c) and p != c:
+                wp = p.replace(c, w)
+                s, y = get_sheng_yun(p)
+                yield wp, s, y, len(wp), [flag]
+
+    for s1, s2 in fuzzy_shengmu:
+        flag = "PINYIN_FUZZY_%s_%s" % (s1.upper(), s2.upper())
+        for y in  yunmu_list:
+            if s1 + y not in pinyin_list and s2 + y in pinyin_list:
+                yield s1 + y, s1, y, len(s1) + len(y),  [flag]
+            # if s2 + y not in pinyin_list and s1 + y in pinyin_list:
+            #     yield s2 + y, s2, y, len (s2) + len(y), [flag]
+
+    for y1, y2 in fuzzy_yunmu:
+        flag = "PINYIN_FUZZY_%s_%s" % (y1.upper(), y2.upper())
+        for s in shengmu_list:
+            if s + y1 not in pinyin_list and s + y2 in pinyin_list:
+                yield s + y1, s, y1, len(s) + len(y1), [flag]
+            # if s + y2 not in pinyin_list and s + y1 in pinyin_list:
+            #     yield s + y2, s, y2, len(s) + len(y2), [flag]
+
+
+def get_pinyin_with_fuzzy():
+    for text, s, y, l, flags in get_pinyin():
+        fss = fuzzy_shengmu_dict.get(s, ["", ""])
+        fys = fuzzy_yunmu_dict.get(y, ["", ""])
+
+        try:
+            fs1, fs2 = fss
+        except:
+            fs1, fs2 = fss[0], ""
+
+        try:
+            fy1, fy2 = fys
+        except:
+            fy1, fy2 = fys[0], ""
+
+        if fs1 and \
+            (fs1 + y not in pinyin_list) and \
+            (fy1 and fs1 + fy1 not in pinyin_list) and \
+            (fy2 and fs1 + fy2 not in pinyin_list):
+            fs1 = ""
+
+        if fs2 and \
+            (fs2 + y not in pinyin_list) and \
+            (fy1 and fs2 + fy1 not in pinyin_list) and \
+            (fy2 and fs2 + fy2 not in pinyin_list):
+            fs2 = ""
+
+        if fy1 and \
+            (s + fy1 not in pinyin_list) and \
+            (fs1 and fs1 + fy1 not in pinyin_list) and \
+            (fs2 and fs2 + fy1 not in pinyin_list):
+            fy1 = ""
+
+        if fy2 and \
+            (s + fy2 not in pinyin_list) and \
+            (fs1 and fs1 + fy2 not in pinyin_list) and \
+            (fs2 and fs2 + fy2 not in pinyin_list):
+            fy2 = ""
+
+        yield text, s, y, s, y, fs1, fy1, fs2, fy2, l, flags
+
+
+def gen_header():
+    print '''/* Please do not modify this file. It is generated by script */
+#include "Types.h"
+
+namespace PY {
+'''
+
+def gen_macros():
+    print '#define PINYIN_ID_VOID    (-1)'
+    print '#define PINYIN_ID_ZERO    (0)'
+    for y in shengmu_list:
+        print '#define PINYIN_ID_%s    (%d)' % (y.upper(), encode_pinyin(y))
+
+    for y in yunmu_list:
+        print '#define PINYIN_ID_%s    (%d)' % (y.upper(), encode_pinyin(y))
+    print
+    print
+    print
+
+def gen_option_check(name, fuzzy):
+    print '''static gboolean
+%s (guint option, gint id, gint fid)
+{
+    switch ((id << 16) | fid) {''' % name
+    for y1, y2 in fuzzy:
+        flag = "PINYIN_FUZZY_%s_%s" % (y1.upper(), y2.upper())
+        args = tuple(["PINYIN_ID_%s" % y.upper() for y in [y1, y2]]) + (flag, )
+        print '''    case (%s << 16) | %s:
+        return (option & %s);''' % args
+
+    print '    default: return FALSE;'
+    print '    }'
+    print '}'
+
+def union_dups(a):
+    n = {}
+    for r in a:
+        if r[:-1] in n:
+            n[r[:-1]] += r[-1]
+        else:
+            n[r[:-1]] = r[-1]
+    na = []
+    for k, flags in n.items():
+        na.append (tuple(list(k) + [" | ".join(flags) if flags else 0]))
+    na.sort()
+    return na
+
+def gen_tables():
+
+    pinyins = list(get_pinyin_with_fuzzy())
+    pinyins = union_dups(pinyins)
+
+    print 'static const Pinyin pinyin_table[] = {'
+    for i, p in enumerate(pinyins):
+        args = (i, ) + tuple(['"%s"' % s for s in p[:3]]) + tuple(["PINYIN_ID_%s" % s.upper() if s else "PINYIN_ID_ZERO" for s in p[3:9]]) + p[9:-1] + (str(p[-1]), )
+        print '''    {  /* %d */
+        text        : %s,
+        sheng       : %s,
+        yun         : %s,
+        sheng_id    : %s,
+        yun_id      : %s,
+        fsheng_id   : %s,
+        fyun_id     : %s,
+        fsheng_id_2 : %s,
+        fyun_id_2   : %s,
+        len         : %d,
+        flags       : %s
+    },''' % args
+
+    print '};'
+    print
+    print '#define PINYIN_TABLE_NR (sizeof (pinyin_table) / sizeof (pinyin_table[0]))'
+
+    return pinyins
+
+def get_all_special():
+    for p in pinyin_list:
+        if p[-1] in ["n", "g", "r"]:
+            for yun in yunmu_list:
+                if yun not in pinyin_list:
+                    continue
+                new_pinyin = p[-1] + yun
+                # if new_pinyin in pinyin_list:
+                yield p, yun, p[:-1], new_pinyin
+        elif p[-1] in ["e"]:
+            yield p, "r", p[:-1], "er"
+
+def get_freq_sum_2(db, p1, p2):
+    s1, y1 = get_sheng_yun(p1)
+    s2, y2 = get_sheng_yun(p2)
+
+    sql = "select max(freq), phrase from py_phrase_1 where s0 = %d and y0 = %d and s1 = %d and y1 = %d"
+
+    c = db.execute(sql % (encode_pinyin(s1), encode_pinyin(y1), encode_pinyin(s2), encode_pinyin(y2)))
+    for r in c:
+        return r[0]
+    return 0
+
+def get_freq_sum_1(db, p1):
+    s1, y1 = get_sheng_yun(p1)
+
+    sql = "select max(freq), phrase from py_phrase_0 where s0 = %d and y0 = %d"
+
+    c = db.execute(sql % (encode_pinyin(s1), encode_pinyin(y1)))
+    for r in c:
+        return r[0] if r[0] else 0
+    return 0
+
+def compaired_special():
+    import sqlite3
+    db = sqlite3.connect("py.db")
+
+    for p1, p2, p3, p4 in get_all_special():
+        if p3 not in pinyin_list or p4 not in pinyin_list:
+            continue
+        if p1 not in pinyin_list or p2 not in pinyin_list:
+            yield p1, p2, p3, p4
+            continue
+
+        if p3 not in pinyin_list or p4 not in pinyin_list:
+            continue
+
+        a1 = get_freq_sum_2(db, p1, p2)
+        a2 = get_freq_sum_2(db, p3, p4)
+        if a1 == a2:
+            a1 = get_freq_sum_1(db, p1) + get_freq_sum_1(db, p2)
+            a2 = get_freq_sum_1(db, p3) + get_freq_sum_1(db, p4)
+        if a1 < a2:
+            yield p1, p2, p3, p4
+
+def gen_full_pinyin_table(pinyins):
+    _dict = {}
+    for i in xrange(0, len(pinyins)):
+        _dict[pinyins[i]] = i
+    full_pinyin = []
+    for i in xrange(0, len(pinyins)):
+        if pinyins[i][0] in pinyin_list:
+            full_pinyin.append (pinyins[i])
+    full_pinyin.sort(lambda a, b: (cmp(a[1], b[1]) << 16) + cmp(a[2],b[4]))
+    print 'static const Pinyin *full_pinyin_table[] = {'
+    for p in full_pinyin:
+        print "    &pinyin_table[%d],    // %s" % (_dict[p], p[0])
+    print '};'
+    print '#define FULL_PINYIN_TABLE_NR (sizeof (full_pinyin_table) / sizeof (full_pinyin_table[0]))'
+    print
+
+
+def gen_special_table(pinyins):
+    _dict = {}
+    for i in xrange(0, len(pinyins)):
+        _dict[pinyins[i][0]] = i
+
+    l = list(compaired_special())
+    l.sort()
+    print 'static const Pinyin *special_table[][4] = {'
+    for r in l:
+        ids =  [("&pinyin_table[%d]," % _dict[py]).ljust(20) for py in r]
+
+        print '    { %s %s %s %s },' % tuple(ids), "/* %s %s => %s %s */" % r
+    print '};'
+    print '#define SPECIAL_TABLE_NR (sizeof (special_table) / sizeof (special_table[0]))'
+    print
+
+
+def main():
+    gen_header()
+    # gen_macros()
+    pinyins = gen_tables()
+    # gen_full_pinyin_table (pinyins)
+    gen_special_table(pinyins)
+    # gen_option_check("pinyin_option_check_sheng", fuzzy_shengmu)
+    # gen_option_check("pinyin_option_check_yun", fuzzy_yunmu)
+
+    print "};"
+
+
+if __name__ == "__main__":
+    main()
+
diff --git a/src/scripts/pydict.py b/src/scripts/pydict.py
new file mode 100644 (file)
index 0000000..72e1449
--- /dev/null
@@ -0,0 +1,105 @@
+PINYIN_DICT = {
+    "a" : 1, "ai" : 2, "an" : 3, "ang" : 4, "ao" : 5,
+    "ba" : 6, "bai" : 7, "ban" : 8, "bang" : 9, "bao" : 10,
+    "bei" : 11, "ben" : 12, "beng" : 13, "bi" : 14, "bian" : 15,
+    "biao" : 16, "bie" : 17, "bin" : 18, "bing" : 19, "bo" : 20,
+    "bu" : 21, "ca" : 22, "cai" : 23, "can" : 24, "cang" : 25,
+    "cao" : 26, "ce" : 27, "cen" : 28, "ceng" : 29, "ci" : 30,
+    "cong" : 31, "cou" : 32, "cu" : 33, "cuan" : 34, "cui" : 35,
+    "cun" : 36, "cuo" : 37, "cha" : 38, "chai" : 39, "chan" : 40,
+    "chang" : 41, "chao" : 42, "che" : 43, "chen" : 44, "cheng" : 45,
+    "chi" : 46, "chong" : 47, "chou" : 48, "chu" : 49, "chuai" : 50,
+    "chuan" : 51, "chuang" : 52, "chui" : 53, "chun" : 54, "chuo" : 55,
+    "da" : 56, "dai" : 57, "dan" : 58, "dang" : 59, "dao" : 60,
+    "de" : 61, "dei" : 62,
+    # "den" : 63,
+    "deng" : 64, "di" : 65,
+    "dia" : 66, "dian" : 67, "diao" : 68, "die" : 69, "ding" : 70,
+    "diu" : 71, "dong" : 72, "dou" : 73, "du" : 74, "duan" : 75,
+    "dui" : 76, "dun" : 77, "duo" : 78, "e" : 79, "ei" : 80,
+    "en" : 81, "er" : 82, "fa" : 83, "fan" : 84, "fang" : 85,
+    "fei" : 86, "fen" : 87, "feng" : 88, "fo" : 89, "fou" : 90,
+    "fu" : 91, "ga" : 92, "gai" : 93, "gan" : 94, "gang" : 95,
+    "gao" : 96, "ge" : 97, "gei" : 98, "gen" : 99, "geng" : 100,
+    "gong" : 101, "gou" : 102, "gu" : 103, "gua" : 104, "guai" : 105,
+    "guan" : 106, "guang" : 107, "gui" : 108, "gun" : 109, "guo" : 110,
+    "ha" : 111, "hai" : 112, "han" : 113, "hang" : 114, "hao" : 115,
+    "he" : 116, "hei" : 117, "hen" : 118, "heng" : 119, "hong" : 120,
+    "hou" : 121, "hu" : 122, "hua" : 123, "huai" : 124, "huan" : 125,
+    "huang" : 126, "hui" : 127, "hun" : 128, "huo" : 129, "ji" : 130,
+    "jia" : 131, "jian" : 132, "jiang" : 133, "jiao" : 134, "jie" : 135,
+    "jin" : 136, "jing" : 137, "jiong" : 138, "jiu" : 139, "ju" : 140,
+    "juan" : 141, "jue" : 142, "jun" : 143, "ka" : 144, "kai" : 145,
+    "kan" : 146, "kang" : 147, "kao" : 148, "ke" : 149,
+    # "kei" : 150,
+    "ken" : 151, "keng" : 152, "kong" : 153, "kou" : 154, "ku" : 155,
+    "kua" : 156, "kuai" : 157, "kuan" : 158, "kuang" : 159, "kui" : 160,
+    "kun" : 161, "kuo" : 162, "la" : 163, "lai" : 164, "lan" : 165,
+    "lang" : 166, "lao" : 167, "le" : 168, "lei" : 169, "leng" : 170,
+    "li" : 171, "lia" : 172, "lian" : 173, "liang" : 174, "liao" : 175,
+    "lie" : 176, "lin" : 177, "ling" : 178, "liu" : 179,
+    "lo" : 180,
+    "long" : 181, "lou" : 182, "lu" : 183, "luan" : 184, "lue" : 185,
+    "lun" : 186, "luo" : 187, "lv" : 188,
+    # "lve" : 189,
+    "ma" : 190,
+    "mai" : 191, "man" : 192, "mang" : 193, "mao" : 194, "me" : 195,
+    "mei" : 196, "men" : 197, "meng" : 198, "mi" : 199, "mian" : 200,
+    "miao" : 201, "mie" : 202, "min" : 203, "ming" : 204, "miu" : 205,
+    "mo" : 206, "mou" : 207, "mu" : 208, "na" : 209, "nai" : 210,
+    "nan" : 211, "nang" : 212, "nao" : 213, "ne" : 214, "nei" : 215,
+    "nen" : 216, "neng" : 217, "ni" : 218, "nian" : 219, "niang" : 220,
+    "niao" : 221, "nie" : 222, "nin" : 223, "ning" : 224, "niu" : 225,
+    # "ng" : 226,
+    "nong" : 227, "nou" : 228, "nu" : 229, "nuan" : 230,
+    "nue" : 231, "nuo" : 232, "nv" : 233,
+    #"nve" : 234,
+    "o" : 235,
+    "ou" : 236, "pa" : 237, "pai" : 238, "pan" : 239, "pang" : 240,
+    "pao" : 241, "pei" : 242, "pen" : 243, "peng" : 244, "pi" : 245,
+    "pian" : 246, "piao" : 247, "pie" : 248, "pin" : 249, "ping" : 250,
+    "po" : 251, "pou" : 252, "pu" : 253, "qi" : 254, "qia" : 255,
+    "qian" : 256, "qiang" : 257, "qiao" : 258, "qie" : 259, "qin" : 260,
+    "qing" : 261, "qiong" : 262, "qiu" : 263, "qu" : 264, "quan" : 265,
+    "que" : 266, "qun" : 267, "ran" : 268, "rang" : 269, "rao" : 270,
+    "re" : 271, "ren" : 272, "reng" : 273, "ri" : 274, "rong" : 275,
+    "rou" : 276, "ru" : 277, "ruan" : 278, "rui" : 279, "run" : 280,
+    "ruo" : 281, "sa" : 282, "sai" : 283, "san" : 284, "sang" : 285,
+    "sao" : 286, "se" : 287, "sen" : 288, "seng" : 289, "si" : 290,
+    "song" : 291, "sou" : 292, "su" : 293, "suan" : 294, "sui" : 295,
+    "sun" : 296, "suo" : 297, "sha" : 298, "shai" : 299, "shan" : 300,
+    "shang" : 301, "shao" : 302, "she" : 303, "shei" : 304, "shen" : 305,
+    "sheng" : 306, "shi" : 307, "shou" : 308, "shu" : 309, "shua" : 310,
+    "shuai" : 311, "shuan" : 312, "shuang" : 313, "shui" : 314, "shun" : 315,
+    "shuo" : 316, "ta" : 317, "tai" : 318, "tan" : 319, "tang" : 320,
+    "tao" : 321, "te" : 322,
+    # "tei" : 323,
+    "teng" : 324, "ti" : 325,
+    "tian" : 326, "tiao" : 327, "tie" : 328, "ting" : 329, "tong" : 330,
+    "tou" : 331, "tu" : 332, "tuan" : 333, "tui" : 334, "tun" : 335,
+    "tuo" : 336, "wa" : 337, "wai" : 338, "wan" : 339, "wang" : 340,
+    "wei" : 341, "wen" : 342, "weng" : 343, "wo" : 344, "wu" : 345,
+    "xi" : 346, "xia" : 347, "xian" : 348, "xiang" : 349, "xiao" : 350,
+    "xie" : 351, "xin" : 352, "xing" : 353, "xiong" : 354, "xiu" : 355,
+    "xu" : 356, "xuan" : 357, "xue" : 358, "xun" : 359, "ya" : 360,
+    "yan" : 361, "yang" : 362, "yao" : 363, "ye" : 364, "yi" : 365,
+    "yin" : 366, "ying" : 367, "yo" : 368, "yong" : 369, "you" : 370,
+    "yu" : 371, "yuan" : 372, "yue" : 373, "yun" : 374, "za" : 375,
+    "zai" : 376, "zan" : 377, "zang" : 378, "zao" : 379, "ze" : 380,
+    "zei" : 381, "zen" : 382, "zeng" : 383, "zi" : 384, "zong" : 385,
+    "zou" : 386, "zu" : 387, "zuan" : 388, "zui" : 389, "zun" : 390,
+    "zuo" : 391, "zha" : 392, "zhai" : 393, "zhan" : 394, "zhang" : 395,
+    "zhao" : 396, "zhe" : 397, "zhen" : 398, "zheng" : 399, "zhi" : 400,
+    "zhong" : 401, "zhou" : 402, "zhu" : 403, "zhua" : 404, "zhuai" : 405,
+    "zhuan" : 406, "zhuang" : 407, "zhui" : 408, "zhun" : 409, "zhuo" : 410,
+    # some weird pinyins
+    #~ "eng" : 411, "chua" : 412, "fe" : 413, "fiao" : 414, "liong" : 415
+}
+
+SHENGMU_DICT = {
+    "" : 0, "b" : 1, "p" : 2, "m" : 3, "f" : 4, "d" : 5,
+    "t" : 6, "n" : 7, "l" : 8, "g" : 9, "k" : 10, "h" : 11,
+    "j" : 12, "q" : 13, "x" : 14, "zh" : 15, "ch" : 16, "sh" : 17,
+    "r" : 18, "z" : 19, "c" : 20, "s" : 21, "y" : 22, "w" : 23
+}
+
similarity index 99%
rename from engine/special_table
rename to src/special_table
index f00d13c..0948b37 100644 (file)
@@ -8,9 +8,7 @@
 #
 # 以 X_ 开头的特殊字符串为内建标识 例如 X_DATE_1 代表阿拉伯数字格式的当前日期.
 #
-# 以 0x 开头的是16进制 Unicode 编码
-#
-# 用户可以按照该文件格式自行编辑定制的用户文件 ~/.scim/chinese/special_table
+# 用户可以按照该文件格式自行编辑定制的用户文件 ~/.ibus/pinyin/special_table
 #
 
 # 当前日期