diff options
author | Peng Huang <shawn.p.huang@gmail.com> | 2009-09-23 13:30:02 +0800 |
---|---|---|
committer | Peng Huang <shawn.p.huang@gmail.com> | 2009-09-23 13:30:02 +0800 |
commit | 998c9299f04a4756ff8a08ab3448b3f7860b9fe0 (patch) | |
tree | 89a3ccd529632944e1659d7b2b01a1d5595d30c2 | |
parent | 9911013dd7e4edc7c295dad24121309b1fda5718 (diff) | |
download | ibus-libpinyin-998c9299f04a4756ff8a08ab3448b3f7860b9fe0.tar.gz ibus-libpinyin-998c9299f04a4756ff8a08ab3448b3f7860b9fe0.tar.xz ibus-libpinyin-998c9299f04a4756ff8a08ab3448b3f7860b9fe0.zip |
Import c version pinyin engine
110 files changed, 6761 insertions, 5510 deletions
@@ -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> diff --git a/Makefile.am b/Makefile.am index ba1b395..f8f9eec 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 @@ -1,2 +1,2 @@ ibus-pinyin -It is a PinYin engine for IBus. +It is a Chinese Pinyin input method for IBus. @@ -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 $* diff --git a/configure.ac b/configure.ac index ee158a8..5c175c4 100644 --- a/configure.ac +++ b/configure.ac @@ -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> # @@ -19,42 +19,60 @@ # 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 diff --git a/icons/Makefile.am b/data/Makefile.am index ee5c45c..bca638d 100644 --- a/icons/Makefile.am +++ b/data/Makefile.am @@ -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> # @@ -18,18 +18,43 @@ # 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 index 0000000..5d59077 --- /dev/null +++ b/data/icons/Makefile.am @@ -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) + diff --git a/icons/chinese.svg b/data/icons/chinese.svg index aa7b61d..aa7b61d 100644 --- a/icons/chinese.svg +++ b/data/icons/chinese.svg diff --git a/icons/english.svg b/data/icons/english.svg index 4369a7f..4369a7f 100644 --- a/icons/english.svg +++ b/data/icons/english.svg diff --git a/icons/full-punct.svg b/data/icons/full-punct.svg index 2a91f19..2a91f19 100644 --- a/icons/full-punct.svg +++ b/data/icons/full-punct.svg diff --git a/icons/full-letter.svg b/data/icons/full.svg index 9653d63..9653d63 100644 --- a/icons/full-letter.svg +++ b/data/icons/full.svg diff --git a/icons/half-punct.svg b/data/icons/half-punct.svg index 41fae25..41fae25 100644 --- a/icons/half-punct.svg +++ b/data/icons/half-punct.svg diff --git a/icons/half-letter.svg b/data/icons/half.svg index 362793e..362793e 100644 --- a/icons/half-letter.svg +++ b/data/icons/half.svg diff --git a/icons/ibus-pinyin.svg b/data/icons/ibus-pinyin.svg index 1582c0d..1582c0d 100644 --- a/icons/ibus-pinyin.svg +++ b/data/icons/ibus-pinyin.svg diff --git a/data/scripts/create_db.py b/data/scripts/create_db.py new file mode 100644 index 0000000..e4826ae --- /dev/null +++ b/data/scripts/create_db.py @@ -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 index 0000000..823e616 --- /dev/null +++ b/data/scripts/create_index.py @@ -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 index 0000000..e22d986 --- /dev/null +++ b/data/scripts/create_unique_index.py @@ -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 index 0000000..1ee8359 --- /dev/null +++ b/data/scripts/double.py @@ -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 index 0000000..44bd80c --- /dev/null +++ b/data/scripts/id.py @@ -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} diff --git a/engine/pydict.py b/data/scripts/pydict.py index 4646477..4646477 100644 --- a/engine/pydict.py +++ b/data/scripts/pydict.py diff --git a/engine/pyutil.py b/data/scripts/pyutil.py index 1872659..1872659 100644 --- a/engine/pyutil.py +++ b/data/scripts/pyutil.py diff --git a/debian/README.Debian b/debian/README.Debian deleted file mode 100644 index e9e6ec8..0000000 --- a/debian/README.Debian +++ /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 index 2175cd9..0000000 --- a/debian/changelog +++ /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 index 7ed6ff8..0000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -5 diff --git a/debian/control b/debian/control deleted file mode 100644 index 161986c..0000000 --- a/debian/control +++ /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 index 26049cd..0000000 --- a/debian/copyright +++ /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 index 02b68ea..0000000 --- a/debian/cron.d.ex +++ /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 index ca882bb..0000000 --- a/debian/dirs +++ /dev/null @@ -1,2 +0,0 @@ -usr/bin -usr/sbin diff --git a/debian/docs b/debian/docs deleted file mode 100644 index 50bd824..0000000 --- a/debian/docs +++ /dev/null @@ -1,2 +0,0 @@ -NEWS -README diff --git a/debian/emacsen-install.ex b/debian/emacsen-install.ex deleted file mode 100644 index 09c12aa..0000000 --- a/debian/emacsen-install.ex +++ /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 index 853219d..0000000 --- a/debian/emacsen-remove.ex +++ /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 index 0691f53..0000000 --- a/debian/emacsen-startup.ex +++ /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 index 9ca3204..0000000 --- a/debian/ibus-pinyin-default.ex +++ /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 index 14ad664..0000000 --- a/debian/ibus-pinyin.doc-base.EX +++ /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 index 0b800d9..0000000 --- a/debian/init.d.ex +++ /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 index e73dc7f..0000000 --- a/debian/init.d.lsb.ex +++ /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 index 15dae44..0000000 --- a/debian/manpage.1.ex +++ /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 index 5adbcb0..0000000 --- a/debian/manpage.sgml.ex +++ /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 index b99a183..0000000 --- a/debian/manpage.xml.ex +++ /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 index 67524d6..0000000 --- a/debian/menu.ex +++ /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 index 6094692..0000000 --- a/debian/postinst.ex +++ /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 index e56c758..0000000 --- a/debian/postrm.ex +++ /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 index a3dd684..0000000 --- a/debian/preinst.ex +++ /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 index a237b14..0000000 --- a/debian/prerm.ex +++ /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 index 222c57f..0000000 --- a/debian/rules +++ /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 index 545b10f..0000000 --- a/debian/watch.ex +++ /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 index aaae759..0000000 --- a/engine/Makefile.am +++ /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 index 6f66d8b..0000000 --- a/engine/factory.py +++ /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 index 9a3c8bb..0000000 --- a/engine/ibus-engine-pinyin.in +++ /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 index fd4d88c..0000000 --- a/engine/main.py +++ /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 index 4182336..0000000 --- a/engine/pinyin.py +++ /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 index e780faf..0000000 --- a/engine/pycreatedb.py +++ /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 index 5266c4c..0000000 --- a/engine/pyparser.py +++ /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 index 399c14a..0000000 --- a/engine/pysqlitedb.py +++ /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 index b1076f6..0000000 --- a/engine/special_phrase +++ /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 index 5f2ac6c..0000000 --- a/engine/specialphrase.py +++ /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 index cdabbe0..0000000 --- a/engine/specialtable.py +++ /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 - diff --git a/ibus-pinyin.spec.in b/ibus-pinyin.spec.in index d3648a3..fca54f4 100644 --- a/ibus-pinyin.spec.in +++ b/ibus-pinyin.spec.in @@ -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. @@ -1,3 +1,2 @@ -ja zh_CN diff --git a/po/POTFILES.in b/po/POTFILES.in index 17701be..e249584 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -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 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 Binary files differnew file mode 100644 index 0000000..a0147ff --- /dev/null +++ b/po/zh_CN.gmo diff --git a/po/zh_CN.po b/po/zh_CN.po index a6efd4c..b62e0b9 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -1,235 +1,166 @@ -# 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 "半角标点" +#: setup/ibus-pinyin-preferences.glade:179 +msgid "Half/full punctuation:" +msgstr "全角/半角标点:" -#: 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 <shawn.p.huang@gmail.com></small>" msgstr "" +"<small>Copyright (c) 2009 Huang Peng <shawn.p.huang@gmail.com></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" diff --git a/setup/Makefile.am b/setup/Makefile.am index 4a4b53a..a83dcb3 100644 --- a/setup/Makefile.am +++ b/setup/Makefile.am @@ -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 index 0000000..95eefd9 --- /dev/null +++ b/setup/ibus-pinyin-preferences.glade @@ -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"><b>Pinyin</b></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"><b>Initial state</b></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">●</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"><b>Others</b></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 => 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 => 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 => 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 => 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 => 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 => 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"><b>Correct pinyin</b></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 => 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 => 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 => 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 => 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 => 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 => 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 => 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 => 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 => 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 => 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 => 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 => 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 => 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 => 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 => 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 => 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 => 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 => 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 => 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 => 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 => 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 => 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 => 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 => 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"><b>Fuzzy pinyin</b></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"><big><b>IBus Pinyin 1.3.0</b></big></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"><small>Copyright (c) 2009 Huang Peng &lt;shawn.p.huang@gmail.com&gt;</small></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> diff --git a/setup/ibus-setup-pinyin.in b/setup/ibus-setup-pinyin.in index a7eb522..27c700c 100644 --- a/setup/ibus-setup-pinyin.in +++ b/setup/ibus-setup-pinyin.in @@ -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 $@ diff --git a/setup/main.py b/setup/main.py index 7f17f83..6396117 100644 --- a/setup/main.py +++ b/setup/main.py @@ -1,284 +1,225 @@ -# 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 index b106fef..0000000 --- a/setup/pydict.py +++ /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 index ad16a12..0000000 --- a/setup/setup.glade +++ /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">●</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 <=> 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 <=> 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 <=> 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 <=> 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 <=> 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 <=> 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 <=> 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 <shawn.p.huang@gmail.com> -</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 index 0000000..535ced8 --- /dev/null +++ b/src/Array.h @@ -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 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 index 0000000..a629c33 --- /dev/null +++ b/src/Config.cc @@ -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 index 0000000..cd7630d --- /dev/null +++ b/src/Config.h @@ -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 index 0000000..918cfd2 --- /dev/null +++ b/src/Database.cc @@ -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 index 0000000..f07f212 --- /dev/null +++ b/src/Database.h @@ -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 index 0000000..eb872a9 --- /dev/null +++ b/src/DoublePinyinEditor.cc @@ -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 index 0000000..75d419a --- /dev/null +++ b/src/DoublePinyinEditor.h @@ -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 index 0000000..f75f09d --- /dev/null +++ b/src/DoublePinyinTable.h @@ -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 index 0000000..f15ff81 --- /dev/null +++ b/src/Engine.cc @@ -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 index 0000000..0b39081 --- /dev/null +++ b/src/Engine.h @@ -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 index 0000000..0514f8a --- /dev/null +++ b/src/FullPinyinEditor.cc @@ -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 index 0000000..6e7a253 --- /dev/null +++ b/src/FullPinyinEditor.h @@ -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 index 0000000..2d0b34e --- /dev/null +++ b/src/HalfFullConverter.cc @@ -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 index 0000000..7a18f6b --- /dev/null +++ b/src/HalfFullConverter.h @@ -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 index 0000000..53b9b51 --- /dev/null +++ b/src/LookupTable.h @@ -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 index 0000000..acf6c44 --- /dev/null +++ b/src/Main.cc @@ -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 index 0000000..39e6b53 --- /dev/null +++ b/src/Makefile.am @@ -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 index 0000000..f19cd55 --- /dev/null +++ b/src/PhraseArray.h @@ -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 index 0000000..83bb553 --- /dev/null +++ b/src/PhraseEditor.cc @@ -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 index 0000000..d998e0c --- /dev/null +++ b/src/PhraseEditor.h @@ -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 index 0000000..fb58fa6 --- /dev/null +++ b/src/PinyinArray.h @@ -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 index 0000000..fd4760c --- /dev/null +++ b/src/PinyinEditor.cc @@ -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 index 0000000..3ad2405 --- /dev/null +++ b/src/PinyinEditor.h @@ -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 index 0000000..9687410 --- /dev/null +++ b/src/PinyinEngine.cc @@ -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 index 0000000..6472302 --- /dev/null +++ b/src/PinyinEngine.h @@ -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 index 0000000..2bdfa49 --- /dev/null +++ b/src/PinyinParser.cc @@ -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 index 0000000..c9ad552 --- /dev/null +++ b/src/PinyinParser.h @@ -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 index 0000000..05de8aa --- /dev/null +++ b/src/Pointer.h @@ -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 index 0000000..5237cd7 --- /dev/null +++ b/src/Property.h @@ -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 index 0000000..e69de29 --- /dev/null +++ b/src/SpecialTable.cc diff --git a/src/SpecialTable.h b/src/SpecialTable.h new file mode 100644 index 0000000..43d9d92 --- /dev/null +++ b/src/SpecialTable.h @@ -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 index 0000000..b473a48 --- /dev/null +++ b/src/String.h @@ -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 index 0000000..22a5aab --- /dev/null +++ b/src/Text.h @@ -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 index 0000000..d083f50 --- /dev/null +++ b/src/Types.h @@ -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 index 0000000..aaa0178 --- /dev/null +++ b/src/Util.h @@ -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 index 0000000..9cd4f3e --- /dev/null +++ b/src/main.db @@ -0,0 +1 @@ +../data/db/main.db
\ No newline at end of file diff --git a/engine/pinyin.xml.in.in b/src/pinyin.xml.in.in index a7f7760..9e04313 100644 --- a/engine/pinyin.xml.in.in +++ b/src/pinyin.xml.in.in @@ -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 <shawn.p.huang@gmail.com></author> @@ -10,18 +10,18 @@ <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 <shawn.p.huang@gmail.com></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 index 0000000..c3d8cf3 --- /dev/null +++ b/src/scripts/genpytable.py @@ -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 index 0000000..72e1449 --- /dev/null +++ b/src/scripts/pydict.py @@ -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 +} + diff --git a/engine/special_table b/src/special_table index f00d13c..0948b37 100644 --- a/engine/special_table +++ b/src/special_table @@ -8,9 +8,7 @@ # # 以 X_ 开头的特殊字符串为内建标识 例如 X_DATE_1 代表阿拉伯数字格式的当前日期. # -# 以 0x 开头的是16进制 Unicode 编码 -# -# 用户可以按照该文件格式自行编辑定制的用户文件 ~/.scim/chinese/special_table +# 用户可以按照该文件格式自行编辑定制的用户文件 ~/.ibus/pinyin/special_table # # 当前日期 |