diff options
author | fujiwarat <takao.fujiwara1@gmail.com> | 2014-01-30 17:33:33 +0900 |
---|---|---|
committer | fujiwarat <takao.fujiwara1@gmail.com> | 2014-01-30 17:33:33 +0900 |
commit | 2e8e2bef7a7943ed351278c2f6c601339abd4d54 (patch) | |
tree | 702155a2687952da2b18d029e5154ea829643877 | |
parent | 85330465240ba6a028c92290d74ef05dcb5d7cb9 (diff) | |
download | ibus-anthy-2e8e2bef7a7943ed351278c2f6c601339abd4d54.tar.gz |
Added python3.
The default is to use 'python' and --with-python option can change it.
./configure --with-python=python3
-rw-r--r-- | configure.ac | 107 | ||||
-rw-r--r-- | engine/Makefile.am | 130 | ||||
-rw-r--r-- | engine/python2/Makefile.am | 144 | ||||
-rw-r--r-- | engine/python2/_config.py.in (renamed from engine/_config.py.in) | 0 | ||||
-rw-r--r-- | engine/python2/anthy.i (renamed from engine/anthy.i) | 0 | ||||
-rw-r--r-- | engine/python2/anthy.xml.in.in (renamed from engine/anthy.xml.in.in) | 0 | ||||
-rw-r--r-- | engine/python2/default.xml.in.in (renamed from engine/default.xml.in.in) | 0 | ||||
-rw-r--r-- | engine/python2/engine.py (renamed from engine/engine.py) | 4 | ||||
-rw-r--r-- | engine/python2/factory.py (renamed from engine/factory.py) | 0 | ||||
-rw-r--r-- | engine/python2/ibus-engine-anthy.in (renamed from engine/ibus-engine-anthy.in) | 0 | ||||
-rw-r--r-- | engine/python2/jastring.py (renamed from engine/jastring.py) | 0 | ||||
-rw-r--r-- | engine/python2/kana.py (renamed from engine/kana.py) | 0 | ||||
-rw-r--r-- | engine/python2/main.py (renamed from engine/main.py) | 0 | ||||
-rw-r--r-- | engine/python2/romaji.py (renamed from engine/romaji.py) | 0 | ||||
-rw-r--r-- | engine/python2/segment.py (renamed from engine/segment.py) | 0 | ||||
-rw-r--r-- | engine/python2/tables.py (renamed from engine/tables.py) | 0 | ||||
-rw-r--r-- | engine/python2/test.py (renamed from engine/test.py) | 0 | ||||
-rw-r--r-- | engine/python2/thumb.py (renamed from engine/thumb.py) | 0 | ||||
-rw-r--r-- | engine/python3/Makefile.am | 144 | ||||
-rw-r--r-- | engine/python3/_config.py.in | 30 | ||||
-rw-r--r-- | engine/python3/anthy.i | 125 | ||||
-rw-r--r-- | engine/python3/anthy.xml.in.in | 19 | ||||
-rw-r--r-- | engine/python3/default.xml.in.in | 19 | ||||
-rw-r--r-- | engine/python3/engine.py | 2780 | ||||
-rw-r--r-- | engine/python3/factory.py | 80 | ||||
-rw-r--r-- | engine/python3/ibus-engine-anthy.in | 33 | ||||
-rw-r--r-- | engine/python3/jastring.py | 304 | ||||
-rw-r--r-- | engine/python3/kana.py | 170 | ||||
-rw-r--r-- | engine/python3/main.py | 188 | ||||
-rw-r--r-- | engine/python3/romaji.py | 263 | ||||
-rw-r--r-- | engine/python3/segment.py | 95 | ||||
-rw-r--r-- | engine/python3/tables.py | 731 | ||||
-rw-r--r-- | engine/python3/test.py | 21 | ||||
-rw-r--r-- | engine/python3/thumb.py | 657 | ||||
-rw-r--r-- | setup/Makefile.am | 104 | ||||
l--------- | setup/_config.py.in | 1 | ||||
-rw-r--r-- | setup/python2/Makefile.am | 116 | ||||
l--------- | setup/python2/_config.py.in | 1 | ||||
-rw-r--r-- | setup/python2/anthyprefs.py.in (renamed from setup/anthyprefs.py.in) | 0 | ||||
-rw-r--r-- | setup/python2/ibus-setup-anthy.desktop.in.in (renamed from setup/ibus-setup-anthy.desktop.in.in) | 0 | ||||
-rw-r--r-- | setup/python2/ibus-setup-anthy.in (renamed from setup/ibus-setup-anthy.in) | 0 | ||||
-rw-r--r-- | setup/python2/main.py (renamed from setup/main.py) | 0 | ||||
-rw-r--r-- | setup/python2/prefs.py (renamed from setup/prefs.py) | 0 | ||||
-rw-r--r-- | setup/python2/setup.ui (renamed from setup/setup.ui) | 0 | ||||
-rw-r--r-- | setup/python3/Makefile.am | 116 | ||||
l--------- | setup/python3/_config.py.in | 1 | ||||
-rw-r--r-- | setup/python3/anthyprefs.py.in | 1329 | ||||
-rw-r--r-- | setup/python3/ibus-setup-anthy.desktop.in.in | 8 | ||||
-rw-r--r-- | setup/python3/ibus-setup-anthy.in | 28 | ||||
-rw-r--r-- | setup/python3/main.py | 1729 | ||||
-rw-r--r-- | setup/python3/prefs.py | 273 | ||||
-rw-r--r-- | setup/python3/setup.ui | 2813 |
52 files changed, 12288 insertions, 275 deletions
diff --git a/configure.ac b/configure.ac index 2ab29d3..fbabf0d 100644 --- a/configure.ac +++ b/configure.ac @@ -110,57 +110,44 @@ dnl - check env AC_PATH_PROG(ENV_IBUS_TEST, env) AC_SUBST(ENV_IBUS_TEST) -dnl - check python -dnl ibus-anthy and pygobject3 uses python2 -dnl but AM_PATH_PYTHON does not check if python3 is used -dnl so I created IBUS_PYTHON_CHECK_VERSION2 from AM_PYTHON_CHECK_VERSION -dnl to check both the python minimum version and 3. - -dnl from python.m4 -IBUS_PYTHON_MIN_VERSION=2.5 -IBUS_PYTHON_CHECK_VERSION2() { - ARGS="import sys -# split strings by '.' and convert to numeric. Append some zeros -# because we need at least 4 digits for the hex conversion. -# map returns an iterator in Python 3.0 and a list in 2.x -minver = list(map(int, '$2'.split('.'))) -if [len](minver) < 4: - for i in list(range(0, 4 - [len](minver))): minver.append(0) -minverhex = 0 -# xrange is not present in Python 3.0 and range returns an iterator -for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]] -threever = [[3, 0, 0, 0]] -threeverhex = 0 -for i in list(range(0, 4)): threeverhex = (threeverhex << 8) + threever[[i]] -sys.exit(not (sys.hexversion >= minverhex and \\ - sys.hexversion < threeverhex))" - PROG="$1" - PYTHON_VERSION2=`"$PROG" -c "import sys; sys.stdout.write(sys.version[[:3]])"` - "$PROG" -c "$ARGS" - return $? -} - -AC_MSG_CHECKING([whether you have python2]) -HAS_PYTHON2=no -IBUS_PYTHON_INTERPRETER_LIST=' -python python2 python2.7 python2.6 pythhon2.5 -' -for PYTHON2 in $IBUS_PYTHON_INTERPRETER_LIST ; do - IBUS_PYTHON_CHECK_VERSION2 $PYTHON2 $IBUS_PYTHON_MIN_VERSION - if test $? -eq 0 ; then - HAS_PYTHON2=yes - break - fi -done -AC_MSG_RESULT($HAS_PYTHON2) - -if test x"$HAS_PYTHON2" = xyes; then - AC_PATH_PROG(PYTHON, $PYTHON2) - PYTHON_VERSION=$PYTHON_VERSION2 -fi +dnl - define python version +AC_ARG_WITH(python, + AS_HELP_STRING([--with-python[=PATH]], + [Select python2 or python3]), + [PYTHON=$with_python], [] +) dnl export $pyexecdir using existent $PYTHON -AM_PATH_PYTHON([$IBUS_PYTHON_MIN_VERSION]) +AM_PATH_PYTHON([2.5]) + +dnl Decided to separate python3 directory from python2 directory here +dnl because engine/table.py includes unicode array so it's better to +dnl use __future__.unicode_literals. +dnl python3 string are always str. +dnl In case __future__.unicode_literals is imported, all the literal +dnl 'a' is treated as unicode and u'a' is not needed in python2. +dnl But str is not unicode so we need to convert str to unicode in +dnl python2 for all non-literal variables likes return values of +dnl gettext, IBusConfig.get_value, get methods in GTK+ and so on. +dnl It would causes to complicate python2 codes if merge python2 and +dnl python3 in the same file. +dnl if sys.version < '3': +dnl return unicode(gettext(a), 'utf-8') +dnl else: +dnl return gettext(a) +case "$PYTHON_VERSION" in +3.*) + enable_python3=yes + enable_python2=no + ;; +*) + enable_python3=no + enable_python2=yes + ;; +esac + +AM_CONDITIONAL([ENABLE_PYTHON2], [test x"$enable_python2" = x"yes"]) +AM_CONDITIONAL([ENABLE_PYTHON3], [test x"$enable_python3" = x"yes"]) dnl - check the supported ibus version AC_MSG_CHECKING([if your ibus version is supported]) @@ -173,9 +160,9 @@ from gi.repository import IBus retval = _ibus_check_version (ibus_major_version, ibus_minor_version) if not retval: - print 'your ibus version %d.%d.%d is old against %d.%d.%d' \ + print ('your ibus version %d.%d.%d is old against %d.%d.%d' \ % ( IBus.MAJOR_VERSION, IBus.MINOR_VERSION, IBus.MICRO_VERSION, \ - ibus_major_version, ibus_minor_version, ibus_micro_version ) + ibus_major_version, ibus_minor_version, ibus_micro_version )) exit (-1) exit(0) " @@ -424,11 +411,19 @@ ibus-anthy.spec data/Makefile gir/Makefile engine/Makefile -engine/ibus-engine-anthy -engine/anthy.xml.in -engine/default.xml.in +engine/python2/Makefile +engine/python2/ibus-engine-anthy +engine/python2/anthy.xml.in +engine/python2/default.xml.in +engine/python3/Makefile +engine/python3/ibus-engine-anthy +engine/python3/anthy.xml.in +engine/python3/default.xml.in setup/Makefile -setup/ibus-setup-anthy +setup/python2/Makefile +setup/python2/ibus-setup-anthy +setup/python3/Makefile +setup/python3/ibus-setup-anthy icons/Makefile m4/Makefile ]) @@ -446,6 +441,8 @@ LT_VERSION_INFO $LT_VERSION_INFO ENV_IBUS_ENGINE $ENV_IBUS_ENGINE HAVE_PYGTK2_ANTHY $enable_pygtk2_anthy python $PYTHON +Enable python2 $enable_python2 +Enable python3 $enable_python3 python-config $PYTHON_CONFIG PYTHON_CFLAGS $PYTHON_CFLAGS PYTHON_LIBS $PYTHON_LIBS diff --git a/engine/Makefile.am b/engine/Makefile.am index a96f831..3c64425 100644 --- a/engine/Makefile.am +++ b/engine/Makefile.am @@ -2,9 +2,8 @@ # # ibus-anthy - The Anthy engine for IBus # -# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com> -# Copyright (c) 2010-2013 Takao Fujiwara <takao.fujiwara1@gmail.com> -# Copyright (c) 2007-2013 Red Hat, Inc. +# Copyright (c) 2014 Takao Fujiwara <takao.fujiwara1@gmail.com> +# Copyright (c) 2014 Red Hat, Inc. # # 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 @@ -20,125 +19,12 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -BUILT_SOURCES = _config.py +SUBDIRS = -engine_anthy_PYTHON = \ - _config.py \ - engine.py \ - factory.py \ - jastring.py \ - kana.py \ - main.py \ - romaji.py \ - segment.py \ - tables.py \ - thumb.py \ - $(NULL) -engine_anthydir = $(pkgdatadir)/engine -engine_anthy_built_files = $(BUILT_SOURCES) -engine_anthy_built_in_files = $(addsuffix .in, $(engine_anthy_built_files)) - -PYGTK2_ANTHY_RAW = anthy.i -PYGTK2_ANTHY_GEN = anthy.py anthy_wrap.c - -if HAVE_PYGTK2_ANTHY -anthy_DATA = \ - anthy.py \ - $(NULL) -anthy_LTLIBRARIES = _anthy.la -anthydir = @pyexecdir@ - -_anthy_la_SOURCES = \ - $(NULL) - -nodist__anthy_la_SOURCES = \ - anthy_wrap.c \ - $(NULL) - -_anthy_la_CFLAGS = \ - @ANTHY_CFLAGS@ \ - @PYTHON_CFLAGS@ \ - $(NULL) - -_anthy_la_LDFLAGS = \ - @ANTHY_LIBS@ \ - @PYTHON_LIBS@ \ - -avoid-version \ - -module \ - $(NULL) - -anthy.py anthy_wrap.c: anthy.i - $(SWIG) -python $(ANTHY_CFLAGS) -I/usr/include -o anthy_wrap.c $(srcdir)/anthy.i +if ENABLE_PYTHON2 +SUBDIRS += python2 endif -libexec_SCRIPTS = ibus-engine-anthy -component_DATA = anthy.xml -componentdir = $(datadir)/ibus/component -engine_DATA = default.xml -enginedir = $(pkgdatadir)/engine - -anthy.xml: anthy.xml.in - ( \ - libexecdir=${libexecdir}; \ - pkgdatadir=${pkgdatadir}; \ - s=`cat $<`; \ - eval "echo \"$${s}\""; \ - ) > $@ - -default.xml: default.xml.in - ( \ - libexecdir=${libexecdir}; \ - pkgdatadir=${pkgdatadir}; \ - s=`cat $<`; \ - eval "echo \"$${s}\""; \ - ) > $@ - -_config.py: _config.py.in - ( \ - PKGDATADIR=$(pkgdatadir); \ - LIBEXECDIR=$(libexecdir); \ - DATADIR=$(datadir); \ - LAYOUT=$(LAYOUT); \ - SYMBOL_CHAR_INT=$(SYMBOL_CHAR_INT); \ - ICON_PREFERENCE=$(ICON_PREFERENCE); \ - s=`cat $<`; \ - eval "echo \"$${s}\""; \ - ) > $@ - -test: - $(ENV_IBUS_TEST) \ - DBUS_DEBUG=true \ - IBUS_ANTHY_PKGDATADIR=$(abs_top_srcdir) \ - PYTHONPATH=$(builddir)/.libs:@pyexecdir@ \ - $(PYTHON) \ - $(srcdir)/main.py - -EXTRA_DIST = \ - $(engine_anthy_built_in_files) \ - $(PYGTK2_ANTHY_RAW) \ - anthy.xml.in.in \ - default.xml.in.in \ - ibus-engine-anthy.in \ - $(NULL) - -CLEANFILES = \ - $(BUILT_SOURCES) \ - $(PYGTK2_ANTHY_GEN) \ - anthy.xml \ - default.xml \ - *.pyc \ - $(NULL) - -DISTCLEANFILES = \ - $(NULL) - -# Need a time lag between .py and .py.in files to build .py files -# because *_PYTHON valuables are installed in the tarball. -dist-hook: - @sleep 1; \ - for in_file in $(engine_anthy_built_in_files) ; do \ - if [ -f $(distdir)/$(srcdir)/$$in_file ] ; then \ - touch $(distdir)/$(srcdir)/$$in_file; \ - fi; \ - done; - +if ENABLE_PYTHON3 +SUBDIRS += python3 +endif diff --git a/engine/python2/Makefile.am b/engine/python2/Makefile.am new file mode 100644 index 0000000..a96f831 --- /dev/null +++ b/engine/python2/Makefile.am @@ -0,0 +1,144 @@ +# vim:set noet ts=4: +# +# ibus-anthy - The Anthy engine for IBus +# +# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com> +# Copyright (c) 2010-2013 Takao Fujiwara <takao.fujiwara1@gmail.com> +# Copyright (c) 2007-2013 Red Hat, Inc. +# +# 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 of the License, 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +BUILT_SOURCES = _config.py + +engine_anthy_PYTHON = \ + _config.py \ + engine.py \ + factory.py \ + jastring.py \ + kana.py \ + main.py \ + romaji.py \ + segment.py \ + tables.py \ + thumb.py \ + $(NULL) +engine_anthydir = $(pkgdatadir)/engine +engine_anthy_built_files = $(BUILT_SOURCES) +engine_anthy_built_in_files = $(addsuffix .in, $(engine_anthy_built_files)) + +PYGTK2_ANTHY_RAW = anthy.i +PYGTK2_ANTHY_GEN = anthy.py anthy_wrap.c + +if HAVE_PYGTK2_ANTHY +anthy_DATA = \ + anthy.py \ + $(NULL) +anthy_LTLIBRARIES = _anthy.la +anthydir = @pyexecdir@ + +_anthy_la_SOURCES = \ + $(NULL) + +nodist__anthy_la_SOURCES = \ + anthy_wrap.c \ + $(NULL) + +_anthy_la_CFLAGS = \ + @ANTHY_CFLAGS@ \ + @PYTHON_CFLAGS@ \ + $(NULL) + +_anthy_la_LDFLAGS = \ + @ANTHY_LIBS@ \ + @PYTHON_LIBS@ \ + -avoid-version \ + -module \ + $(NULL) + +anthy.py anthy_wrap.c: anthy.i + $(SWIG) -python $(ANTHY_CFLAGS) -I/usr/include -o anthy_wrap.c $(srcdir)/anthy.i +endif + +libexec_SCRIPTS = ibus-engine-anthy +component_DATA = anthy.xml +componentdir = $(datadir)/ibus/component +engine_DATA = default.xml +enginedir = $(pkgdatadir)/engine + +anthy.xml: anthy.xml.in + ( \ + libexecdir=${libexecdir}; \ + pkgdatadir=${pkgdatadir}; \ + s=`cat $<`; \ + eval "echo \"$${s}\""; \ + ) > $@ + +default.xml: default.xml.in + ( \ + libexecdir=${libexecdir}; \ + pkgdatadir=${pkgdatadir}; \ + s=`cat $<`; \ + eval "echo \"$${s}\""; \ + ) > $@ + +_config.py: _config.py.in + ( \ + PKGDATADIR=$(pkgdatadir); \ + LIBEXECDIR=$(libexecdir); \ + DATADIR=$(datadir); \ + LAYOUT=$(LAYOUT); \ + SYMBOL_CHAR_INT=$(SYMBOL_CHAR_INT); \ + ICON_PREFERENCE=$(ICON_PREFERENCE); \ + s=`cat $<`; \ + eval "echo \"$${s}\""; \ + ) > $@ + +test: + $(ENV_IBUS_TEST) \ + DBUS_DEBUG=true \ + IBUS_ANTHY_PKGDATADIR=$(abs_top_srcdir) \ + PYTHONPATH=$(builddir)/.libs:@pyexecdir@ \ + $(PYTHON) \ + $(srcdir)/main.py + +EXTRA_DIST = \ + $(engine_anthy_built_in_files) \ + $(PYGTK2_ANTHY_RAW) \ + anthy.xml.in.in \ + default.xml.in.in \ + ibus-engine-anthy.in \ + $(NULL) + +CLEANFILES = \ + $(BUILT_SOURCES) \ + $(PYGTK2_ANTHY_GEN) \ + anthy.xml \ + default.xml \ + *.pyc \ + $(NULL) + +DISTCLEANFILES = \ + $(NULL) + +# Need a time lag between .py and .py.in files to build .py files +# because *_PYTHON valuables are installed in the tarball. +dist-hook: + @sleep 1; \ + for in_file in $(engine_anthy_built_in_files) ; do \ + if [ -f $(distdir)/$(srcdir)/$$in_file ] ; then \ + touch $(distdir)/$(srcdir)/$$in_file; \ + fi; \ + done; + diff --git a/engine/_config.py.in b/engine/python2/_config.py.in index 4d5738b..4d5738b 100644 --- a/engine/_config.py.in +++ b/engine/python2/_config.py.in diff --git a/engine/anthy.i b/engine/python2/anthy.i index 68a3aa9..68a3aa9 100644 --- a/engine/anthy.i +++ b/engine/python2/anthy.i diff --git a/engine/anthy.xml.in.in b/engine/python2/anthy.xml.in.in index 9a93744..9a93744 100644 --- a/engine/anthy.xml.in.in +++ b/engine/python2/anthy.xml.in.in diff --git a/engine/default.xml.in.in b/engine/python2/default.xml.in.in index 27e3c82..27e3c82 100644 --- a/engine/default.xml.in.in +++ b/engine/python2/default.xml.in.in diff --git a/engine/engine.py b/engine/python2/engine.py index f38ebcf..be91802 100644 --- a/engine/engine.py +++ b/engine/python2/engine.py @@ -2350,7 +2350,7 @@ class Engine(IBus.EngineSimple): self.__convert_chars = UN(clipboard_text) for i in xrange(0, len(self.__convert_chars)): keyval = self.__convert_chars[i] - self.__preedit_ja_string.insert(unichr(ord (keyval))) + self.__preedit_ja_string.insert(unichr(ord(keyval))) self.__context.set_string(self.__convert_chars.encode('utf-8')) nr_segments = self.__context.get_nr_segments() @@ -2484,7 +2484,7 @@ class Engine(IBus.EngineSimple): self.__cursor_pos = 0 text, cursor = self.__get_preedit() self.__convert_chars = text - self.__context.set_string(text.encode ('utf-8')) + self.__context.set_string(text.encode('utf-8')) self.__lookup_table.clear() self.__lookup_table.set_cursor_visible(False) diff --git a/engine/factory.py b/engine/python2/factory.py index d4aa075..d4aa075 100644 --- a/engine/factory.py +++ b/engine/python2/factory.py diff --git a/engine/ibus-engine-anthy.in b/engine/python2/ibus-engine-anthy.in index c54b10a..c54b10a 100644 --- a/engine/ibus-engine-anthy.in +++ b/engine/python2/ibus-engine-anthy.in diff --git a/engine/jastring.py b/engine/python2/jastring.py index aeb7e6e..aeb7e6e 100644 --- a/engine/jastring.py +++ b/engine/python2/jastring.py diff --git a/engine/kana.py b/engine/python2/kana.py index c85a199..c85a199 100644 --- a/engine/kana.py +++ b/engine/python2/kana.py diff --git a/engine/main.py b/engine/python2/main.py index b899681..b899681 100644 --- a/engine/main.py +++ b/engine/python2/main.py diff --git a/engine/romaji.py b/engine/python2/romaji.py index 48167c6..48167c6 100644 --- a/engine/romaji.py +++ b/engine/python2/romaji.py diff --git a/engine/segment.py b/engine/python2/segment.py index d423f19..d423f19 100644 --- a/engine/segment.py +++ b/engine/python2/segment.py diff --git a/engine/tables.py b/engine/python2/tables.py index 2e41366..2e41366 100644 --- a/engine/tables.py +++ b/engine/python2/tables.py diff --git a/engine/test.py b/engine/python2/test.py index cd67997..cd67997 100644 --- a/engine/test.py +++ b/engine/python2/test.py diff --git a/engine/thumb.py b/engine/python2/thumb.py index 6a7e3d2..6a7e3d2 100644 --- a/engine/thumb.py +++ b/engine/python2/thumb.py diff --git a/engine/python3/Makefile.am b/engine/python3/Makefile.am new file mode 100644 index 0000000..a96f831 --- /dev/null +++ b/engine/python3/Makefile.am @@ -0,0 +1,144 @@ +# vim:set noet ts=4: +# +# ibus-anthy - The Anthy engine for IBus +# +# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com> +# Copyright (c) 2010-2013 Takao Fujiwara <takao.fujiwara1@gmail.com> +# Copyright (c) 2007-2013 Red Hat, Inc. +# +# 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 of the License, 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +BUILT_SOURCES = _config.py + +engine_anthy_PYTHON = \ + _config.py \ + engine.py \ + factory.py \ + jastring.py \ + kana.py \ + main.py \ + romaji.py \ + segment.py \ + tables.py \ + thumb.py \ + $(NULL) +engine_anthydir = $(pkgdatadir)/engine +engine_anthy_built_files = $(BUILT_SOURCES) +engine_anthy_built_in_files = $(addsuffix .in, $(engine_anthy_built_files)) + +PYGTK2_ANTHY_RAW = anthy.i +PYGTK2_ANTHY_GEN = anthy.py anthy_wrap.c + +if HAVE_PYGTK2_ANTHY +anthy_DATA = \ + anthy.py \ + $(NULL) +anthy_LTLIBRARIES = _anthy.la +anthydir = @pyexecdir@ + +_anthy_la_SOURCES = \ + $(NULL) + +nodist__anthy_la_SOURCES = \ + anthy_wrap.c \ + $(NULL) + +_anthy_la_CFLAGS = \ + @ANTHY_CFLAGS@ \ + @PYTHON_CFLAGS@ \ + $(NULL) + +_anthy_la_LDFLAGS = \ + @ANTHY_LIBS@ \ + @PYTHON_LIBS@ \ + -avoid-version \ + -module \ + $(NULL) + +anthy.py anthy_wrap.c: anthy.i + $(SWIG) -python $(ANTHY_CFLAGS) -I/usr/include -o anthy_wrap.c $(srcdir)/anthy.i +endif + +libexec_SCRIPTS = ibus-engine-anthy +component_DATA = anthy.xml +componentdir = $(datadir)/ibus/component +engine_DATA = default.xml +enginedir = $(pkgdatadir)/engine + +anthy.xml: anthy.xml.in + ( \ + libexecdir=${libexecdir}; \ + pkgdatadir=${pkgdatadir}; \ + s=`cat $<`; \ + eval "echo \"$${s}\""; \ + ) > $@ + +default.xml: default.xml.in + ( \ + libexecdir=${libexecdir}; \ + pkgdatadir=${pkgdatadir}; \ + s=`cat $<`; \ + eval "echo \"$${s}\""; \ + ) > $@ + +_config.py: _config.py.in + ( \ + PKGDATADIR=$(pkgdatadir); \ + LIBEXECDIR=$(libexecdir); \ + DATADIR=$(datadir); \ + LAYOUT=$(LAYOUT); \ + SYMBOL_CHAR_INT=$(SYMBOL_CHAR_INT); \ + ICON_PREFERENCE=$(ICON_PREFERENCE); \ + s=`cat $<`; \ + eval "echo \"$${s}\""; \ + ) > $@ + +test: + $(ENV_IBUS_TEST) \ + DBUS_DEBUG=true \ + IBUS_ANTHY_PKGDATADIR=$(abs_top_srcdir) \ + PYTHONPATH=$(builddir)/.libs:@pyexecdir@ \ + $(PYTHON) \ + $(srcdir)/main.py + +EXTRA_DIST = \ + $(engine_anthy_built_in_files) \ + $(PYGTK2_ANTHY_RAW) \ + anthy.xml.in.in \ + default.xml.in.in \ + ibus-engine-anthy.in \ + $(NULL) + +CLEANFILES = \ + $(BUILT_SOURCES) \ + $(PYGTK2_ANTHY_GEN) \ + anthy.xml \ + default.xml \ + *.pyc \ + $(NULL) + +DISTCLEANFILES = \ + $(NULL) + +# Need a time lag between .py and .py.in files to build .py files +# because *_PYTHON valuables are installed in the tarball. +dist-hook: + @sleep 1; \ + for in_file in $(engine_anthy_built_in_files) ; do \ + if [ -f $(distdir)/$(srcdir)/$$in_file ] ; then \ + touch $(distdir)/$(srcdir)/$$in_file; \ + fi; \ + done; + diff --git a/engine/python3/_config.py.in b/engine/python3/_config.py.in new file mode 100644 index 0000000..f68b50a --- /dev/null +++ b/engine/python3/_config.py.in @@ -0,0 +1,30 @@ +# vim:set et sts=4 sw=4: +# -*- coding: utf-8 -*- +# +# ibus-anthy - The Anthy engine for IBus +# +# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com> +# Copyright (c) 2010-2014 Takao Fujiwara <takao.fujiwara1@gmail.com> +# Copyright (c) 2007-2014 Red Hat, Inc. +# +# 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 of the License, 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +PKGDATADIR = '${PKGDATADIR}' +LIBEXECDIR = '${LIBEXECDIR}' +LOCALEDIR = '${DATADIR}/locale' +LAYOUT = '${LAYOUT}' +SYMBOL_CHAR = chr(${SYMBOL_CHAR_INT}) +ICON_PREFERENCE = '${ICON_PREFERENCE}' +DEBUG = False diff --git a/engine/python3/anthy.i b/engine/python3/anthy.i new file mode 100644 index 0000000..68a3aa9 --- /dev/null +++ b/engine/python3/anthy.i @@ -0,0 +1,125 @@ +/* vim:set et ts=4: */ +/* + * ibus-anthy - The Anthy engine for IBus + * + * Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com> + * Copyright (c) 2010-2013 Takao Fujiwara <takao.fujiwara1@gmail.com> + * Copyright (c) 2007-2013 Red Hat, Inc. + * + * 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 of the License, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +%module anthy +%{ + /* Put header files here or function declarations like below */ +#include <anthy/anthy.h> +%} + +%init %{ + anthy_init (); +%} + +/* anthy_context_t */ +%include anthy/anthy.h +struct anthy_context {}; +%extend anthy_context { + anthy_context () { + return anthy_create_context (); + } + + void reset () { + anthy_reset_context (self); + } + + int set_string (char *str) { + return anthy_set_string (self, str); + } + + void resize_segment (int a1, int a2) { + anthy_resize_segment (self, a1, a2); + } + + int get_stat (struct anthy_conv_stat *a1) { + return anthy_get_stat (self, a1); + } + + int get_segment_stat (int a1, struct anthy_segment_stat *a2) { + return anthy_get_segment_stat (self, a1, a2); + } + + char *get_segment (int a1, int a2) { + int len; + static char temp[512]; + + len = anthy_get_segment (self, a1, a2, temp, sizeof (temp)); + if (len >= 0) + return temp; + else + return NULL; + } + + int commit_segment (int a1, int a2) { + return anthy_commit_segment (self, a1, a2); + } + + int set_prediction_string (const char *a1) { + return anthy_set_prediction_string (self, a1); + } + + int get_prediction_stat (struct anthy_prediction_stat *a1) { + return anthy_get_prediction_stat (self, a1); + } + + char *get_prediction (int a1) { + int len; + static char temp[512]; + + len = anthy_get_prediction (self, a1, temp, sizeof (temp)); + + if (len >= 0) + return temp; + else + return NULL; + } + + int commit_prediction (int a1) { + return anthy_commit_prediction(self, a1); + } + + void _print () { + anthy_print_context (self); + } + + int _set_encoding (int encoding) { + return anthy_context_set_encoding (self, encoding); + } + + int set_reconversion_mode (int mode) { + return anthy_set_reconversion_mode (self, mode); + } + + int init_personality (void) { + return anthy_init_personality (); + } + + int do_set_personality (const char *id) { + return anthy_do_set_personality (id); + } + + ~anthy_context () { + anthy_release_context (self); + } +}; + diff --git a/engine/python3/anthy.xml.in.in b/engine/python3/anthy.xml.in.in new file mode 100644 index 0000000..9a93744 --- /dev/null +++ b/engine/python3/anthy.xml.in.in @@ -0,0 +1,19 @@ +<?xml version=\"1.0\" encoding=\"utf-8\"?> +<!-- filename: anthy.xml --> +<component> + <name>org.freedesktop.IBus.Anthy</name> + <description>Anthy Component</description> + <exec>${libexecdir}/ibus-engine-anthy --ibus</exec> + <version>@VERSION@</version> + <author>Peng Huang <shawn.p.huang@gmail.com></author> + <license>GPL</license> + <homepage>http://code.google.com/p/ibus</homepage> + <textdomain>ibus-anthy</textdomain> + + <!-- for engines --> + <observed-paths> + <path>~/.config/ibus-anthy/engines.xml</path> + <path>${pkgdatadir}/engine/default.xml</path> + </observed-paths> + <engines exec=\"${libexecdir}/ibus-engine-anthy --xml\" /> +</component> diff --git a/engine/python3/default.xml.in.in b/engine/python3/default.xml.in.in new file mode 100644 index 0000000..27e3c82 --- /dev/null +++ b/engine/python3/default.xml.in.in @@ -0,0 +1,19 @@ +<?xml version=\"1.0\" encoding=\"utf-8\"?> +<engines> + <engine> + <name>anthy</name> + <language>ja</language> + <license>GPL</license> + <author>Peng Huang <shawn.p.huang@gmail.com></author> + <icon>ibus-anthy</icon> + @LAYOUT_XML@ + <layout_variant></layout_variant> + <layout_option></layout_option> + <longname>Anthy</longname> + <description>Anthy Input Method</description> + <rank>99</rank> + @HOTKEYS_XML@ + @SYMBOL_XML@ + <version>@PACKAGE_VERSION@</version> + </engine> +</engines> diff --git a/engine/python3/engine.py b/engine/python3/engine.py new file mode 100644 index 0000000..2119c39 --- /dev/null +++ b/engine/python3/engine.py @@ -0,0 +1,2780 @@ +# vim:set et sts=4 sw=4: +# -*- coding: utf-8 -*- +# +# ibus-anthy - The Anthy engine for IBus +# +# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com> +# Copyright (c) 2010-2014 Takao Fujiwara <takao.fujiwara1@gmail.com> +# Copyright (c) 2007-2014 Red Hat, Inc. +# +# 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 of the License, 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import binascii +import os +from os import environ, path +import signal +import sys +from gettext import dgettext + +from main import get_userhome + +try: + from locale import getpreferredencoding +except: + pass + +from gi.repository import GLib +from gi.repository import IBus + +from gi.repository import Anthy +NTH_UNCONVERTED_CANDIDATE = Anthy.NTH_UNCONVERTED_CANDIDATE +NTH_KATAKANA_CANDIDATE = Anthy.NTH_KATAKANA_CANDIDATE +NTH_HIRAGANA_CANDIDATE = Anthy.NTH_HIRAGANA_CANDIDATE +NTH_HALFKANA_CANDIDATE = Anthy.NTH_HALFKANA_CANDIDATE + +import _config as config +from tables import * +import jastring +from segment import unichar_half_to_full + +sys.path.append(path.join(config.PKGDATADIR, 'setup')) +from anthyprefs import AnthyPrefs + +_ = lambda a : dgettext('ibus-anthy', a) +N_ = lambda a : a +UN = lambda a : unicode(a, 'utf-8') + +printerr = AnthyPrefs.printerr + +INPUT_MODE_HIRAGANA, \ +INPUT_MODE_KATAKANA, \ +INPUT_MODE_HALF_WIDTH_KATAKANA, \ +INPUT_MODE_LATIN, \ +INPUT_MODE_WIDE_LATIN = list(range(5)) + +CONV_MODE_OFF, \ +CONV_MODE_ANTHY, \ +CONV_MODE_HIRAGANA, \ +CONV_MODE_KATAKANA, \ +CONV_MODE_HALF_WIDTH_KATAKANA, \ +CONV_MODE_LATIN_0, \ +CONV_MODE_LATIN_1, \ +CONV_MODE_LATIN_2, \ +CONV_MODE_LATIN_3, \ +CONV_MODE_WIDE_LATIN_0, \ +CONV_MODE_WIDE_LATIN_1, \ +CONV_MODE_WIDE_LATIN_2, \ +CONV_MODE_WIDE_LATIN_3, \ +CONV_MODE_PREDICTION = list(range(14)) + +SEGMENT_DEFAULT = 0 +SEGMENT_SINGLE = 1 << 0 +SEGMENT_IMMEDIATE = 1 << 1 + +CLIPBOARD_RECONVERT = list(range(1)) + +LINK_DICT_EMBEDDED, \ +LINK_DICT_SINGLE = list(range(2)) + +IMPORTED_EMBEDDED_DICT_DIR = 'imported_words_default.d' +IMPORTED_EMBEDDED_DICT_PREFIX = 'ibus__' +IMPORTED_SINGLE_DICT_PREFIX = 'imported_words_ibus__' + +KP_Table = {} +for s in dir(IBus): + if s.startswith('KEY_KP_'): + v = IBus.keyval_from_name(s[7:]) + if v: + KP_Table[IBus.keyval_from_name(s[4:])] = v +for k, v in zip(['KEY_KP_Add', 'KEY_KP_Decimal', 'KEY_KP_Divide', 'KEY_KP_Enter', + 'KEY_KP_Equal', 'KEY_KP_Multiply', 'KEY_KP_Separator', + 'KEY_KP_Space', 'KEY_KP_Subtract'], + ['KEY_plus', 'KEY_period', 'KEY_slash', 'KEY_Return', + 'KEY_equal', 'KEY_asterisk', 'KEY_comma', + 'KEY_space', 'KEY_minus']): + KP_Table[getattr(IBus, k)] = getattr(IBus, v) + +class Engine(IBus.EngineSimple): + __input_mode = None + __typing_mode = None + __segment_mode = None + __dict_mode = None + + __setup_pid = 0 + __prefs = None + __keybind = {} + __thumb = None + __latin_with_shift = True + + def __init__(self, bus, object_path): + super(Engine, self).__init__(engine_name="anthy", + connection=bus.get_connection(), + object_path=object_path) + + # create anthy context + self.__context = Anthy.GContext() + self.__context.set_encoding(Anthy.UTF8_ENCODING) + + # init state + self.__idle_id = 0 + self.__prop_dict = {} + self.__input_purpose = 0 + self.__has_input_purpose = False + if hasattr(IBus, 'InputPurpose'): + self.__has_input_purpose = True + try: + self.__is_utf8 = (getpreferredencoding().lower() == 'utf-8') + except: + self.__is_utf8 = False + self.__ibus_version = 0.0 + +# self.__lookup_table = ibus.LookupTable.new(page_size=9, +# cursor_pos=0, +# cursor_visible=True, +# round=True) + size = self.__prefs.get_value('common', 'page_size') + self.__lookup_table = IBus.LookupTable.new(page_size=size, + cursor_pos=0, + cursor_visible=True, + round=True) + self.__prop_list = self.__init_props() + + # Do not use self.do_process_key_event to work ISO 14755 + # with Ctrl+Shift+u . + # The super (parent) method of do_process_key_event is called + # loop infinitely if this class overrides it. + # self.process_key_event is not accessible too. + self.connect('process-key-event', self.__process_key_event) + self.connect('destroy', self.__destroy) + + self.__init_signal() + # use reset to init values + self.__reset() + + ibus_config = bus.get_config() + if ibus_config != None: + ibus_config.connect('value-changed', + self.__config_value_changed_cb) + + def __get_ibus_version(self): + if self.__ibus_version == 0.0: + self.__ibus_version = \ + IBus.MAJOR_VERSION + IBus.MINOR_VERSION / 1000.0 + \ + IBus.MICRO_VERSION / 1000000.0 + return self.__ibus_version + + # reset values of engine + def __reset(self): + self.__preedit_ja_string = jastring.JaString(Engine.__typing_mode, + self.__latin_with_shift) + self.__convert_chars = '' + self.__cursor_pos = 0 + self.__convert_mode = CONV_MODE_OFF + self.__segments = list() + self.__lookup_table.clear() + self.__lookup_table_visible = False + self._MM = 0 + self._SS = 0 + self._H = 0 + self._RMM = 0 + self._RSS = 0 + if self.__idle_id != 0: + GLib.source_remove(self.__idle_id) + self.__idle_id = 0 + + def __init_props(self): + anthy_props = IBus.PropList() + + self.__set_input_mode_props(anthy_props) + self.__set_typing_method_props(anthy_props) + self.__set_segment_mode_props(anthy_props) + self.__set_dict_mode_props(anthy_props) + self.__set_dict_config_props(anthy_props) + + if not self.__prefs.get_value('common', 'show-preferences'): + return anthy_props + + anthy_props.append(IBus.Property(key='setup', + label=IBus.Text.new_from_string(_("Preferences - Anthy")), + icon=config.ICON_PREFERENCE, + tooltip=IBus.Text.new_from_string(_("Configure Anthy")), + sensitive=True, + visible=True)) + + return anthy_props + + def __init_signal(self): + signal.signal(signal.SIGHUP, self.__signal_cb) + signal.signal(signal.SIGINT, self.__signal_cb) + signal.signal(signal.SIGQUIT, self.__signal_cb) + signal.signal(signal.SIGABRT, self.__signal_cb) + signal.signal(signal.SIGTERM, self.__signal_cb) + + def __signal_cb(self, signum, object): + self.__remove_dict_files() + signal.signal(signum, signal.SIG_DFL) + os.kill(os.getpid(), signum) + + def __set_input_mode_props(self, anthy_props): + # The class method is kept even if the engine is switched. + if Engine.__input_mode == None: + # The config value is readonly for initial engine and + # the engine keeps the class method in the memory. + Engine.__input_mode = INPUT_MODE_HIRAGANA + Engine.__input_mode = self.__prefs.get_value('common', + 'input_mode') + + if not self.__prefs.get_value('common', 'show-input-mode'): + return + + # init input mode properties + symbol = 'あ' + ''' + Need to split _() by line for intltool to detect them. + ''' + # Translators: Specify the order of %s with your translation. + # It will be "Input Mode (A)" for example. + label = _("%(description)s (%(symbol)s)") % \ + { 'description' : _("Input mode"), 'symbol' : symbol } + input_mode_prop = IBus.Property(key='InputMode', + prop_type=IBus.PropType.MENU, + label=IBus.Text.new_from_string(label), + symbol=IBus.Text.new_from_string(symbol), + icon='', + tooltip=IBus.Text.new_from_string(_("Switch input mode")), + sensitive=True, + visible=True, + state=IBus.PropState.UNCHECKED, + sub_props=None) + self.__prop_dict['InputMode'] = input_mode_prop + + props = IBus.PropList() + props.append(IBus.Property(key='InputMode.Hiragana', + prop_type=IBus.PropType.RADIO, + label=IBus.Text.new_from_string(_("Hiragana")), + icon=None, + tooltip=None, + sensitive=True, + visible=True, + state=IBus.PropState.UNCHECKED, + sub_props=None)) + props.append(IBus.Property(key='InputMode.Katakana', + prop_type=IBus.PropType.RADIO, + label=IBus.Text.new_from_string(_("Katakana")), + icon=None, + tooltip=None, + sensitive=True, + visible=True, + state=IBus.PropState.UNCHECKED, + sub_props=None)) + props.append(IBus.Property(key='InputMode.HalfWidthKatakana', + prop_type=IBus.PropType.RADIO, + label=IBus.Text.new_from_string(_("Halfwidth Katakana")), + icon=None, + tooltip=None, + sensitive=True, + visible=True, + state=IBus.PropState.UNCHECKED, + sub_props=None)) + props.append(IBus.Property(key='InputMode.Latin', + prop_type=IBus.PropType.RADIO, + label=IBus.Text.new_from_string(_("Latin")), + icon=None, + tooltip=None, + sensitive=True, + visible=True, + state=IBus.PropState.UNCHECKED, + sub_props=None)) + props.append(IBus.Property(key='InputMode.WideLatin', + prop_type=IBus.PropType.RADIO, + label=IBus.Text.new_from_string(_("Wide Latin")), + icon=None, + tooltip=None, + sensitive=True, + visible=True, + state=IBus.PropState.UNCHECKED, + sub_props=None)) + + props.get(Engine.__input_mode).set_state(IBus.PropState.CHECKED) + + i = 0 + while props.get(i) != None: + prop = props.get(i) + self.__prop_dict[prop.get_key()] = prop + i += 1 + + input_mode_prop.set_sub_props(props) + anthy_props.append(input_mode_prop) + + mode = Engine.__input_mode + mode = 'InputMode.' + ['Hiragana', 'Katakana', 'HalfWidthKatakana', + 'Latin', 'WideLatin'][mode] + self.__input_mode_activate(mode, IBus.PropState.CHECKED) + + def __set_typing_method_props(self, anthy_props): + if Engine.__typing_mode == None: + Engine.__typing_mode = jastring.TYPING_MODE_ROMAJI + Engine.__typing_mode = self.__prefs.get_value('common', + 'typing_method') + + if not self.__prefs.get_value('common', 'show-typing-method'): + return + + # typing input mode properties + symbol = 'R' + label = _("%(description)s (%(symbol)s)") % \ + { 'description' : _("Typing method"), 'symbol' : symbol } + typing_mode_prop = IBus.Property(key='TypingMode', + prop_type=IBus.PropType.MENU, + label=IBus.Text.new_from_string(label), + symbol=IBus.Text.new_from_string(symbol), + icon='', + tooltip=IBus.Text.new_from_string(_("Switch typing method")), + sensitive=True, + visible=True, + state=IBus.PropState.UNCHECKED, + sub_props=None) + self.__prop_dict['TypingMode'] = typing_mode_prop + + props = IBus.PropList() + props.append(IBus.Property(key='TypingMode.Romaji', + prop_type=IBus.PropType.RADIO, + label=IBus.Text.new_from_string(_("Romaji")), + icon=None, + tooltip=None, + sensitive=True, + visible=True, + state=IBus.PropState.UNCHECKED, + sub_props=None)) + props.append(IBus.Property(key='TypingMode.Kana', + prop_type=IBus.PropType.RADIO, + label=IBus.Text.new_from_string(_("Kana")), + icon=None, + tooltip=None, + sensitive=True, + visible=True, + state=IBus.PropState.UNCHECKED, + sub_props=None)) + props.append(IBus.Property(key='TypingMode.ThumbShift', + prop_type=IBus.PropType.RADIO, + label=IBus.Text.new_from_string(_("Thumb shift")), + icon=None, + tooltip=None, + sensitive=True, + visible=True, + state=IBus.PropState.UNCHECKED, + sub_props=None)) + props.get(Engine.__typing_mode).set_state(IBus.PropState.CHECKED) + + i = 0 + while props.get(i) != None: + prop = props.get(i) + self.__prop_dict[prop.get_key()] = prop + i += 1 + + typing_mode_prop.set_sub_props(props) + anthy_props.append(typing_mode_prop) + + mode = Engine.__typing_mode + mode = 'TypingMode.' + ['Romaji', 'Kana', 'ThumbShift'][mode] + self.__typing_mode_activate(mode, IBus.PropState.CHECKED) + + def __set_segment_mode_props(self, anthy_props): + if Engine.__segment_mode == None: + Engine.__segment_mode = SEGMENT_DEFAULT + Engine.__segment_mode = self.__prefs.get_value('common', + 'conversion_segment_mode') + + if not self.__prefs.get_value('common', 'show-segment-mode'): + return + + symbol = '連' + label = _("%(description)s (%(symbol)s)") % \ + { 'description' : _("Segment mode"), 'symbol' : symbol } + segment_mode_prop = IBus.Property(key='SegmentMode', + prop_type=IBus.PropType.MENU, + label=IBus.Text.new_from_string(label), + symbol=IBus.Text.new_from_string(symbol), + icon=None, + tooltip=IBus.Text.new_from_string(_("Switch conversion mode")), + sensitive=True, + visible=True, + state=IBus.PropState.UNCHECKED, + sub_props=None) + self.__prop_dict['SegmentMode'] = segment_mode_prop + + props = IBus.PropList() + props.append(IBus.Property(key='SegmentMode.Multi', + prop_type=IBus.PropType.RADIO, + label=IBus.Text.new_from_string(_("Multiple segment")), + icon=None, + tooltip=None, + sensitive=True, + visible=True, + state=IBus.PropState.UNCHECKED, + sub_props=None)) + props.append(IBus.Property(key='SegmentMode.Single', + prop_type=IBus.PropType.RADIO, + label=IBus.Text.new_from_string(_("Single segment")), + icon=None, + tooltip=None, + sensitive=True, + visible=True, + state=IBus.PropState.UNCHECKED, + sub_props=None)) + props.append(IBus.Property(key='SegmentMode.ImmediateMulti', + prop_type=IBus.PropType.RADIO, + label=IBus.Text.new_from_string(_("Immediate conversion (multiple segment)")), + icon=None, + tooltip=None, + sensitive=True, + visible=True, + state=IBus.PropState.UNCHECKED, + sub_props=None)) + props.append(IBus.Property(key='SegmentMode.ImmediateSingle', + prop_type=IBus.PropType.RADIO, + label=IBus.Text.new_from_string(_("Immediate conversion (single segment)")), + icon=None, + tooltip=None, + sensitive=True, + visible=True, + state=IBus.PropState.UNCHECKED, + sub_props=None)) + props.get(Engine.__segment_mode).set_state(IBus.PropState.CHECKED) + + i = 0 + while props.get(i) != None: + prop = props.get(i) + self.__prop_dict[prop.get_key()] = prop + i += 1 + + segment_mode_prop.set_sub_props(props) + anthy_props.append(segment_mode_prop) + + mode = Engine.__segment_mode + mode = 'SegmentMode.' + ['Multi', 'Single', + 'ImmediateMulti', 'ImmediateSingle'][mode] + self.__segment_mode_activate(mode, IBus.PropState.CHECKED) + + def __set_dict_mode_props(self, anthy_props, update_prop=False): + if Engine.__dict_mode == None: + Engine.__dict_mode = 0 + + if not self.__prefs.get_value('common', 'show-dict-mode'): + return + + short_label = self.__prefs.get_value('dict/file/embedded', + 'short_label') + label = _("%(description)s (%(symbol)s)") % \ + { 'description' : _("Dictionary mode"), 'symbol' : short_label } + dict_mode_prop = IBus.Property(key='DictMode', + prop_type=IBus.PropType.MENU, + label=IBus.Text.new_from_string(label), + symbol=IBus.Text.new_from_string(short_label), + icon=None, + tooltip=IBus.Text.new_from_string(_("Switch dictionary")), + sensitive=True, + visible=True, + state=IBus.PropState.UNCHECKED, + sub_props=None) + self.__prop_dict['DictMode'] = dict_mode_prop + props = IBus.PropList() + + long_label = self.__prefs.get_value('dict/file/embedded', + 'long_label') + props.append(IBus.Property(key='DictMode.embedded', + prop_type=IBus.PropType.RADIO, + # if long_label is UTF-8 + label=IBus.Text.new_from_string(_(long_label)), + icon=None, + tooltip=None, + sensitive=True, + visible=True, + state=IBus.PropState.UNCHECKED, + sub_props=None)) + for file in self.__prefs.get_value('dict', 'files'): + if not self.__link_dict_file(file): + continue + id = self.__get_dict_id_from_file(file) + section = 'dict/file/' + id + if not self.__prefs.get_value(section, 'single'): + continue + key = 'DictMode.' + id + long_label = self.__prefs.get_value(section, 'long_label') + + # ibus-config 'value-changed' signal updated dict/files but + # not dict/file/new yet. + if long_label == None: + continue + + if 'is_system' in self.__prefs.keys(section) and \ + self.__prefs.get_value(section, 'is_system'): + uni_long_label = _(long_label) + else: + uni_long_label = long_label + props.append(IBus.Property(key=key, + prop_type=IBus.PropType.RADIO, + label=IBus.Text.new_from_string(uni_long_label), + icon=None, + tooltip=None, + sensitive=True, + visible=True, + state=IBus.PropState.UNCHECKED, + sub_props=None)) + + props.get(Engine.__dict_mode).set_state(IBus.PropState.CHECKED) + + i = 0 + while props.get(i) != None: + prop = props.get(i) + self.__prop_dict[prop.get_key()] = prop + i += 1 + + dict_mode_prop.set_sub_props(props) + + if update_prop: + # focus-in event will call register_properties(). + # Need to switch another IME to update menus on GtkStatusIcon? + anthy_props.update_property(dict_mode_prop) + else: + anthy_props.append(dict_mode_prop) + + prop_name = self.__dict_mode_get_prop_name(Engine.__dict_mode) + if prop_name == None: + return + self.__dict_mode_activate(prop_name, + IBus.PropState.CHECKED) + + def __set_dict_config_props(self, anthy_props): + if not self.__prefs.get_value('common', 'show-dict-config'): + return + + admin_command = self.__prefs.get_value('common', 'dict_admin_command') + icon_path = self.__prefs.get_value('common', 'dict_config_icon') + + if not path.exists(admin_command[0]): + return + label = _("Dictionary - Anthy") + if icon_path and path.exists(icon_path): + icon = icon_path + else: + # Translators: "Dic" means 'dictionary', One kanji may be good. + label = _("Dic") + icon = '' + + dict_prop = IBus.Property(key='setup-dict-kasumi', + prop_type=IBus.PropType.MENU, + label=IBus.Text.new_from_string(label), + icon=icon, + tooltip=IBus.Text.new_from_string(_("Configure dictionaries")), + sensitive=True, + visible=True, + state=IBus.PropState.UNCHECKED, + sub_props=None) + self.__prop_dict['setup-dict-kasumi'] = dict_prop + + props = IBus.PropList() + props.append(IBus.Property(key='setup-dict-kasumi-admin', + prop_type=IBus.PropType.NORMAL, + label=IBus.Text.new_from_string(_("Edit dictionaries")), + icon=icon, + tooltip=IBus.Text.new_from_string(_("Launch the dictionary tool")), + sensitive=True, + visible=True, + state=IBus.PropState.UNCHECKED, + sub_props=None)) + props.append(IBus.Property(key='setup-dict-kasumi-word', + prop_type=IBus.PropType.NORMAL, + label=IBus.Text.new_from_string(_("Add words")), + icon=icon, + tooltip=IBus.Text.new_from_string(_("Add words to the dictionary")), + sensitive=True, + visible=True, + state=IBus.PropState.UNCHECKED, + sub_props=None)) + + i = 0 + while props.get(i) != None: + prop = props.get(i) + self.__prop_dict[prop.get_key()] = prop + i += 1 + + dict_prop.set_sub_props(props) + anthy_props.append(dict_prop) + + def __get_clipboard(self, clipboard, text, data): + clipboard_text = clipboard.wait_for_text () + + if data == CLIPBOARD_RECONVERT: + self.__update_reconvert(clipboard_text) + + return clipboard_text + + def __get_single_dict_files(self): + files = self.__prefs.get_value('dict', 'files') + single_files = [] + for file in files: + if not path.exists(file): + continue + id = self.__get_dict_id_from_file(file) + section = 'dict/file/' + id + if self.__prefs.get_value(section, 'single'): + single_files.append(file) + return single_files + + def __remove_dict_files(self): + for file in self.__prefs.get_value('dict', 'files'): + self.__remove_dict_file(file) + + def update_preedit(self, string, attrs, cursor_pos, visible): + text = IBus.Text.new_from_string(string) + i = 0 + while attrs.get(i) != None: + attr = attrs.get(i) + text.append_attribute(attr.get_attr_type(), + attr.get_value(), + attr.get_start_index(), + attr.get_end_index()) + i += 1 + mode = self.__prefs.get_value('common', 'behavior_on_focus_out') + if self.__get_ibus_version() >= 1.003 and mode == 1: + self.update_preedit_text_with_mode(text, + cursor_pos, visible, + IBus.PreeditFocusMode.COMMIT) + else: + self.update_preedit_text(text, + cursor_pos, visible) + + def update_aux_string(self, string, attrs, visible): + text = IBus.Text.new_from_string(string) + i = 0 + while attrs.get(i) != None: + attr = attrs.get(i) + text.append_attribute(attr.get_attr_type(), + attr.get_value(), + attr.get_start_index(), + attr.get_end_index()) + i += 1 + self.update_auxiliary_text(text, visible) + + def do_page_up(self): + # only process cursor down in convert mode + if self.__convert_mode != CONV_MODE_ANTHY: + return False + + if not self.__lookup_table.page_up(): + return False + + index = self.__lookup_table.get_cursor_pos() + candidate = self.__lookup_table.get_candidate(index).get_text() + self.__segments[self.__cursor_pos] = index, candidate + self.__invalidate() + return True + + def do_page_down(self): + # only process cursor down in convert mode + if self.__convert_mode != CONV_MODE_ANTHY: + return False + + if not self.__lookup_table.page_down(): + return False + + index = self.__lookup_table.get_cursor_pos() + candidate = self.__lookup_table.get_candidate(index).get_text() + self.__segments[self.__cursor_pos] = index, candidate + self.__invalidate() + return True + + def do_cursor_up(self): + # only process cursor down in convert mode + # if self.__convert_mode != CONV_MODE_ANTHY: + if self.__convert_mode != CONV_MODE_ANTHY and self.__convert_mode != CONV_MODE_PREDICTION: + return False + + if not self.__lookup_table.cursor_up(): + return False + + index = self.__lookup_table.get_cursor_pos() + candidate = self.__lookup_table.get_candidate(index).get_text() + self.__segments[self.__cursor_pos] = index, candidate + self.__invalidate() + return True + + def do_cursor_down(self): + # only process cursor down in convert mode + # if self.__convert_mode != CONV_MODE_ANTHY: + if self.__convert_mode != CONV_MODE_ANTHY and self.__convert_mode != CONV_MODE_PREDICTION: + return False + + if not self.__lookup_table.cursor_down(): + return False + + index = self.__lookup_table.get_cursor_pos() + candidate = self.__lookup_table.get_candidate(index).get_text() + self.__segments[self.__cursor_pos] = index, candidate + self.__invalidate() + return True + + def do_candidate_clicked(self, index, button, state): + if index == 9: + keyval = IBus.KEY_0 + else: + keyval = IBus.KEY_1 + index + self.__on_key_number(keyval) + + def __commit_string(self, text): + self.__reset() + self.commit_text(IBus.Text.new_from_string(text)) + self.__invalidate() + + def __shrink_segment(self, relative_size): + self.__context.resize_segment(self.__cursor_pos, relative_size) + nr_segments = self.__context.get_nr_segments() + del self.__segments[self.__cursor_pos:] + for i in range(self.__cursor_pos, nr_segments): + buf = self.__context.get_segment(i, 0) + text = buf + self.__segments.append((0, text)) + self.__lookup_table_visible = False + self.__fill_lookup_table() + self.__invalidate() + return True + + def do_property_activate(self, prop_name, state): + + if state == IBus.PropState.CHECKED: + if prop_name == None: + return + elif prop_name.startswith('InputMode.'): + self.__input_mode_activate(prop_name, state) + return + elif prop_name.startswith('TypingMode.'): + self.__typing_mode_activate(prop_name, state) + return + elif prop_name.startswith('SegmentMode.'): + self.__segment_mode_activate(prop_name, state) + return + elif prop_name.startswith('DictMode.'): + self.__dict_mode_activate(prop_name, state) + return + else: + if prop_name == 'setup': + self.__start_setup() + elif prop_name == 'setup-dict-kasumi-admin': + self.__start_dict_admin() + elif prop_name == 'setup-dict-kasumi-word': + self.__start_add_word() + else: + self.__prop_dict[prop_name].set_state(state) + if prop_name == 'DictMode': + sub_name = self.__dict_mode_get_prop_name(self.__dict_mode) + if sub_name == None: + return + self.__dict_mode_activate(sub_name, + IBus.PropState.CHECKED) + + def __input_mode_activate(self, prop_name, state): + input_modes = { + 'InputMode.Hiragana' : (INPUT_MODE_HIRAGANA, 'あ'), + 'InputMode.Katakana' : (INPUT_MODE_KATAKANA, 'ア'), + 'InputMode.HalfWidthKatakana' : (INPUT_MODE_HALF_WIDTH_KATAKANA, '_ア'), + 'InputMode.Latin' : (INPUT_MODE_LATIN, '_A'), + 'InputMode.WideLatin' : (INPUT_MODE_WIDE_LATIN, 'A'), + } + + if prop_name not in input_modes: + printerr('Unknown prop_name = %s' % prop_name) + return + self.__prop_dict[prop_name].set_state(state) + self.update_property(self.__prop_dict[prop_name]) + + mode, symbol = input_modes[prop_name] + + label = _("%(description)s (%(symbol)s)") % \ + { 'description' : _("Input mode"), 'symbol' : symbol } + Engine.__input_mode = mode + prop = self.__prop_dict['InputMode'] + prop.set_symbol(IBus.Text.new_from_string(symbol)) + prop.set_label(IBus.Text.new_from_string(label)) + self.update_property(prop) + + self.__reset() + self.__invalidate() + + def __typing_mode_activate(self, prop_name, state): + typing_modes = { + 'TypingMode.Romaji' : (jastring.TYPING_MODE_ROMAJI, 'R'), + 'TypingMode.Kana' : (jastring.TYPING_MODE_KANA, 'か'), + 'TypingMode.ThumbShift' : (jastring.TYPING_MODE_THUMB_SHIFT, '親'), + } + + if prop_name not in typing_modes: + printerr('Unknown prop_name = %s' % prop_name) + return + self.__prop_dict[prop_name].set_state(state) + self.update_property(self.__prop_dict[prop_name]) + if prop_name == 'TypingMode.ThumbShift': + self._reset_thumb() + + mode, symbol = typing_modes[prop_name] + + label = _("%(description)s (%(symbol)s)") % \ + { 'description' : _("Typing method"), 'symbol' : symbol } + Engine.__typing_mode = mode + prop = self.__prop_dict['TypingMode'] + prop.set_symbol(IBus.Text.new_from_string(symbol)) + prop.set_label(IBus.Text.new_from_string(label)) + self.update_property(prop) + + self.__reset() + self.__invalidate() + + def __refresh_typing_mode_property(self): + if 'TypingMode' not in self.__prop_dict: + return + + prop = self.__prop_dict['TypingMode'] + modes = { + jastring.TYPING_MODE_ROMAJI : ('TypingMode.Romaji', 'R'), + jastring.TYPING_MODE_KANA : ('TypingMode.Kana', 'か'), + jastring.TYPING_MODE_THUMB_SHIFT : ('TypingMode.ThumbShift', '親'), + } + prop_name, symbol = modes.get(Engine.__typing_mode, (None, None)) + if prop_name == None or symbol == None: + return + label = _("%(description)s (%(symbol)s)") % \ + { 'description' : _("Typing method"), 'symbol' : symbol } + _prop = self.__prop_dict[prop_name] + _prop.set_state(IBus.PropState.CHECKED) + self.update_property(_prop) + prop.set_symbol(IBus.Text.new_from_string(symbol)) + prop.set_label(IBus.Text.new_from_string(label)) + self.update_property(prop) + + def __segment_mode_activate(self, prop_name, state): + segment_modes = { + 'SegmentMode.Multi' : (SEGMENT_DEFAULT, '連'), + 'SegmentMode.Single' : (SEGMENT_SINGLE, '単'), + 'SegmentMode.ImmediateMulti' : (SEGMENT_IMMEDIATE, '逐|連'), + 'SegmentMode.ImmediateSingle' : + (SEGMENT_IMMEDIATE | SEGMENT_SINGLE, '逐|単'), + } + + if prop_name not in segment_modes: + printerr('Unknown prop_name = %s' % prop_name) + return + self.__prop_dict[prop_name].set_state(state) + self.update_property(self.__prop_dict[prop_name]) + + mode, symbol = segment_modes[prop_name] + + label = _("%(description)s (%(symbol)s)") % \ + { 'description' : _("Segment mode"), 'symbol' : symbol } + Engine.__segment_mode = mode + prop = self.__prop_dict['SegmentMode'] + prop.set_symbol(IBus.Text.new_from_string(symbol)) + prop.set_label(IBus.Text.new_from_string(label)) + self.update_property(prop) + + self.__reset() + self.__invalidate() + + def __dict_mode_get_prop_name(self, mode): + if mode == 0: + id = 'embedded' + else: + single_files = self.__get_single_dict_files() + file = single_files[mode - 1] + id = self.__get_dict_id_from_file(file) + return 'DictMode.' + id + + def __dict_mode_activate(self, prop_name, state): + if prop_name not in list(self.__prop_dict.keys()): + # The prop_name is added. Need to restart. + return + i = prop_name.find('.') + if i < 0: + return + # The id is already quoted. + id = prop_name[i + 1:] + + file = None + single_files = self.__get_single_dict_files() + + if id == 'embedded': + pass + else: + found = False + for file in single_files: + if id == self.__get_quoted_id(file): + found = True + break + if found == False: + return + + if id == 'embedded': + dict_name = 'default' + Engine.__dict_mode = 0 + else: + if file not in single_files: + printerr('Index error', file, single_files) + return + dict_name = 'ibus__' + id + Engine.__dict_mode = single_files.index(file) + 1 + self.__prop_dict[prop_name].set_state(state) + self.update_property(self.__prop_dict[prop_name]) + self.__context.init_personality() + # dict_name is unicode but the argument is str. + self.__context.do_set_personality(str(dict_name)) + + prop = self.__prop_dict['DictMode'] + section = 'dict/file/' + id + symbol = self.__prefs.get_value(section, 'short_label') + label = _("%(description)s (%(symbol)s)") % \ + { 'description' : _("Dictionary mode"), 'symbol' : symbol } + prop.set_symbol(IBus.Text.new_from_string(symbol)) + prop.set_label(IBus.Text.new_from_string(label)) + self.update_property(prop) + + def __argb(self, a, r, g, b): + return ((a & 0xff)<<24) + ((r & 0xff) << 16) + ((g & 0xff) << 8) + (b & 0xff) + + def __rgb(self, r, g, b): + return self.__argb(255, r, g, b) + + def do_focus_in(self): + self.register_properties(self.__prop_list) + self.__refresh_typing_mode_property() + mode = self.__prefs.get_value('common', 'behavior_on_focus_out') + if mode == 2: + self.__update_input_chars() +# self.__reset() +# self.__invalidate() + size = self.__prefs.get_value('common', 'page_size') + if size != self.__lookup_table.get_page_size(): + self.__lookup_table.set_page_size(size) + + def do_focus_out(self): + if self.__has_input_purpose: + self.__input_purpose = 0 + mode = self.__prefs.get_value('common', 'behavior_on_focus_out') + if mode == 0 or mode == 1: + self.__reset() + self.__invalidate() + + def do_set_content_type(self, purpose, hints): + if self.__has_input_purpose: + self.__input_purpose = purpose + + def do_disable(self): + self.__reset() + self.__invalidate() + + def do_reset(self): + self.__reset() + self.__invalidate() + + def __destroy(self, obj): + if self.__idle_id != 0: + GLib.source_remove(self.__idle_id) + self.__idle_id = 0 + # It seems do_destroy() is called when launch_engine() is called. + #self.__remove_dict_files() + # It seems super.destroy() does not unref the engine. + + def __join_all_segments(self): + while True: + nr_segments = self.__context.get_nr_segments() + seg = nr_segments - self.__cursor_pos + + if seg > 1: + self.__context.resize_segment(self.__cursor_pos, 1) + else: + break + + def __normalize_preedit(self, preedit): + if not self.__is_utf8: + return preedit + for key in list(romaji_normalize_rule.keys()): + if preedit.find(key) >= 0: + for value in romaji_normalize_rule[key]: + preedit = preedit.replace(key, value) + return preedit + + # begine convert + def __begin_anthy_convert(self): + if Engine.__segment_mode & SEGMENT_IMMEDIATE: + self.__end_anthy_convert() + if self.__convert_mode == CONV_MODE_ANTHY: + return + self.__convert_mode = CONV_MODE_ANTHY + +# text, cursor = self.__preedit_ja_string.get_hiragana() + text, cursor = self.__preedit_ja_string.get_hiragana(True) + + text = self.__normalize_preedit(text) + self.__context.set_string(text) + if Engine.__segment_mode & SEGMENT_SINGLE: + self.__join_all_segments() + nr_segments = self.__context.get_nr_segments() + + for i in range(0, nr_segments): + buf = self.__context.get_segment(i, 0) + text = buf + self.__segments.append((0, text)) + + if Engine.__segment_mode & SEGMENT_IMMEDIATE: + self.__cursor_pos = nr_segments - 1 + else: + self.__cursor_pos = 0 + self.__fill_lookup_table() + self.__lookup_table_visible = False + + def __end_anthy_convert(self): + if self.__convert_mode == CONV_MODE_OFF: + return + + self.__convert_mode = CONV_MODE_OFF + self.__convert_chars = '' + self.__segments = list() + self.__cursor_pos = 0 + self.__lookup_table.clear() + self.__lookup_table_visible = False + + def __end_convert(self): + self.__end_anthy_convert() + + # test case 'verudhi' can show U+3046 + U+309B and U+3094 + def __candidate_cb(self, candidate): + if not self.__is_utf8: + return + for key in list(romaji_utf8_rule.keys()): + if candidate.find(key) >= 0: + for value in romaji_utf8_rule[key]: + candidate = candidate.replace(key, value) + self.__lookup_table.append_candidate(IBus.Text.new_from_string(candidate)) + + def __fill_lookup_table(self): + if self.__convert_mode == CONV_MODE_PREDICTION: + nr_predictions = self.__context.get_nr_predictions() + + # fill lookup_table + self.__lookup_table.clear() + for i in range(0, seg_stat.nr_predictions): + buf = self.__context.get_prediction(i) + candidate = buf + self.__lookup_table.append_candidate(IBus.Text.new_from_string(candidate)) + self.__candidate_cb(candidate) + return + + # get segment stat + nr_candidates = self.__context.get_nr_candidates(self.__cursor_pos) + + # fill lookup_table + self.__lookup_table.clear() + for i in range(0, nr_candidates): + buf = self.__context.get_segment(self.__cursor_pos, i) + candidate = buf + self.__lookup_table.append_candidate(IBus.Text.new_from_string(candidate)) + self.__candidate_cb(candidate) + + + def __invalidate(self): + if self.__idle_id != 0: + return + self.__idle_id = GLib.idle_add(self.__update, + priority = GLib.PRIORITY_LOW) + +# def __get_preedit(self): + def __get_preedit(self, commit=False): + if Engine.__input_mode == INPUT_MODE_HIRAGANA: +# text, cursor = self.__preedit_ja_string.get_hiragana() + text, cursor = self.__preedit_ja_string.get_hiragana(commit) + elif Engine.__input_mode == INPUT_MODE_KATAKANA: +# text, cursor = self.__preedit_ja_string.get_katakana() + text, cursor = self.__preedit_ja_string.get_katakana(commit) + elif Engine.__input_mode == INPUT_MODE_HALF_WIDTH_KATAKANA: +# text, cursor = self.__preedit_ja_string.get_half_width_katakana() + text, cursor = self.__preedit_ja_string.get_half_width_katakana(commit) + else: + text, cursor = '', 0 + return text, cursor + + def __update_input_chars(self): + text, cursor = self.__get_preedit() + attrs = IBus.AttrList() + attrs.append(IBus.attr_underline_new( + IBus.AttrUnderline.SINGLE, 0, + len(text))) + + self.update_preedit(text, + attrs, cursor, not self.__preedit_ja_string.is_empty()) + self.update_aux_string('', IBus.AttrList(), False) + self.update_lookup_table(self.__lookup_table, + self.__lookup_table_visible) + + def __update_convert_chars(self): +# if self.__convert_mode == CONV_MODE_ANTHY: + if self.__convert_mode == CONV_MODE_ANTHY or self.__convert_mode == CONV_MODE_PREDICTION: + self.__update_anthy_convert_chars() + return + if self.__convert_mode == CONV_MODE_HIRAGANA: +# text, cursor = self.__preedit_ja_string.get_hiragana() + text, cursor = self.__preedit_ja_string.get_hiragana(True) + elif self.__convert_mode == CONV_MODE_KATAKANA: +# text, cursor = self.__preedit_ja_string.get_katakana() + text, cursor = self.__preedit_ja_string.get_katakana(True) + elif self.__convert_mode == CONV_MODE_HALF_WIDTH_KATAKANA: +# text, cursor = self.__preedit_ja_string.get_half_width_katakana() + text, cursor = self.__preedit_ja_string.get_half_width_katakana(True) + elif self.__convert_mode == CONV_MODE_LATIN_0: + text, cursor = self.__preedit_ja_string.get_latin() + if text == text.lower(): + self.__convert_mode = CONV_MODE_LATIN_1 + elif self.__convert_mode == CONV_MODE_LATIN_1: + text, cursor = self.__preedit_ja_string.get_latin() + text = text.lower() + elif self.__convert_mode == CONV_MODE_LATIN_2: + text, cursor = self.__preedit_ja_string.get_latin() + text = text.upper() + elif self.__convert_mode == CONV_MODE_LATIN_3: + text, cursor = self.__preedit_ja_string.get_latin() + text = text.capitalize() + elif self.__convert_mode == CONV_MODE_WIDE_LATIN_0: + text, cursor = self.__preedit_ja_string.get_wide_latin() + if text == text.lower(): + self.__convert_mode = CONV_MODE_WIDE_LATIN_1 + elif self.__convert_mode == CONV_MODE_WIDE_LATIN_1: + text, cursor = self.__preedit_ja_string.get_wide_latin() + text = text.lower() + elif self.__convert_mode == CONV_MODE_WIDE_LATIN_2: + text, cursor = self.__preedit_ja_string.get_wide_latin() + text = text.upper() + elif self.__convert_mode == CONV_MODE_WIDE_LATIN_3: + text, cursor = self.__preedit_ja_string.get_wide_latin() + text = text.capitalize() + self.__convert_chars = text + attrs = IBus.AttrList() + attrs.append(IBus.attr_underline_new( + IBus.AttrUnderline.SINGLE, 0, len(text))) + attrs.append(IBus.attr_background_new(self.__rgb(200, 200, 240), + 0, len(text))) + attrs.append(IBus.attr_foreground_new(self.__rgb(0, 0, 0), + 0, len(text))) + self.update_preedit(text, attrs, len(text), True) + + self.update_aux_string('', + IBus.AttrList(), self.__lookup_table_visible) + self.update_lookup_table(self.__lookup_table, + self.__lookup_table_visible) + + def __update_anthy_convert_chars(self): + self.__convert_chars = '' + pos = 0 + for i, (seg_index, text) in enumerate(self.__segments): + self.__convert_chars += text + if i < self.__cursor_pos: + pos += len(text) + attrs = IBus.AttrList() + attrs.append(IBus.attr_underline_new( + IBus.AttrUnderline.SINGLE, 0, len(self.__convert_chars))) + attrs.append(IBus.attr_background_new(self.__rgb(200, 200, 240), + pos, pos + len(self.__segments[self.__cursor_pos][1]))) + attrs.append(IBus.attr_foreground_new(self.__rgb(0, 0, 0), + pos, pos + len(self.__segments[self.__cursor_pos][1]))) + self.update_preedit(self.__convert_chars, attrs, pos, True) + aux_string = '( %d / %d )' % (self.__lookup_table.get_cursor_pos() + 1, self.__lookup_table.get_number_of_candidates()) + self.update_aux_string(aux_string, + IBus.AttrList(), self.__lookup_table_visible) + self.update_lookup_table(self.__lookup_table, + self.__lookup_table_visible) + + def __update(self): + if self.__convert_mode == CONV_MODE_OFF: + self.__update_input_chars() + else: + self.__update_convert_chars() + self.__idle_id = 0 + + def __on_key_return(self): + if self.__preedit_ja_string.is_empty(): + return False + + if self.__convert_mode == CONV_MODE_OFF: +# text, cursor = self.__get_preedit() + text, cursor = self.__get_preedit(True) + self.__commit_string(text) + elif self.__convert_mode == CONV_MODE_ANTHY: + for i, (seg_index, text) in enumerate(self.__segments): + self.__context.commit_segment(i, seg_index) + self.__commit_string(self.__convert_chars) + elif self.__convert_mode == CONV_MODE_PREDICTION: + self.__context.commit_prediction(self.__segments[0][0]) + self.__commit_string(self.__convert_chars) + else: + self.__commit_string(self.__convert_chars) + + return True + + def __on_key_escape(self): + if self.__preedit_ja_string.is_empty(): + return False + self.__reset() + self.__invalidate() + return True + + def __on_key_back_space(self): + if self.__preedit_ja_string.is_empty(): + return False + + if self.__convert_mode != CONV_MODE_OFF: + if self.__lookup_table_visible: + if self.__lookup_table.get_number_of_candidates() > 0: + self.__lookup_table.set_cursor_pos(0) + candidate = self.__lookup_table.get_candidate(0).get_text() + self.__segments[self.__cursor_pos] = 0, candidate + self.__lookup_table_visible = False + elif self.__segments[self.__cursor_pos][0] != \ + NTH_UNCONVERTED_CANDIDATE: + buf = self.__context.get_segment(self.__cursor_pos, + NTH_UNCONVERTED_CANDIDATE) + self.__segments[self.__cursor_pos] = \ + NTH_UNCONVERTED_CANDIDATE, buf + #elif self._chk_mode('25'): + ''' + # FIXME: Delete the last char in the active segment. + # + # If we are able to delete a char in the active segment, + # we also should be able to add a char in the active segment. + # Currently plain preedit, no segment mode, i.e. + # using self.__preedit_ja_string, can delete or add a char + # but anthy active segoment mode, i.e. + # using self.__segments, can not delete or add a char. + # Deleting a char could be easy here but adding a char is + # difficult because we need to update both self.__segments + # and self.__preedit_ja_string but self.__preedit_ja_string + # has no segment. To convert self.__segments to + # self.__preedit_ja_string, we may use the reconvert mode + # but no idea to convert keyvals to hiragana + # in self__on_key_common() with multiple key typings. + + # Delete a char in the active segment + all_text = '' + nr_segments = self.__context.get_nr_segments() + for i in xrange(0, nr_segments): + buf = self.__context.get_segment(i, + NTH_UNCONVERTED_CANDIDATE) + text = buf + if i == self.__cursor_pos and len(text) > 0: + text = text[:len(text) - 1] + all_text += text + + if all_text == '': + return + + # Set self.__preedit_ja_string by anthy context. + self.__preedit_ja_string = jastring.JaString(Engine.__typing_mode, + self.__latin_with_shift) + self.__convert_chars = self.__normalize_preedit(all_text) + for i in xrange(0, len(self.__convert_chars)): + keyval = self.__convert_chars[i] + self.__preedit_ja_string.insert(chr(ord(keyval))) + self.__context.set_string(self.__convert_chars) + + # Set self.__segments by anty context + # for editable self.__segments, + # save NTH_UNCONVERTED_CANDIDATE + nr_segments = self.__context.get_nr_segments() + if self.__cursor_pos >= nr_segments and \ + nr_segments > 0: + self.__cursor_pos = nr_segments - 1 + for i in xrange(self.__cursor_pos, nr_segments): + if i == self.__cursor_pos: + index = NTH_UNCONVERTED_CANDIDATE + else: + index = 0 + buf = self.__context.get_segment(i, + index) + text = buf + self.__segments[i] = index, text + + # Update self.__lookup_table + self.__fill_lookup_table() + ''' + else: + self.__end_convert() + else: + self.__preedit_ja_string.remove_before() + + self.__invalidate() + return True + + def __on_key_delete(self): + if self.__preedit_ja_string.is_empty(): + return False + + if self.__convert_mode != CONV_MODE_OFF: + self.__end_convert() + else: + self.__preedit_ja_string.remove_after() + + self.__invalidate() + return True + + '''def __on_key_hiragana_katakana(self): + if self.__convert_mode == CONV_MODE_ANTHY: + self.__end_anthy_convert() + + if Engine.__input_mode >= INPUT_MODE_HIRAGANA and \ + Engine.__input_mode < INPUT_MODE_HALF_WIDTH_KATAKANA: + Engine.__input_mode += 1 + else: + Engine.__input_mode = INPUT_MODE_HIRAGANA + + modes = { INPUT_MODE_HIRAGANA: 'あ', + INPUT_MODE_KATAKANA: 'ア', + INPUT_MODE_HALF_WIDTH_KATAKANA: '_ア' } + + prop = self.__prop_dict[u'InputMode'] + label = modes[Engine.__input_mode] + prop.set_label(IBus.Text.new_from_string(label)) + self.update_property(prop) + + self.__invalidate() + return True''' + + '''def __on_key_muhenka(self): + if self.__preedit_ja_string.is_empty(): + return False + + if self.__convert_mode == CONV_MODE_ANTHY: + self.__end_anthy_convert() + + new_mode = CONV_MODE_HIRAGANA + if self.__convert_mode < CONV_MODE_WIDE_LATIN_3 and \ + self.__convert_mode >= CONV_MODE_HIRAGANA : + self.__convert_mode += 1 + else: + self.__convert_mode = CONV_MODE_HIRAGANA + + self.__invalidate() + + return True''' + + '''def __on_key_henkan(self): + if self.__preedit_ja_string.is_empty(): + return False + if self.__convert_mode != CONV_MODE_ANTHY: + self.__begin_anthy_convert() + self.__invalidate() + elif self.__convert_mode == CONV_MODE_ANTHY: + self.__lookup_table_visible = True + self.do_cursor_down() + return True''' + + '''def __on_key_space(self, wide=False): + if Engine.__input_mode == INPUT_MODE_WIDE_LATIN or wide: + # Input Wide space U+3000 + wide_char = symbol_rule[chr(IBus.KEY_space)] + self.__commit_string(wide_char) + return True + + if self.__preedit_ja_string.is_empty(): + if Engine.__input_mode in (INPUT_MODE_HIRAGANA, INPUT_MODE_KATAKANA): + # Input Wide space U+3000 + wide_char = symbol_rule[chr(IBus.KEY_space)] + self.__commit_string(wide_char) + return True + else: + # Input Half space U+0020 + self.__commit_string(chr(IBus.KEY_space)) + return True + + if self.__convert_mode != CONV_MODE_ANTHY: + self.__begin_anthy_convert() + self.__invalidate() + elif self.__convert_mode == CONV_MODE_ANTHY: + self.__lookup_table_visible = True + self.do_cursor_down() + return True''' + + def __on_key_up(self): + if self.__preedit_ja_string.is_empty(): + return False + self.__lookup_table_visible = True + self.do_cursor_up() + return True + + def __on_key_down(self): + if self.__preedit_ja_string.is_empty(): + return False + self.__lookup_table_visible = True + self.do_cursor_down() + return True + + def __on_key_page_up(self): + if self.__preedit_ja_string.is_empty(): + return False + if self.__lookup_table_visible == True: + self.do_page_up() + return True + + def __on_key_page_down(self): + if self.__preedit_ja_string.is_empty(): + return False + if self.__lookup_table_visible == True: + self.do_page_down() + return True + + '''def __on_key_left(self): + if self.__preedit_ja_string.is_empty(): + return False + + if self.__convert_mode == CONV_MODE_OFF: + self.__preedit_ja_string.move_cursor(-1) + self.__invalidate() + return True + + if self.__convert_mode != CONV_MODE_ANTHY: + return True + + if self.__cursor_pos == 0: + return True + self.__cursor_pos -= 1 + self.__lookup_table_visible = False + self.__fill_lookup_table() + self.__invalidate() + return True''' + + def __on_key_right(self): + if self.__preedit_ja_string.is_empty(): + return False + + if self.__convert_mode == CONV_MODE_OFF: + self.__preedit_ja_string.move_cursor(1) + self.__invalidate() + return True + + if self.__convert_mode != CONV_MODE_ANTHY: + return True + + if self.__cursor_pos + 1 >= len(self.__segments): + return True + + self.__cursor_pos += 1 + self.__lookup_table_visible = False + self.__fill_lookup_table() + self.__invalidate() + return True + + def __on_key_number(self, keyval): + if self.__convert_mode != CONV_MODE_ANTHY: + return False + if not self.__lookup_table_visible: + return False + + if keyval == IBus.KEY_0: + keyval = IBus.KEY_9 + 1 + index = keyval - IBus.KEY_1 + + return self.__on_candidate_index_in_page(index) + + def __on_key_conv(self, mode): + if self.__preedit_ja_string.is_empty(): + return False + + if self.__convert_mode == CONV_MODE_ANTHY: + self.__end_anthy_convert() + + if mode == 0 or mode == 1: + if self.__convert_mode == CONV_MODE_HIRAGANA + mode: + return True + self.__convert_mode = CONV_MODE_HIRAGANA + mode + elif mode == 2: + if self.__convert_mode == CONV_MODE_HALF_WIDTH_KATAKANA: + return True + self.__convert_mode = CONV_MODE_HALF_WIDTH_KATAKANA + elif mode == 3: + if CONV_MODE_WIDE_LATIN_0 <= self.__convert_mode <= CONV_MODE_WIDE_LATIN_3: + self.__convert_mode += 1 + if self.__convert_mode > CONV_MODE_WIDE_LATIN_3: + self.__convert_mode = CONV_MODE_WIDE_LATIN_1 + else: + self.__convert_mode = CONV_MODE_WIDE_LATIN_0 + elif mode == 4: + if CONV_MODE_LATIN_0 <= self.__convert_mode <= CONV_MODE_LATIN_3: + self.__convert_mode += 1 + if self.__convert_mode > CONV_MODE_LATIN_3: + self.__convert_mode = CONV_MODE_LATIN_1 + else: + self.__convert_mode = CONV_MODE_LATIN_0 + else: + printerr('Unkown convert mode (%d)!' % mode) + return False + self.__invalidate() + return True + + def __on_key_common(self, keyval, state=0): + + # If use-system-layout is FALSE in ibus 1.4.y or lower, + # ibus converts the keymap and ibus-anthy needed to use + # self.__commit_string + # ibus 1.5.y uses XKB directly so Latin mode can return FALSE. + if Engine.__input_mode == INPUT_MODE_LATIN: + return False + + elif Engine.__input_mode == INPUT_MODE_WIDE_LATIN: + # Input Wide Latin chars + char = chr(keyval) + wide_char = None#symbol_rule.get(char, None) + if wide_char == None: + wide_char = unichar_half_to_full(char) + self.__commit_string(wide_char) + return True + + # Input Japanese + if Engine.__segment_mode & SEGMENT_IMMEDIATE: + # Commit nothing + pass + elif self.__convert_mode == CONV_MODE_ANTHY: + for i, (seg_index, text) in enumerate(self.__segments): + self.__context.commit_segment(i, seg_index) + self.__commit_string(self.__convert_chars) + elif self.__convert_mode != CONV_MODE_OFF: + self.__commit_string(self.__convert_chars) + + # 'n' + '\'' == 'nn' in romaji + if (keyval >= ord('A') and keyval <= ord('Z')) or \ + (keyval >= ord('a') and keyval <= ord('z')): + shift = (state & IBus.ModifierType.SHIFT_MASK) != 0 + else: + shift = False + self.__preedit_ja_string.set_shift(shift) + self.__preedit_ja_string.insert(chr(keyval)) + if Engine.__segment_mode & SEGMENT_IMMEDIATE: + self.__begin_anthy_convert() + self.__invalidate() + return True + +#======================================================================= + @classmethod + def CONFIG_RELOADED(cls, bus): + if config.DEBUG: + print('RELOADED') + if not cls.__prefs: + cls.__prefs = AnthyPrefs(bus) + cls._init_prefs() + + cls.__keybind = cls._mk_keybind() + + jastring.JaString.SET_PREFS(cls.__prefs) + + @classmethod + def CONFIG_VALUE_CHANGED(cls, bus, section, name, variant): + if config.DEBUG: + print('VALUE_CHAMGED =', section, name, variant) + + if not section.startswith('engine/anthy'): + # This value is used for IBus.config.set_value only. + return + + # The key was deleted by dconf. + # test case: update /desktop/ibus/engine/anthy/thumb/ls + # and reset the key with dconf direclty. + if variant.get_type_string() == '()': + cls.__prefs.undo_item(section, name) + return + + value = cls.__prefs.variant_to_value(variant) + base_sec = section[len(cls.__prefs._prefix) + 1:] + sec = cls._get_shortcut_type() + if base_sec == sec: + cmd = '_Engine__cmd_' + name + old = cls.__prefs.get_value(sec, name) + value = value if value != [''] else [] + for s in set(old).difference(value): + cls.__keybind.get(cls._s_to_key(s), []).remove(cmd) + + keys = cls.__prefs.keys(sec) + for s in set(value).difference(old): + cls.__keybind.setdefault(cls._s_to_key(s), []).append(cmd) + cls.__keybind.get(cls._s_to_key(s)).sort( + key = lambda a: keys.index(a[13:])) + cls.__prefs.set_value(sec, name, value) + elif base_sec == 'common': + cls.__prefs.set_value(base_sec, name, value) + if name == 'shortcut_type': + cls.__keybind = cls._mk_keybind() + if name == 'latin_with_shift': + cls.__latin_with_shift = value + jastring.JaString.RESET(cls.__prefs, base_sec, name, value) + elif base_sec.startswith('kana_typing_rule'): + jastring.JaString.RESET(cls.__prefs, base_sec, name, value) + + @classmethod + def _init_prefs(cls): + prefs = cls.__prefs + value = prefs.get_value('common', 'latin_with_shift') + cls.__latin_with_shift = value + + @classmethod + def _mk_keybind(cls): + keybind = {} + sec = cls._get_shortcut_type() + for k in cls.__prefs.keys(sec): + cmd = '_Engine__cmd_' + k + for s in cls.__prefs.get_value(sec, k): + keybind.setdefault(cls._s_to_key(s), []).append(cmd) + return keybind + + @classmethod + def _get_shortcut_type(cls): + try: + t = 'shortcut/' + cls.__prefs.get_value('common', 'shortcut_type') + except: + t = 'shortcut/default' + return t + + @classmethod + def _s_to_key(cls, s): + keyval = IBus.keyval_from_name(s.split('+')[-1]) + s = s.lower() + state = ('shift+' in s and IBus.ModifierType.SHIFT_MASK or 0) | ( + 'ctrl+' in s and IBus.ModifierType.CONTROL_MASK or 0) | ( + 'alt+' in s and IBus.ModifierType.MOD1_MASK or 0) + return cls._mk_key(keyval, state) + + @classmethod + def _reset_thumb(cls): + if cls.__thumb == None: + import thumb + cls.__thumb = thumb.ThumbShiftKeyboard(cls.__prefs) + + else: + cls.__thumb.reset() + + @staticmethod + def _mk_key(keyval, state): + if state & (IBus.ModifierType.CONTROL_MASK | IBus.ModifierType.MOD1_MASK): + if keyval < 0xff and \ + chr(keyval) in '!"#$%^\'()*+,-./:;<=>?@[\]^_`{|}~': + state |= IBus.ModifierType.SHIFT_MASK + elif IBus.KEY_a <= keyval <= IBus.KEY_z: + keyval -= (IBus.KEY_a - IBus.KEY_A) + + return repr([int(state), int(keyval)]) + + def __process_key_event(self, obj, keyval, keycode, state): + try: + return self.__process_key_event_internal2(keyval, keycode, state) + except: + import traceback + traceback.print_exc() + return False + + def __process_key_event_thumb(self, keyval, keycode, state): + if self.__thumb == None: + self._reset_thumb() + + def on_timeout(keyval): + if self._MM: + insert(self.__thumb.get_char(self._MM)[self._SS]) + else: + cmd_exec([0, RS(), LS()][self._SS]) + self._H = None + + def start(t): + self._H = GLib.timeout_add(t, on_timeout, keyval) + + def stop(): + if self._H: + GLib.source_remove(self._H) + self._H = None + return True + return False + + def insert(keyval): + try: + self._MM = self._SS = 0 + ret = self.__on_key_common(ord(keyval)) + if (keyval in ',.、。' and + self.__prefs.get_value('common', 'behavior_on_period')): + return self.__cmd_convert(keyval, state) + return ret + except: + pass + + def cmd_exec(keyval, state=0): + key = self._mk_key(keyval, state) + for cmd in self.__keybind.get(key, []): + if config.DEBUG: + print('cmd =', cmd) + try: + if getattr(self, cmd)(keyval, state): + return True + except: + printerr('Unknown command = %s' % cmd) + return False + + def RS(): + return self.__thumb.get_rs() + + def LS(): + return self.__thumb.get_ls() + + def T1(): + return self.__thumb.get_t1() + + def T2(): + return self.__thumb.get_t2() + + state = state & (IBus.ModifierType.SHIFT_MASK | + IBus.ModifierType.CONTROL_MASK | + IBus.ModifierType.MOD1_MASK | + IBus.ModifierType.RELEASE_MASK) + + if keyval in KP_Table and self.__prefs.get_value('common', + 'ten_key_mode'): + keyval = KP_Table[keyval] + + if state & IBus.ModifierType.RELEASE_MASK: + if keyval == self._MM: + if stop(): + insert(self.__thumb.get_char(self._MM)[self._SS]) + self._MM = 0 + elif (1 if keyval == RS() else 2) == self._SS: + if stop(): + cmd_exec([0, RS(), LS()][self._SS]) + self._SS = 0 + if keyval in [RS(), LS()]: + self._RSS = 0 + elif keyval == self._RMM: + self._RMM = 0 + else: + if keyval in [LS(), RS()] and state == 0: + if self._SS: + stop() + cmd_exec([0, RS(), LS()][self._SS]) + self._SS = 1 if keyval == RS() else 2 + start(T1()) + elif self._MM: + stop() + self._RMM = self._MM + self._RSS = 1 if keyval == RS() else 2 + insert(self.__thumb.get_char(self._MM)[1 if keyval == RS() else 2]) + else: + if self._RSS == (1 if keyval == RS() else 2): + if self._RMM: + insert(self.__thumb.get_char(self._RMM)[self._RSS]) + else: + self._SS = 1 if keyval == RS() else 2 + start(T1()) + elif keyval in self.__thumb.get_chars() and state == 0: + if self._MM: + stop() + insert(self.__thumb.get_char(self._MM)[self._SS]) + start(T2()) + self._MM = keyval + elif self._SS: + stop() + self._RMM = keyval + self._RSS = self._SS + insert(self.__thumb.get_char(keyval)[self._SS]) + else: + if self._RMM == keyval: + if self._RSS: + insert(self.__thumb.get_char(self._RMM)[self._RSS]) + else: + if cmd_exec(keyval, state): + return True + start(T2()) + self._MM = keyval + else: + if self._MM: + stop() + insert(self.__thumb.get_char(self._MM)[self._SS]) + elif self._SS: + stop() + cmd_exec([0, RS(), LS()][self._SS]) + if cmd_exec(keyval, state): + return True + elif 0x21 <= keyval <= 0x7e and state & \ + (IBus.ModifierType.CONTROL_MASK | IBus.ModifierType.MOD1_MASK) == 0: + if state & IBus.ModifierType.SHIFT_MASK: + insert(self.__thumb.get_shift_char(keyval, chr(keyval))) + elif self._SS == 0: + insert(chr(keyval)) + else: + if not self.__preedit_ja_string.is_empty(): + return True + return False + return True + + def __process_key_event_internal2(self, keyval, keycode, state): + if self.__has_input_purpose and \ + self.__input_purpose == IBus.InputPurpose.PASSWORD: + return False + + if Engine.__typing_mode == jastring.TYPING_MODE_THUMB_SHIFT and \ + Engine.__input_mode not in [INPUT_MODE_LATIN, INPUT_MODE_WIDE_LATIN]: + return self.__process_key_event_thumb(keyval, keycode, state) + + is_press = (state & IBus.ModifierType.RELEASE_MASK) == 0 + + state = state & (IBus.ModifierType.SHIFT_MASK | + IBus.ModifierType.CONTROL_MASK | + IBus.ModifierType.MOD1_MASK) + + # ignore key release events + if not is_press: + return False + + if keyval in KP_Table and self.__prefs.get_value('common', + 'ten_key_mode'): + keyval = KP_Table[keyval] + + key = self._mk_key(keyval, state) + for cmd in self.__keybind.get(key, []): + if config.DEBUG: + print('cmd =', cmd) + try: + if getattr(self, cmd)(keyval, state): + return True + except: + printerr('Unknown command = %s' % cmd) + + # If input mode is not LATIN, eat Ctrl+Shift+u + hex_mod_mask = IBus.ModifierType.SHIFT_MASK | \ + IBus.ModifierType.CONTROL_MASK + if Engine.__input_mode != INPUT_MODE_LATIN and \ + keyval == IBus.KEY_U and \ + state & hex_mod_mask == hex_mod_mask: + return True + + if state & (IBus.ModifierType.CONTROL_MASK | IBus.ModifierType.MOD1_MASK): + return False + + if (IBus.KEY_exclam <= keyval <= IBus.KEY_asciitilde or + keyval == IBus.KEY_yen): + if Engine.__typing_mode == jastring.TYPING_MODE_KANA: + if keyval == IBus.KEY_0 and state == IBus.ModifierType.SHIFT_MASK: + keyval = IBus.KEY_asciitilde + elif keyval == IBus.KEY_backslash and keycode in [132-8, 133-8]: + keyval = IBus.KEY_yen + ret = self.__on_key_common(keyval, state) + if (Engine.__input_mode != INPUT_MODE_LATIN and + chr(keyval) in ',.' and + self.__prefs.get_value('common', 'behavior_on_period')): + return self.__cmd_convert(keyval, state) + return ret + else: + if not self.__preedit_ja_string.is_empty(): + return True + return False + + def _chk_mode(self, mode): + if '0' in mode and self.__preedit_ja_string.is_empty(): + return True + + if self.__convert_mode == CONV_MODE_OFF: + if '1' in mode and not self.__preedit_ja_string.is_empty(): + return True + elif self.__convert_mode == CONV_MODE_ANTHY: + if '2' in mode and not self.__lookup_table_visible: + return True + elif self.__convert_mode == CONV_MODE_PREDICTION: + if '3' in mode and not self.__lookup_table_visible: + return True + else: + if '4' in mode: + return True + + if '5' in mode and self.__lookup_table_visible: + return True + + return False + + def __get_quoted_id(self, file): + id = file + has_mbcs = False + + for i in range(0, len(id)): + if ord(id[i]) >= 0x7f: + has_mbcs = True + break + if has_mbcs: + id = str(binascii.hexlify(id.encode()), 'ascii') + + if id.find('/') >=0: + id = id[id.rindex('/') + 1:] + if id.find('.') >=0: + id = id[:id.rindex('.')] + + if id.startswith('0x'): + id = str(binascii.hexlify(id.encode()), 'ascii') + has_mbcs = True + if has_mbcs: + id = '0x' + id + return id + + def __get_dict_id_from_file(self, file): + return self.__get_quoted_id(file) + + def __link_dict_file_with_id(self, file, id, link_mode): + if id == None: + return + if link_mode == LINK_DICT_EMBEDDED: + directory = get_userhome() + '/.anthy/' + IMPORTED_EMBEDDED_DICT_DIR + name = IMPORTED_EMBEDDED_DICT_PREFIX + id + elif link_mode == LINK_DICT_SINGLE: + directory = get_userhome() + '/.anthy' + name = IMPORTED_SINGLE_DICT_PREFIX + id + else: + return + if path.exists(directory): + if not path.isdir(directory): + printerr(directory + ' is not a directory') + return + else: + os.makedirs(directory, 0o700) + backup_dir = os.getcwd() + os.chdir(directory) + if path.lexists(directory + '/' + name): + if path.islink(directory + '/' + name): + printerr('Removing ' + name) + os.unlink(directory + '/' + name) + else: + alternate = name + str(os.getpid()) + printerr('Moving ' + name + ' to ' + alternate) + os.rename(name, alternate) + os.symlink(file, directory + '/' + name) + if backup_dir != None: + os.chdir(backup_dir) + + def __remove_dict_file_with_id(self, file, id, link_mode): + if id == None: + return + if link_mode == LINK_DICT_EMBEDDED: + directory = get_userhome() + '/.anthy/' + IMPORTED_EMBEDDED_DICT_DIR + name = IMPORTED_EMBEDDED_DICT_PREFIX + id + elif link_mode == LINK_DICT_SINGLE: + directory = get_userhome() + '/.anthy' + name = IMPORTED_SINGLE_DICT_PREFIX + id + else: + return + if path.exists(directory): + if not path.isdir(directory): + printerr(directory + ' is not a directory') + return + backup_dir = os.getcwd() + os.chdir(directory) + if path.lexists(directory + '/' + name): + os.unlink(directory + '/' + name) + if backup_dir != None: + os.chdir(backup_dir) + + def __link_dict_file(self, file): + if not path.exists(file): + printerr(file + ' does not exist') + return False + id = self.__get_dict_id_from_file(file) + section = 'dict/file/' + id + if section not in self.__prefs.sections(): + self.__fetch_dict_values(section) + if self.__prefs.get_value(section, 'embed'): + self.__link_dict_file_with_id(file, id, LINK_DICT_EMBEDDED) + if self.__prefs.get_value(section, 'single'): + self.__link_dict_file_with_id(file, id, LINK_DICT_SINGLE) + return True + + def __remove_dict_file(self, file): + id = self.__get_dict_id_from_file(file) + section = 'dict/file/' + id + if section not in self.__prefs.sections(): + self.__fetch_dict_values(section) + if self.__prefs.get_value(section, 'embed'): + self.__remove_dict_file_with_id(file, id, LINK_DICT_EMBEDDED) + if self.__prefs.get_value(section, 'single'): + self.__remove_dict_file_with_id(file, id, LINK_DICT_SINGLE) + + def __set_dict_files_value(self, base_sec, name, value): + if name == 'files': + str_list = [] + for file in value: + str_list.append(self.__prefs.str(file)) + old_files = self.__prefs.get_value(base_sec, name) + for file in old_files: + if file in str_list: + continue + self.__remove_dict_file(file) + for file in str_list: + if file in old_files: + continue + self.__link_dict_file(file) + self.__prefs.set_value(base_sec, name, str_list) + else: + self.__prefs.set_value(base_sec, name, value) + + def __fetch_dict_values(self, section): + self.__prefs.set_new_section(section) + self.__prefs.set_new_key(section, 'short_label') + self.__prefs.set_no_key_warning(True) + self.__prefs.fetch_item(section, 'short_label') + self.__prefs.set_new_key(section, 'long_label') + self.__prefs.fetch_item(section, 'long_label') + self.__prefs.set_new_key(section, 'embed') + self.__prefs.fetch_item(section, 'embed') + self.__prefs.set_new_key(section, 'single') + self.__prefs.fetch_item(section, 'single') + self.__prefs.set_new_key(section, 'reverse') + self.__prefs.fetch_item(section, 'reverse') + self.__prefs.set_no_key_warning(False) + + def __config_value_changed_cb(self, ibus_config, section, name, variant): + if config.DEBUG: + print('VALUE_CHAMGED =', section, name, variant) + + if not section.startswith('engine/anthy'): + # This value is used for IBus.config.set_value only. + return + + # The key was deleted by dconf. + # test case: update /desktop/ibus/engine/anthy/thumb/ls + # and reset the key with dconf direclty. + if variant.get_type_string() == '()': + self.__prefs.undo_item(section, name) + return + + value = self.__prefs.variant_to_value(variant) + base_sec = section[len(self.__prefs._prefix) + 1:] + sec = self._get_shortcut_type() + + if base_sec == 'thumb': + self.__prefs.set_value(base_sec, name, value) + self._reset_thumb() + elif base_sec == 'dict': + self.__set_dict_files_value(base_sec, name, value) + self.__set_dict_mode_props(self.__prop_list, True) + elif base_sec.startswith('dict/file/'): + if base_sec not in self.__prefs.sections(): + self.__fetch_dict_values(base_sec) + self.__prefs.set_value(base_sec, name, value) + self.__set_dict_mode_props(self.__prop_list, True) + elif base_sec: + self.__prefs.set_value(base_sec, name, value) + else: + self.__prefs.set_value(section, name, value) + + #mod_keys + def __set_input_mode(self, mode): + self.__input_mode_activate(mode, IBus.PropState.CHECKED) + self.__reset() + self.__invalidate() + + return True + + def __unset_current_input_mode(self): + modes = { + INPUT_MODE_HIRAGANA: 'InputMode.Hiragana', + INPUT_MODE_KATAKANA: 'InputMode.Katakana', + INPUT_MODE_HALF_WIDTH_KATAKANA: 'InputMode.HalfWidthKatakana', + INPUT_MODE_LATIN: 'InputMode.Latin', + INPUT_MODE_WIDE_LATIN: 'InputMode.WideLatin' + } + self.__input_mode_activate(modes[Engine.__input_mode], + IBus.PropState.UNCHECKED) + + def __cmd_on_off(self, keyval, state): + # ibus 1.5 or later needs to send UNCHECKED + self.__unset_current_input_mode() + if Engine.__input_mode == INPUT_MODE_LATIN: + return self.__set_input_mode('InputMode.Hiragana') + else: + return self.__set_input_mode('InputMode.Latin') + + def __cmd_circle_input_mode(self, keyval, state): + modes = { + INPUT_MODE_HIRAGANA: 'InputMode.Katakana', + INPUT_MODE_KATAKANA: 'InputMode.HalfWidthKatakana', + INPUT_MODE_HALF_WIDTH_KATAKANA: 'InputMode.Latin', + INPUT_MODE_LATIN: 'InputMode.WideLatin', + INPUT_MODE_WIDE_LATIN: 'InputMode.Hiragana' + } + # ibus 1.5 or later needs to send UNCHECKED + self.__unset_current_input_mode() + return self.__set_input_mode(modes[Engine.__input_mode]) + + def __cmd_circle_kana_mode(self, keyval, state): + modes = { + INPUT_MODE_HIRAGANA: 'InputMode.Katakana', + INPUT_MODE_KATAKANA: 'InputMode.HalfWidthKatakana', + INPUT_MODE_HALF_WIDTH_KATAKANA: 'InputMode.Hiragana', + INPUT_MODE_LATIN: 'InputMode.Hiragana', + INPUT_MODE_WIDE_LATIN: 'InputMode.Hiragana' + } + # ibus 1.5 or later needs to send UNCHECKED + self.__unset_current_input_mode() + return self.__set_input_mode(modes[Engine.__input_mode]) + + def __cmd_latin_mode(self, keyval, state): + # ibus 1.5 or later needs to send UNCHECKED + self.__unset_current_input_mode() + return self.__set_input_mode('InputMode.Latin') + + def __cmd_wide_latin_mode(self, keyval, state): + # ibus 1.5 or later needs to send UNCHECKED + self.__unset_current_input_mode() + return self.__set_input_mode('InputMode.WideLatin') + + def __cmd_hiragana_mode(self, keyval, state): + # ibus 1.5 or later needs to send UNCHECKED + self.__unset_current_input_mode() + return self.__set_input_mode('InputMode.Hiragana') + + def __cmd_katakana_mode(self, keyval, state): + # ibus 1.5 or later needs to send UNCHECKED + self.__unset_current_input_mode() + return self.__set_input_mode('InputMode.Katakana') + + def __cmd_half_katakana(self, keyval, state): + # ibus 1.5 or later needs to send UNCHECKED + self.__unset_current_input_mode() + return self.__set_input_mode('InputMode.HalfWidthKatakana') + +# def __cmd_cancel_pseudo_ascii_mode_key(self, keyval, state): +# pass + + def __unset_current_typing_mode(self): + modes = { + jastring.TYPING_MODE_ROMAJI: 'TypingMode.Romaji', + jastring.TYPING_MODE_KANA: 'TypingMode.Kana', + jastring.TYPING_MODE_THUMB_SHIFT: 'TypingMode.ThumbShift', + } + self.__typing_mode_activate(modes[Engine.__typing_mode], + IBus.PropState.UNCHECKED) + + def __cmd_circle_typing_method(self, keyval, state): + if not self._chk_mode('0'): + return False + + modes = { + jastring.TYPING_MODE_THUMB_SHIFT: 'TypingMode.Romaji', + jastring.TYPING_MODE_KANA: 'TypingMode.ThumbShift', + jastring.TYPING_MODE_ROMAJI: 'TypingMode.Kana', + } + # ibus 1.5 or later needs to send UNCHECKED + self.__unset_current_typing_mode() + self.__typing_mode_activate(modes[Engine.__typing_mode], + IBus.PropState.CHECKED) + return True + + def __cmd_circle_dict_method(self, keyval, state): + if not self._chk_mode('0'): + return False + + # ibus 1.5 or later needs to send UNCHECKED + prop_name = self.__dict_mode_get_prop_name(Engine.__dict_mode) + if prop_name != None: + self.__dict_mode_activate(prop_name, + IBus.PropState.UNCHECKED) + + single_files = self.__get_single_dict_files() + new_mode = Engine.__dict_mode + 1 + if new_mode > len(single_files): + new_mode = 0 + Engine.__dict_mode = new_mode + prop_name = self.__dict_mode_get_prop_name(Engine.__dict_mode) + if prop_name == None: + return False + self.__dict_mode_activate(prop_name, + IBus.PropState.CHECKED) + return True + + #edit_keys + def __cmd_insert_space(self, keyval, state): + if Engine.__input_mode == INPUT_MODE_LATIN: + return False + if (self.__prefs.get_value('common', 'half_width_space') or + Engine.__input_mode == INPUT_MODE_HALF_WIDTH_KATAKANA): + return self.__cmd_insert_half_space(keyval, state) + else: + return self.__cmd_insert_wide_space(keyval, state) + + def __cmd_insert_alternate_space(self, keyval, state): + if Engine.__input_mode == INPUT_MODE_LATIN: + return False + if (self.__prefs.get_value('common', 'half_width_space') or + Engine.__input_mode == INPUT_MODE_HALF_WIDTH_KATAKANA): + return self.__cmd_insert_wide_space(keyval, state) + else: + return self.__cmd_insert_half_space(keyval, state) + + def __cmd_insert_half_space(self, keyval, state): + if not self._chk_mode('0'): + return False + + if not self.__preedit_ja_string.is_empty(): + return False + self.__commit_string(chr(IBus.KEY_space)) + return True + + def __cmd_insert_wide_space(self, keyval, state): + if not self._chk_mode('0'): + return False + + if not self.__preedit_ja_string.is_empty(): + return False + char = chr(IBus.KEY_space) + wide_char = symbol_rule.get(char, None) + if wide_char == None: + wide_char = unichar_half_to_full(char) + self.__commit_string(wide_char) + return True + + def __cmd_backspace(self, keyval, state): + if not self._chk_mode('12345'): + return False + + return self.__on_key_back_space() + + def __cmd_delete(self, keyval, state): + if not self._chk_mode('12345'): + return False + + return self.__on_key_delete() + + def __cmd_commit(self, keyval, state): + if not self._chk_mode('12345'): + return False + + return self.__on_key_return() + + def __cmd_convert(self, keyval, state): + if not self._chk_mode('14'): + return False + + self.__begin_anthy_convert() + self.__invalidate() + + return True + + def __cmd_predict(self, keyval, state): + if not self._chk_mode('14'): + return False + + text, cursor = self.__preedit_ja_string.get_hiragana(True) + + self.__context.set_prediction_string(text) + nr_predictions = self.__context.get_nr_predictions() + +# for i in range(nr_predictions): +# print self.__context.get_prediction(i) + + buf = self.__context.get_prediction(0) + if not buf: + return False + + text = buf + self.__segments.append((0, text)) + + self.__convert_mode = CONV_MODE_PREDICTION + self.__cursor_pos = 0 + self.__fill_lookup_table() + self.__lookup_table_visible = False + self.__invalidate() + + return True + + def __cmd_cancel(self, keyval, state): + return self.__cmd_cancel_all(keyval, state) + + def __cmd_cancel_all(self, keyval, state): + if not self._chk_mode('12345'): + return False + + if self.__convert_mode == CONV_MODE_OFF: + return self.__on_key_escape() + else: + self.__end_convert() + self.__invalidate() + return True + + def __cmd_reconvert(self, keyval, state): + if not self.__preedit_ja_string.is_empty(): + # if user has inputed some chars + return False + + # Move importing Gtk into Engine from the header + # because ibus-engine-anthy --xml does not requre to open X. + try: + from gi.repository import Gtk + clipboard_get = Gtk.Clipboard.get + except ImportError: + clipboard_get = lambda a : None + except RuntimeError: + # Do we support the engine without display? + printerr("Gtk couldn't be initialized") + printerr('Could not open display') + clipboard_get = lambda a : None + + # Use Gtk.Clipboard.request_text() instead of + # Gtk.Clipboard.wait_for_text() because DBus is timed out. + clipboard = clipboard_get ('PRIMARY') + if clipboard: + clipboard.request_text (self.__get_clipboard, CLIPBOARD_RECONVERT) + + return True + + def __update_reconvert(self, clipboard_text): + if clipboard_text == None: + return False + + self.__convert_chars = clipboard_text + for i in range(0, len(self.__convert_chars)): + keyval = self.__convert_chars[i] + self.__preedit_ja_string.insert(chr(ord(keyval))) + + self.__context.set_string(self.__convert_chars) + nr_segments = self.__context.get_nr_segments() + + for i in range(0, nr_segments): + buf = self.__context.get_segment(i, 0) + text = buf + self.__segments.append((0, text)) + + self.__convert_mode = CONV_MODE_ANTHY + self.__cursor_pos = 0 + self.__fill_lookup_table() + self.__lookup_table_visible = False + self.__invalidate() + + return True + +# def __cmd_do_nothing(self, keyval, state): +# return True + + #caret_keys + def __move_caret(self, i): + if not self._chk_mode('1'): + return False + + if self.__convert_mode == CONV_MODE_OFF: + self.__preedit_ja_string.move_cursor( + -len(self.__preedit_ja_string.get_latin()[0]) if i == 0 else + i if i in [-1, 1] else + len(self.__preedit_ja_string.get_latin()[0])) + self.__invalidate() + return True + + return False + + def __cmd_move_caret_first(self, keyval, state): + return self.__move_caret(0) + + def __cmd_move_caret_last(self, keyval, state): + return self.__move_caret(2) + + def __cmd_move_caret_forward(self, keyval, state): + return self.__move_caret(1) + + def __cmd_move_caret_backward(self, keyval, state): + return self.__move_caret(-1) + + #segments_keys + def __select_segment(self, i): + if not self._chk_mode('25'): + return False + + pos = 0 if i == 0 else \ + self.__cursor_pos + i if i in [-1, 1] else \ + len(self.__segments) - 1 + + if 0 <= pos < len(self.__segments) and pos != self.__cursor_pos: + self.__cursor_pos = pos + self.__lookup_table_visible = False + self.__fill_lookup_table() + self.__invalidate() + + return True + + def __cmd_select_first_segment(self, keyval, state): + return self.__select_segment(0) + + def __cmd_select_last_segment(self, keyval, state): + return self.__select_segment(2) + + def __cmd_select_next_segment(self, keyval, state): + return self.__select_segment(1) + + def __cmd_select_prev_segment(self, keyval, state): + return self.__select_segment(-1) + + def __cmd_shrink_segment(self, keyval, state): + if not self._chk_mode('25'): + return False + + if self.__convert_mode == CONV_MODE_ANTHY: + self.__shrink_segment(-1) + return True + + def __cmd_expand_segment(self, keyval, state): + if not self._chk_mode('25'): + return False + + if self.__convert_mode == CONV_MODE_ANTHY: + self.__shrink_segment(1) + return True + + def __move_cursor_char_length(self, length): + if Engine.__input_mode == INPUT_MODE_HIRAGANA: + self.__preedit_ja_string.move_cursor_hiragana_length(length) + elif Engine.__input_mode == INPUT_MODE_KATAKANA: + self.__preedit_ja_string.move_cursor_katakana_length(length) + elif Engine.__input_mode == INPUT_MODE_HALF_WIDTH_KATAKANA: + self.__preedit_ja_string.move_cursor_half_with_katakana_length(length) + else: + self.__preedit_ja_string.move_cursor(length) + + def __commit_nth_segment(self, commit_index, keyval, state): + + if commit_index >= len(self.__segments): + return False + + if self.__convert_mode == CONV_MODE_ANTHY: + for i in range(0, commit_index + 1): + (seg_index, text) = self.__segments[i] + self.commit_text(IBus.Text.new_from_string(text)) + + text, cursor = self.__get_preedit() + commit_length = 0 + for i in range(0, commit_index + 1): + buf = self.__context.get_segment(i, NTH_UNCONVERTED_CANDIDATE) + commit_length += len(buf) + self.__move_cursor_char_length(commit_length - cursor) + for i in range(0, commit_length): + self.__preedit_ja_string.remove_before() + self.__move_cursor_char_length(cursor - commit_length) + + del self.__segments[0:commit_index + 1] + + if len(self.__segments) == 0: + self.__reset() + else: + if self.__cursor_pos > commit_index: + self.__cursor_pos -= (commit_index + 1) + else: + self.__cursor_pos = 0 + text, cursor = self.__get_preedit() + self.__convert_chars = text + self.__context.set_string(text) + + self.__lookup_table.clear() + self.__lookup_table.set_cursor_visible(False) + self.__lookup_table_visible = False + self.update_aux_string('', IBus.AttrList(), + self.__lookup_table_visible) + self.__fill_lookup_table() + self.__invalidate() + self.__update_input_chars() + + return True + + def __cmd_commit_first_segment(self, keyval, state): + return self.__commit_nth_segment(0, keyval, state) + + def __cmd_commit_selected_segment(self, keyval, state): + return self.__commit_nth_segment(self.__cursor_pos, keyval, state) + + #candidates_keys + def __on_candidate_index_in_page(self, index): + if not self._chk_mode('5'): + return False + + if index >= self.__lookup_table.get_page_size(): + return False + cursor_pos = self.__lookup_table.get_cursor_pos() + cursor_in_page = self.__lookup_table.get_cursor_in_page() + real_index = cursor_pos - cursor_in_page + index + if real_index >= self.__lookup_table.get_number_of_candidates(): + return False + self.__lookup_table.set_cursor_pos(real_index) + index = self.__lookup_table.get_cursor_pos() + candidate = self.__lookup_table.get_candidate(index).get_text() + self.__segments[self.__cursor_pos] = index, candidate + self.__lookup_table_visible = False + self.__on_key_right() + self.__invalidate() + return True + + def __cmd_select_first_candidate(self, keyval, state): + return self.__on_candidate_index_in_page(0) + + def __cmd_select_last_candidate(self, keyval, state): + return self.__on_candidate_index_in_page( + self.__lookup_table.get_page_size() - 1) + + def __cmd_select_next_candidate(self, keyval, state): + if not self._chk_mode('235'): + return False + + return self.__on_key_down() + + def __cmd_select_prev_candidate(self, keyval, state): + if not self._chk_mode('235'): + return False + + return self.__on_key_up() + + def __cmd_candidates_page_up(self, keyval, state): + if not self._chk_mode('5'): + return False + + return self.__on_key_page_up() + + def __cmd_candidates_page_down(self, keyval, state): + if not self._chk_mode('5'): + return False + + return self.__on_key_page_down() + + #direct_select_keys + def __select_keyval(self, keyval): + if not self._chk_mode('5'): + return False + + return self.__on_key_number(keyval) + + def __cmd_select_candidates_1(self, keyval, state): + return self.__select_keyval(keyval) + + def __cmd_select_candidates_2(self, keyval, state): + return self.__select_keyval(keyval) + + def __cmd_select_candidates_3(self, keyval, state): + return self.__select_keyval(keyval) + + def __cmd_select_candidates_4(self, keyval, state): + return self.__select_keyval(keyval) + + def __cmd_select_candidates_5(self, keyval, state): + return self.__select_keyval(keyval) + + def __cmd_select_candidates_6(self, keyval, state): + return self.__select_keyval(keyval) + + def __cmd_select_candidates_7(self, keyval, state): + return self.__select_keyval(keyval) + + def __cmd_select_candidates_8(self, keyval, state): + return self.__select_keyval(keyval) + + def __cmd_select_candidates_9(self, keyval, state): + return self.__select_keyval(keyval) + + def __cmd_select_candidates_0(self, keyval, state): + return self.__select_keyval(keyval) + + #convert_keys + def __cmd_convert_to_char_type_forward(self, keyval, state): + if self.__convert_mode == CONV_MODE_ANTHY: + n = self.__segments[self.__cursor_pos][0] + if n == NTH_HIRAGANA_CANDIDATE: + return self.__convert_segment_to_kana(NTH_KATAKANA_CANDIDATE) + elif n == NTH_KATAKANA_CANDIDATE: + return self.__convert_segment_to_kana(NTH_HALFKANA_CANDIDATE) + elif n == NTH_HALFKANA_CANDIDATE: + return self.__convert_segment_to_latin(-100) + elif n == -100: + return self.__convert_segment_to_latin(-101) + else: + return self.__convert_segment_to_kana(NTH_HIRAGANA_CANDIDATE) + + if self.__convert_mode == CONV_MODE_KATAKANA: + return self.__cmd_convert_to_half_katakana(keyval, state) + elif self.__convert_mode == CONV_MODE_HALF_WIDTH_KATAKANA: + return self.__cmd_convert_to_latin(keyval, state) + elif CONV_MODE_LATIN_0 <= self.__convert_mode <= CONV_MODE_LATIN_3: + return self.__cmd_convert_to_wide_latin(keyval, state) + elif (CONV_MODE_WIDE_LATIN_0 <= self.__convert_mode + <= CONV_MODE_WIDE_LATIN_3): + return self.__cmd_convert_to_hiragana(keyval, state) + else: + return self.__cmd_convert_to_katakana(keyval, state) + + def __cmd_convert_to_char_type_backward(self, keyval, state): + if self.__convert_mode == CONV_MODE_ANTHY: + n = self.__segments[self.__cursor_pos][0] + if n == NTH_KATAKANA_CANDIDATE: + return self.__convert_segment_to_kana(NTH_HIRAGANA_CANDIDATE) + elif n == NTH_HALFKANA_CANDIDATE: + return self.__convert_segment_to_kana(NTH_KATAKANA_CANDIDATE) + elif n == -100: + return self.__convert_segment_to_kana(NTH_HALFKANA_CANDIDATE) + elif n == -101: + return self.__convert_segment_to_latin(-100) + else: + return self.__convert_segment_to_latin(-101) + + if self.__convert_mode == CONV_MODE_KATAKANA: + return self.__cmd_convert_to_hiragana(keyval, state) + elif self.__convert_mode == CONV_MODE_HALF_WIDTH_KATAKANA: + return self.__cmd_convert_to_katakana(keyval, state) + elif CONV_MODE_LATIN_0 <= self.__convert_mode <= CONV_MODE_LATIN_3: + return self.__cmd_convert_to_half_katakana(keyval, state) + elif (CONV_MODE_WIDE_LATIN_0 <= self.__convert_mode + <= CONV_MODE_WIDE_LATIN_3): + return self.__cmd_convert_to_latin(keyval, state) + else: + return self.__cmd_convert_to_wide_latin(keyval, state) + + def __convert_segment_to_kana(self, n): + if self.__convert_mode == CONV_MODE_ANTHY and -4 <= n <= -2: + buf = self.__context.get_segment(self.__cursor_pos, n) + self.__segments[self.__cursor_pos] = n, buf + self.__lookup_table_visible = False + self.__invalidate() + return True + + return False + + def __cmd_convert_to_hiragana(self, keyval, state): + if not self._chk_mode('12345'): + return False + + if self.__convert_mode == CONV_MODE_ANTHY: + return self.__convert_segment_to_kana(NTH_HIRAGANA_CANDIDATE) + + return self.__on_key_conv(0) + + def __cmd_convert_to_katakana(self, keyval, state): + if not self._chk_mode('12345'): + return False + + if self.__convert_mode == CONV_MODE_ANTHY: + return self.__convert_segment_to_kana(NTH_KATAKANA_CANDIDATE) + + return self.__on_key_conv(1) + + def __cmd_convert_to_half(self, keyval, state): + if not self._chk_mode('12345'): + return False + + if self.__convert_mode == CONV_MODE_ANTHY: + i, s = self.__segments[self.__cursor_pos] + if i == -101: + return self.__convert_segment_to_latin(-100) + elif i == -100: + return self.__convert_segment_to_latin(-100) + return self.__convert_segment_to_kana(NTH_HALFKANA_CANDIDATE) + + elif CONV_MODE_WIDE_LATIN_0 <= self.__convert_mode <= CONV_MODE_WIDE_LATIN_3: + return self.__on_key_conv(4) + elif CONV_MODE_LATIN_0 <= self.__convert_mode <= CONV_MODE_LATIN_3: + return self.__on_key_conv(4) + return self.__on_key_conv(2) + + def __cmd_convert_to_half_katakana(self, keyval, state): + if not self._chk_mode('12345'): + return False + + if self.__convert_mode == CONV_MODE_ANTHY: + return self.__convert_segment_to_kana(NTH_HALFKANA_CANDIDATE) + + return self.__on_key_conv(2) + + def __convert_segment_to_latin(self, n): + if self.__convert_mode == CONV_MODE_ANTHY and n in [-100, -101]: + start = 0 + for i in range(self.__cursor_pos): + start += len(self.__context.get_segment(i, NTH_UNCONVERTED_CANDIDATE)) + end = start + len(self.__context.get_segment(self.__cursor_pos, NTH_UNCONVERTED_CANDIDATE)) + i, s = self.__segments[self.__cursor_pos] + s2 = self.__preedit_ja_string.get_raw(start, end) + if n == -101: + s2 = ''.join([unichar_half_to_full(c) for c in s2]) + if i == n: + if s == s2.lower(): + s2 = s2.upper() + elif s == s2.upper(): + s2 = s2.capitalize() + elif s == s2 or s == s2.capitalize(): + s2 = s2.lower() + self.__segments[self.__cursor_pos] = n, s2 + self.__lookup_table_visible = False + self.__invalidate() + return True + + return False + + def __cmd_convert_to_wide_latin(self, keyval, state): + if not self._chk_mode('12345'): + return False + + if self.__convert_mode == CONV_MODE_ANTHY: + return self.__convert_segment_to_latin(-101) + + return self.__on_key_conv(3) + + def __cmd_convert_to_latin(self, keyval, state): + if not self._chk_mode('12345'): + return False + + if self.__convert_mode == CONV_MODE_ANTHY: + return self.__convert_segment_to_latin(-100) + + return self.__on_key_conv(4) + + #dictonary_keys + def __cmd_dict_admin(self, keyval, state): + if not self._chk_mode('0'): + return False + + self.__start_dict_admin() + return True + + def __cmd_add_word(self, keyval, state): + if not self._chk_mode('0'): + return False + + self.__start_add_word() + return True + + def __cmd_start_setup(self, keyval, state): + if not self._chk_mode('0'): + return False + + self.__start_setup() + return True + + def __start_dict_admin(self): + command = self.__prefs.get_value('common', 'dict_admin_command') + os.spawnl(os.P_NOWAIT, *command) + + def __start_add_word(self): + command = self.__prefs.get_value('common', 'add_word_command') + os.spawnl(os.P_NOWAIT, *command) + + def __start_setup(self): + if Engine.__setup_pid != 0: + pid, state = os.waitpid(Engine.__setup_pid, os.P_NOWAIT) + if pid != Engine.__setup_pid: + return + Engine.__setup_pid = 0 + setup_cmd = path.join(config.LIBEXECDIR, 'ibus-setup-anthy') + Engine.__setup_pid = os.spawnl(os.P_NOWAIT, setup_cmd, 'ibus-setup-anthy') + + def __cmd_hiragana_for_latin_with_shift(self, keyval, state): + self.__preedit_ja_string.set_hiragana_katakana(True) + diff --git a/engine/python3/factory.py b/engine/python3/factory.py new file mode 100644 index 0000000..8994793 --- /dev/null +++ b/engine/python3/factory.py @@ -0,0 +1,80 @@ +# vim:set et sts=4 sw=4: +# -*- coding: utf-8 -*- +# +# ibus-anthy - The Anthy engine for IBus +# +# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com> +# Copyright (c) 2010-2014 Takao Fujiwara <takao.fujiwara1@gmail.com> +# Copyright (c) 2007-2014 Red Hat, Inc. +# +# 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 of the License, 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import os + +from gi.repository import IBus + +import _config as config +import engine + + +class EngineFactory(IBus.Factory): + FACTORY_PATH = '/com/redhat/IBus/engines/Anthy/Factory' + ENGINE_PATH = '/com/redhat/IBus/engines/Anthy/Engine' + NAME = 'Anthy' + LANG = 'ja' + ICON = config.PKGDATADIR + '/icons/ibus-anthy.png' + AUTHORS = 'Huang Peng <shawn.p.huang@gmail.com>' + CREDITS = 'GPLv2' + + def __init__(self, bus): + self.__bus = bus + engine.Engine.CONFIG_RELOADED(bus) + super(EngineFactory, self).__init__(object_path=IBus.PATH_FACTORY, + connection=bus.get_connection()) + + self.__id = 0 + self.__config = self.__bus.get_config() + + if self.__config != None: + self.__config.connect('value-changed', + self.__config_value_changed_cb) + else: + print('ibus-config is not running or bus address is not correct.', + file=sys.stderr) + + bus.get_connection().signal_subscribe('org.freedesktop.DBus', + 'org.freedesktop.DBus', + 'NameOwnerChanged', + '/org/freedesktop/DBus', + None, + 0, + self.__name_owner_changed_cb, + bus) + + def do_create_engine(self, engine_name): + if engine_name == 'anthy': + self.__id += 1 + return engine.Engine(self.__bus, '%s/%d' % (self.ENGINE_PATH, self.__id)) + + return super(EngineFactory, self).do_create_engine(engine_name) + + def __config_value_changed_cb(self, config, section, name, value): + engine.Engine.CONFIG_VALUE_CHANGED(self.__bus, section, name, value) + + def __name_owner_changed_cb(self, connection, sender_name, object_path, + interface_name, signal_name, parameters, + user_data): + if signal_name == 'NameOwnerChanged': + engine.Engine.CONFIG_RELOADED(self.__bus) diff --git a/engine/python3/ibus-engine-anthy.in b/engine/python3/ibus-engine-anthy.in new file mode 100644 index 0000000..c54b10a --- /dev/null +++ b/engine/python3/ibus-engine-anthy.in @@ -0,0 +1,33 @@ +#!/bin/sh +# +# vim:set noet ts=4: +# +# ibus-anthy - The Anthy engine for IBus +# +# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com> +# Copyright (c) 2010-2013 Takao Fujiwara <takao.fujiwara1@gmail.com> +# Copyright (c) 2007-2013 Red Hat, Inc. +# +# 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 of the License, 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +prefix=@prefix@ +datarootdir=@datarootdir@ +exec_prefix=@exec_prefix@ +libexecdir=@libexecdir@ +export IBUS_PREFIX=@prefix@ +export IBUS_ANTHY_PKGDATADIR=@datarootdir@/@PACKAGE@ +export LIBEXECDIR=$libexecdir +exec @ENV_IBUS_ENGINE@ @PYTHON@ @datarootdir@/@PACKAGE@/engine/main.py $@ + diff --git a/engine/python3/jastring.py b/engine/python3/jastring.py new file mode 100644 index 0000000..255799d --- /dev/null +++ b/engine/python3/jastring.py @@ -0,0 +1,304 @@ +# vim:set et sts=4 sw=4: +# -*- coding: utf-8 -*- +# +# ibus-anthy - The Anthy engine for IBus +# +# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com> +# Copyright (c) 2010-2014 Takao Fujiwara <takao.fujiwara1@gmail.com> +# Copyright (c) 2007-2014 Red Hat, Inc. +# +# 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 of the License, 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import romaji +import kana +import thumb + +from segment import unichar_half_to_full + +HalfSymbolTable = {} +for i in range(32, 127): + if not chr(i).isalnum(): + HalfSymbolTable[unichar_half_to_full(chr(i))] = chr(i) + +HalfNumberTable = {} +for i in range(10): + HalfNumberTable[unichar_half_to_full(str(i))] = str(i) + +PeriodTable = {'。': '.', '、': ',', '。': '.', '、': ','} + +SymbolTable = {} +SymbolTable[0] = {'「': '「', '」': '」', '/': '/'} +SymbolTable[1] = {'「': '「', '」': '」', '/': '・'} +SymbolTable[2] = {'「': '[', '」': ']', '/': '/'} +SymbolTable[3] = {'「': '[', '」': ']', '/': '・'} + +TYPING_MODE_ROMAJI, \ +TYPING_MODE_KANA, \ +TYPING_MODE_THUMB_SHIFT = list(range(3)) + +class JaString: + _prefs = None + _mode = TYPING_MODE_ROMAJI + _shift = False + _unshift = False + + def __init__(self, mode=TYPING_MODE_ROMAJI, latin_with_shift=True): + self._init_mode(mode) + if mode == TYPING_MODE_ROMAJI: + romaji.RomajiSegment.SET_LATIN_WITH_SHIFT(latin_with_shift) + + @classmethod + def _init_mode(cls, mode): + cls._mode = mode + cls._shift = False + cls._unshift = False + cls.__cursor = 0 + cls.__segments = list() + if mode == TYPING_MODE_ROMAJI: + romaji.RomajiSegment.INIT_ROMAJI_TYPING_RULE(cls._prefs) + elif mode == TYPING_MODE_KANA: + kana.KanaSegment.INIT_KANA_TYPING_RULE(cls._prefs) + elif mode == TYPING_MODE_THUMB_SHIFT: + thumb.ThumbShiftSegment.INIT_THUMB_TYPING_RULE(cls._prefs) + + @classmethod + def SET_PREFS(cls, prefs): + cls._prefs = prefs + + @classmethod + def RESET(cls, prefs, section, name, value): + cls._prefs = prefs + if section.startswith('kana_typing_rule'): + mode = TYPING_MODE_KANA + kana.KanaSegment.RESET(prefs, section, name, value) + cls._init_mode(mode) + if section == 'common' and name == 'latin_with_shift': + romaji.RomajiSegment.SET_LATIN_WITH_SHIFT(value) + + def set_shift(self, shift): + self._shift = shift + + def set_hiragana_katakana(self, mode): + if mode and self._mode == TYPING_MODE_ROMAJI: + self._unshift = True + + def insert(self, c): + segment_before = None + segment_after = None + new_segments = None + + if self.__cursor >= 1: + segment_before = self.__segments[self.__cursor - 1] + if self.__cursor < len(self.__segments): + segment_after = self.__segments[self.__cursor] + if segment_before and not segment_before.is_finished(): + if type(segment_before) == romaji.RomajiSegment: + new_segments = segment_before.append(c, + self._shift, + self._unshift) + self._unshift = False + else: + new_segments = segment_before.append(c) + elif segment_after and not segment_after.is_finished(): + if type(segment_after) == romaji.RomajiSegment: + new_segments = segment_after.prepend(c, + self._shift, + self._unshift) + self._unshift = False + else: + new_segments = segment_after.prepend(c) + else: + if c != '\0' and c != '': + if self._mode == TYPING_MODE_ROMAJI: + new_segments = [romaji.RomajiSegment(c, + '', + self._shift, + self._unshift)] + self._unshift = False + elif self._mode == TYPING_MODE_KANA: + # kana mode doesn't have shift latin in MS. + new_segments = [kana.KanaSegment(c)] + elif self._mode == TYPING_MODE_THUMB_SHIFT: + new_segments = [thumb.ThumbShiftSegment(c)] + if new_segments: + self.__segments[self.__cursor:self.__cursor] = new_segments + self.__cursor += len(new_segments) + + def remove_before(self): + index = self.__cursor - 1 + if index >= 0: + segment = self.__segments[index] + segment.pop() + if segment.is_empty(): + del self.__segments[index] + self.__cursor = index + return True + + return False + + def remove_after(self): + index = self.__cursor + if index < len(self.__segments): + segment = self.__segments[index] + segment.pop() + if segment.is_empty(): + del self.__segments[index] + return True + + return False + + def get_string(self, type): + pass + + def move_cursor(self, delta): + self.__cursor += delta + if self.__cursor < 0: + self.__cursor = 0 + elif self.__cursor > len(self.__segments): + self.__cursor = len(self.__segments) + + # hiragana segments are not char lengths. + # e.g. 'ya' is 1 segment and 1 char and 'kya' is 1 segment and 2 chars. + def move_cursor_hiragana_length(self, length): + delta = length + if delta < 0: + if self.__cursor >= len(self.__segments): + delta = delta + (self.__cursor - len(self.__segments) + 1) + self.__cursor = len(self.__segments) - 1 + while delta < 0: + text = str(self.__segments[self.__cursor].to_hiragana()) + if len(text) > -delta: + break + delta = delta + len(text) + self.__cursor = self.__cursor - 1 + else: + if self.__cursor >= len(self.__segments): + self.__cursor = len(self.__segments) + return + while delta > 0: + text = str(self.__segments[self.__cursor].to_hiragana()) + if len(text) > delta: + break + delta = delta - len(text) + self.__cursor = self.__cursor + 1 + + def move_cursor_katakana_length(self, length): + delta = length + if delta < 0: + if self.__cursor >= len(self.__segments): + delta = delta + (self.__cursor - len(self.__segments) + 1) + self.__cursor = len(self.__segments) - 1 + while delta < 0: + text = str(self.__segments[self.__cursor].to_katanaka()) + if len(text) > -delta: + break + delta = delta + len(text) + self.__cursor = self.__cursor - 1 + else: + if self.__cursor >= len(self.__segments): + self.__cursor = len(self.__segments) + return + while delta > 0: + text = str(self.__segments[self.__cursor].to_katanaka()) + if len(text) > delta: + break + delta = delta - len(text) + self.__cursor = self.__cursor + 1 + + def move_cursor_half_with_katakana_length(self, length): + delta = length + if delta < 0: + if self.__cursor >= len(self.__segments): + delta = delta + (self.__cursor - len(self.__segments) + 1) + self.__cursor = len(self.__segments) - 1 + while delta < 0: + text = str(self.__segments[self.__cursor].to_half_width_katakana()) + if len(text) > -delta: + break + delta = delta + len(text) + self.__cursor = self.__cursor - 1 + else: + if self.__cursor >= len(self.__segments): + self.__cursor = len(self.__segments) + return + while delta > 0: + text = str(self.__segments[self.__cursor].to_half_width_katakana()) + if len(text) > delta: + break + delta = delta - len(text) + self.__cursor = self.__cursor + 1 + + def _chk_text(self, s): + period = self._prefs.get_value('common', 'period_style') + symbol = self._prefs.get_value('common', 'symbol_style') + half_symbol = self._prefs.get_value('common', 'half_width_symbol') + half_number = self._prefs.get_value('common', 'half_width_number') + ret = '' + for c in s: + c = c if not period else PeriodTable.get(c, c) + # thumb_left + '2' and '/' are different + if self._mode != TYPING_MODE_THUMB_SHIFT: + c = c if not symbol else SymbolTable[symbol].get(c, c) + c = c if not half_symbol else HalfSymbolTable.get(c, c) + c = c if not half_number else HalfNumberTable.get(c, c) + ret += c + return ret + + def get_hiragana(self, commit=False): + conv = lambda s: s.to_hiragana() + R = lambda s: s if not (commit and s[-1:] == 'n') else s[:-1] + 'ん' + text_before = R(''.join(map(conv, self.__segments[:self.__cursor]))) + text_after = R(''.join(map(conv, self.__segments[self.__cursor:]))) + return self._chk_text(text_before + text_after), len(text_before) + + def get_katakana(self, commit=False): + conv = lambda s: s.to_katakana() + R = lambda s: s if not (commit and s[-1:] == 'n') else s[:-1] + 'ン' + text_before = R(''.join(map(conv, self.__segments[:self.__cursor]))) + text_after = R(''.join(map(conv, self.__segments[self.__cursor:]))) + return self._chk_text(text_before + text_after), len(text_before) + + def get_half_width_katakana(self, commit=False): + conv = lambda s: s.to_half_width_katakana() + R = lambda s: s if not (commit and s[-1:] == 'n') else s[:-1] + 'ン' + text_before = R(''.join(map(conv, self.__segments[:self.__cursor]))) + text_after = R(''.join(map(conv, self.__segments[self.__cursor:]))) + return self._chk_text(text_before + text_after), len(text_before) + + def get_latin(self): + conv = lambda s: s.to_latin() + text_before = ''.join(map(conv, self.__segments[:self.__cursor])) + text_after = ''.join(map(conv, self.__segments[self.__cursor:])) + return text_before + text_after, len(text_before) + + def get_wide_latin(self): + conv = lambda s: s.to_wide_latin() + text_before = ''.join(map(conv, self.__segments[:self.__cursor])) + text_after = ''.join(map(conv, self.__segments[self.__cursor:])) + return text_before + text_after, len(text_before) + + def is_empty(self): + return all([s.is_empty() for s in self.__segments]) + + def get_raw(self, start, end): + i = 0 + r = '' + for s in self.__segments: + if i >= end: + break + elif start <= i: + r += s.to_latin() + i += len(s.to_hiragana()) + return r diff --git a/engine/python3/kana.py b/engine/python3/kana.py new file mode 100644 index 0000000..10e1b96 --- /dev/null +++ b/engine/python3/kana.py @@ -0,0 +1,170 @@ +# vim:set et sts=4 sw=4: +# -*- coding: utf-8 -*- +# +# ibus-anthy - The Anthy engine for IBus +# +# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com> +# Copyright (c) 2010-2014 Takao Fujiwara <takao.fujiwara1@gmail.com> +# Copyright (c) 2007-2014 Red Hat, Inc. +# +# 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 of the License, 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import sys + +from tables import * +import segment + +_UNFINISHED_HIRAGANA = set('かきくけこさしすせそたちつてとはひふへほ') + +class KanaSegment(segment.Segment): + _prefs = None + _kana_typing_rule_section = None + _kana_voiced_consonant_rule = None + + def __init__(self, enchars='', jachars=''): + if not jachars: + jachars = self.__get_kana_typing_rule(enchars, '') + super(KanaSegment, self).__init__(enchars, jachars) + + @classmethod + def INIT_KANA_TYPING_RULE(cls, prefs): + cls._prefs = prefs + if prefs == None: + cls._kana_typing_rule_section = None + return + if cls._kana_typing_rule_section == None: + cls._init_kana_typing_method() + if cls._kana_voiced_consonant_rule == None and \ + cls._kana_typing_rule_section != None: + cls._init_kana_voiced_consonant_rule() + + @classmethod + def _init_kana_typing_method(cls, method=None): + prefs = cls._prefs + if method == None: + method = prefs.get_value('kana_typing_rule', 'method') + if method == None: + method = 'jp' + cls._kana_typing_rule_section = 'kana_typing_rule/' + method + if cls._kana_typing_rule_section not in prefs.sections(): + cls._kana_typing_rule_section = None + + @classmethod + def _init_kana_voiced_consonant_rule(cls): + prefs = cls._prefs + # Create kana_voiced_consonant_rule dynamically. + # E.g. 't' + '@' on jp kbd becomes Hiragana GA + # 't' + '[' on us kbd becomes Hiragana GA + # If the customized table provides U+309b with other chars, + # it needs to be detected dynamically. + cls._kana_voiced_consonant_rule = {} + section = cls._kana_typing_rule_section + for gkey in prefs.keys(section): + value = prefs.get_value(section, gkey) + key = prefs.typing_from_config_key(gkey) + if key == '': + continue + if value == chr(0x309b): + for no_voiced, voiced in \ + list(kana_voiced_consonant_no_rule.items()): + rule = no_voiced + key + cls._kana_voiced_consonant_rule[rule] = voiced + if value == chr(0x309c): + for no_voiced, voiced in \ + list(kana_semi_voiced_consonant_no_rule.items()): + rule = no_voiced + key + cls._kana_voiced_consonant_rule[rule] = voiced + + @classmethod + def RESET(cls, prefs, section, name, value): + cls._prefs = prefs + if section == 'kana_typing_rule' and name == 'method' and \ + value != None: + cls._kana_typing_rule_section = None + cls._kana_voiced_consonant_rule = None + cls._init_kana_typing_method(value) + elif section.startswith('kana_typing_rule/'): + # Probably it's better to restart ibus by manual + # instead of saving the emitted values from config. + cls._kana_voiced_consonant_rule = None + + def __get_kana_typing_rule(self, enchars, retval=None): + prefs = self._prefs + value = None + section = self._kana_typing_rule_section + if section != None: + # Need to send Unicode to typing_to_config_key instead of UTF-8 + # not to separate U+A5 + gkey = prefs.typing_to_config_key(enchars) + if gkey == '': + return None + enchars = gkey + if enchars in prefs.keys(section): + value = prefs.str(prefs.str(prefs.get_value(section, enchars))) + else: + prefs.set_no_key_warning(True) + value = prefs.get_value_direct(section, enchars) + prefs.set_no_key_warning(False) + if value != None: + value = prefs.str(prefs.str(value)) + if value == '': + value = None + if value == None: + value = retval + else: + value = kana_typing_rule_static.get(enchars, retval) + return value + + def is_finished(self): + return not (self._jachars in _UNFINISHED_HIRAGANA) + + def append(self, enchar): + if enchar == '\0' or enchar == '': + return [] + if self._jachars: + text = self._jachars + enchar + if self._kana_voiced_consonant_rule != None: + jachars = self._kana_voiced_consonant_rule.get(text, None) + if jachars: + self._enchars = self._enchars + enchar + self._jachars = jachars + return [] + return [KanaSegment(enchar)] + self._enchars = self._enchars + enchar + self._jachars = self.__get_kana_typing_rule(self._enchars, '') + return [] + + def prepend(self, enchar): + if enchar == '\0' or enchar == '': + return [] + if self._enchars == '': + self._enchars = enchar + self._jachars = self.__get_kana_typing_rule(self._enchars, '') + return [] + return [KanaSegment(enchar)] + + def pop(self, index=-1): + if index == -1: + index = len(self._enchars) - 1 + if index < 0 or index >= len(self._enchars): + raise IndexError('Out of bound') + if self.is_finished(): + self._enchars = '' + self._jachars = '' + else: + enchars = list(self._enchars) + del enchars[index] + self._enchars = ''.join(enchars) + self._jachars = self.__get_kana_typing_rule(self._enchars, '') diff --git a/engine/python3/main.py b/engine/python3/main.py new file mode 100644 index 0000000..eb6fe5f --- /dev/null +++ b/engine/python3/main.py @@ -0,0 +1,188 @@ +# vim:set et sts=4 sw=4: +# -*- coding: utf-8 -*- +# +# ibus-anthy - The Anthy engine for IBus +# +# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com> +# Copyright (c) 2010-2014 Takao Fujiwara <takao.fujiwara1@gmail.com> +# Copyright (c) 2007-2014 Red Hat, Inc. +# +# 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 of the License, 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import os +from os import path +import sys +import getopt +import locale +import xml.dom.minidom + +from gi.repository import GLib + +# set_prgname before importing factory to show the name in warning +# messages when import modules are failed. E.g. Gtk. +GLib.set_prgname('ibus-engine-anthy') + +from gi.repository import IBus + +import _config as config +import factory + +class IMApp: + def __init__(self, exec_by_ibus): + command_line = config.LIBEXECDIR + '/ibus-engine-anthy --ibus' + self.__component = IBus.Component(name='org.freedesktop.IBus.Anthy', + description='Anthy Component', + version='0.1.0', + license='GPL', + author='Peng Huang <shawn.p.huang@gmail.com>', + homepage='http://code.google.com/p/ibus/', + command_line=command_line, + textdomain='ibus-anthy') + engine = IBus.EngineDesc(name='anthy', + longname='Anthy', + description='Anthy Input Method', + language='ja', + license='GPL', + author='Peng Huang <shawn.p.huang@gmail.com>', + icon='ibus-anthy', + layout=config.LAYOUT, + symbol=config.SYMBOL_CHAR, + rank=99) + self.__component.add_engine(engine) + self.__mainloop = GLib.MainLoop() + self.__bus = IBus.Bus() + self.__bus.connect('disconnected', self.__bus_disconnected_cb) + self.__factory = factory.EngineFactory(self.__bus) + if exec_by_ibus: + self.__bus.request_name('org.freedesktop.IBus.Anthy', 0) + else: + self.__bus.register_component(self.__component) + + def run(self): + self.__mainloop.run() + + def __bus_disconnected_cb(self, bus): + self.__mainloop.quit() + + +def launch_engine(exec_by_ibus): + IMApp(exec_by_ibus).run() + +def get_userhome(): + if 'HOME' not in os.environ: + import pwd + userhome = pwd.getpwuid(os.getuid()).pw_dir + else: + userhome = os.environ['HOME'] + userhome = userhome.rstrip('/') + return userhome + +def resync_engine_file(): + user_config = path.join(get_userhome(), '.config', + 'ibus-anthy', 'engines.xml') + system_config = path.join(config.PKGDATADIR, 'engine', 'default.xml') + if not path.exists(user_config): + return + if not path.exists(system_config): + os.unlink(user_config) + return + + # path.getmtime depends on the build time rather than install time. + def __get_engine_file_version(engine_file): + version_str = '' + dom = xml.dom.minidom.parse(engine_file) + elements = dom.getElementsByTagName('version') + nodes = [] + if len(elements) > 0: + nodes = elements[0].childNodes + if len(nodes) > 0: + version_str = nodes[0].data + if version_str != '': + version_str = version_str.strip() + return version_str + + user_config_version = __get_engine_file_version(user_config) + system_config_version = __get_engine_file_version(system_config) + if system_config_version > user_config_version: + import shutil + shutil.copyfile(system_config, user_config) + +def print_xml(): + user_config = os.path.join(get_userhome(), '.config', + 'ibus-anthy', 'engines.xml') + system_config = os.path.join(config.PKGDATADIR, 'engine', 'default.xml') + xml = None + for f in [user_config, system_config]: + if os.path.exists(f): + xml = f + break + if xml == None: + print('Not exist: %s' % system_config, file=sys.stderr) + return + file = open(xml, 'r') + print(file.read()) + file.close() + +def print_help(out, v = 0): + print('-i, --ibus executed by ibus.', file=out) + print('-h, --help show this message.', file=out) + print('-d, --daemonize daemonize ibus.', file=out) + print('-x, --xml print engine xml.', file=out) + sys.exit(v) + +def main(): + try: + locale.setlocale(locale.LC_ALL, '') + except: + pass + + exec_by_ibus = False + daemonize = False + xml = False + + shortopt = 'ihdx' + longopt = ['ibus', 'help', 'daemonize', 'xml'] + + try: + opts, args = getopt.getopt(sys.argv[1:], shortopt, longopt) + except getopt.GetoptError as 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 + elif o in ('-x', '--xml'): + xml = True + else: + print('Unknown argument: %s' % o, file=sys.stderr) + print_help(sys.stderr, 1) + + if daemonize: + if os.fork(): + sys.exit() + + if xml: + resync_engine_file() + print_xml() + return + + launch_engine(exec_by_ibus) + +if __name__ == '__main__': + main() diff --git a/engine/python3/romaji.py b/engine/python3/romaji.py new file mode 100644 index 0000000..d495120 --- /dev/null +++ b/engine/python3/romaji.py @@ -0,0 +1,263 @@ +# vim:set et sts=4 sw=4: +# -*- coding: utf-8 -*- +# +# ibus-anthy - The Anthy engine for IBus +# +# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com> +# Copyright (c) 2010-2014 Takao Fujiwara <takao.fujiwara1@gmail.com> +# Copyright (c) 2007-2014 Red Hat, Inc. +# +# 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 of the License, 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import sys + +from tables import * +import segment + +def romaji_correction_rule_get(k, d): + return ('ん', k[1:2]) if k[0:1] == 'n' and not k[1:2] in "aiueony'" else d + +class RomajiSegment(segment.Segment): + _prefs = None + _romaji_typing_rule_section = None + _latin_with_shift = True + _shift_mode = False + + def __init__(self, enchars='', jachars='', shift=False, unshift=False): + if self._latin_with_shift: + # If Shift key is pressed, Latin mode. + # If Hiragana_Katakana key is pressed, Hiragana mode. + if shift: + self._shift_mode = True + if unshift: + self._shift_mode = False + + enchars_orig = enchars + # Even if the chars are capital with CapsLock, Hiragana + # should be converted. E.g. 'SA' + enchars = enchars.lower() + + if not jachars and not shift: + jachars = self.__get_romaji_typing_rule(enchars, None) + if jachars == None: + jachars = symbol_rule.get(enchars, '') + super(RomajiSegment, self).__init__(enchars_orig, jachars) + + @classmethod + def INIT_ROMAJI_TYPING_RULE(cls, prefs): + cls._prefs = prefs + if prefs == None: + cls._romaji_typing_rule_section = None + return + method = prefs.get_value('romaji_typing_rule', 'method') + if method == None: + method = 'default' + cls._romaji_typing_rule_section = 'romaji_typing_rule/' + method + if cls._romaji_typing_rule_section not in prefs.sections(): + cls._romaji_typing_rule_section = None + + @classmethod + def SET_LATIN_WITH_SHIFT(cls, latin_with_shift): + # Do not use IBus.Config in every conversion for the performance. + cls._latin_with_shift = latin_with_shift + + def __get_romaji_typing_rule(self, enchars, retval=None): + prefs = self._prefs + value = None + section = self._romaji_typing_rule_section + if section != None: + # Need to send Unicode to typing_to_config_key instead of UTF-8 + # not to separate U+A5 + gkey = prefs.typing_to_config_key(enchars) + if gkey == '': + return None + if gkey in prefs.keys(section): + value = prefs.get_value(section, gkey) + else: + prefs.set_no_key_warning(True) + value = prefs.get_value_direct(section, gkey) + prefs.set_no_key_warning(False) + if value == '': + value = None + if value == None: + value = retval + else: + value = romaji_typing_rule_static.get(enchars, retval) + return value + + def is_finished(self): + return self._jachars != '' + + def append(self, enchar, shift=False, unshift=False): + if self.is_finished(): + if enchar == '' and enchar == '\0': + return [] + return [RomajiSegment(enchar)] + + text_orig = self._enchars + enchar + text = text_orig.lower() + + if self._latin_with_shift: + # If Shift key is pressed, Latin mode. + # If Hiragana_Katakana key is pressed, Hiragana mode. + if shift: + self._shift_mode = True + if unshift: + self._shift_mode = False + if self._shift_mode: + self._enchars = text_orig + return [] + + if shift: + self._enchars = text_orig + return [] + + jachars = self.__get_romaji_typing_rule(text, None) + if jachars == None: + jachars = symbol_rule.get(text, None) + if jachars: + self._enchars = text_orig + self._jachars = jachars + return [] + + jachars, c = romaji_double_consonat_typing_rule.get(text, (None, None)) + if jachars: + self._enchars = text_orig[0] + self._jachars = jachars + return [RomajiSegment(c)] + +# jachars, c = romaji_correction_rule.get(text, (None, None)) + jachars, c = romaji_correction_rule_get(text, (None, None)) + if jachars: + self._enchars = text_orig[0] + self._jachars = jachars + return [RomajiSegment(c)] + + for i in range(-min(4, len(text)), 0): + enchars = text[i:] + + jachars = self.__get_romaji_typing_rule(enchars, None) + if jachars == None: + jachars = symbol_rule.get(enchars, None) + if jachars: + jasegment = RomajiSegment(enchars, jachars) + self._enchars = text_orig[:i] + return [jasegment] + + jachars, c = romaji_double_consonat_typing_rule.get(enchars, (None, None)) + if jachars: + jasegment = RomajiSegment(enchars[:-len(c)], jachars) + self._enchars = text_orig[:i] + if c: + return [jasegment, RomajiSegment(c)] + return [jasegment] + +# jachars, c = romaji_correction_rule.get(enchars, (None, None)) + jachars, c = romaji_correction_rule_get(enchars, (None, None)) + if jachars: + jasegment = RomajiSegment(enchars[:-len(c)], jachars) + self._enchars = text_orig[:i] + if c: + return [jasegment, RomajiSegment(c)] + return [jasegment] + + self._enchars = text_orig + return [] + + def prepend(self, enchar, shift=False, unshift=False): + if enchar == '' or enchar == '\0': + return [] + + if self.is_finished(): + return [RomajiSegment(enchar)] + + text_orig = enchar + self._enchars + text = text_orig.lower() + + if self._latin_with_shift: + if shift: + self._shift_mode = True + if unshift: + self._shift_mode = False + if self._shift_mode: + self._enchars = text_orig + return [] + + if shift: + self._enchars = text_orig + return [] + + jachars = self.__get_romaji_typing_rule(text, None) + if jachars == None: + jachars = symbol_rule.get(text, None) + if jachars: + self._enchars = text_orig + self._jachars = jachars + return [] + + jachars, c = romaji_double_consonat_typing_rule.get(text, (None, None)) + if jachars: + self._enchars = c + return [RomajiSegment(text_orig[0], jachars)] + +# jachars, c = romaji_correction_rule.get(text, (None, None)) + jachars, c = romaji_correction_rule_get(text, (None, None)) + if jachars: + self._enchars = c + return [RomajiSegment(text_orig[0], jachars)] + + for i in range(min(4, len(text)), 0, -1): + enchars = text[:i] + + jachars = self.__get_romaji_typing_rule(enchars, None) + if jachars == None: + jachars = symbol_rule.get(enchars, None) + if jachars: + jasegment = RomajiSegment(enchars, jachars) + self._enchars = text_orig[i:] + return [jasegment] + + jachars, c = romaji_double_consonat_typing_rule.get(enchars, (None, None)) + if jachars: + self._enchars = c + text_orig[i:] + return [RomajiSegment(enchars[:-len(c)], jachars)] + +# jachars, c = romaji_correction_rule.get(enchars, (None, None)) + jachars, c = romaji_correction_rule_get(enchars, (None, None)) + if jachars: + self._enchars = c + text_orig[i:] + return [RomajiSegment(enchars[:-len(c)], jachars)] + + self._enchars = text_orig + return [] + + def pop(self, index=-1): + if index == -1: + index = len(self._enchars) - 1 + if index < 0 or index >= len(self._enchars): + raise IndexError('Out of bound') + if self.is_finished(): + self._enchars = '' + self._jachars = '' + else: + enchars = list(self._enchars) + del enchars[index] + self._enchars = ''.join(enchars) + jachars = self.__get_romaji_typing_rule(self._enchars, None) + if jachars == None: + jachars = symbol_rule.get(self._enchars, '') + self._jachars = jachars + + diff --git a/engine/python3/segment.py b/engine/python3/segment.py new file mode 100644 index 0000000..b7450ec --- /dev/null +++ b/engine/python3/segment.py @@ -0,0 +1,95 @@ +# vim:set et sts=4 sw=4: +# -*- coding: utf-8 -*- +# +# ibus-anthy - The Anthy engine for IBus +# +# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com> +# Copyright (c) 2010-2014 Takao Fujiwara <takao.fujiwara1@gmail.com> +# Copyright (c) 2007-2014 Red Hat, Inc. +# +# 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 of the License, 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +from tables import * + +_half_full_table = [ + (0x0020, 0x3000, 1), + (0x0021, 0xFF01, 0x5E), +] + +def _h_to_f(c): + code = ord (c) + for half, full, size in _half_full_table: + if code >= half and code < half + size: + return chr(full + code - half) + return c + +def unichar_half_to_full(c): + tdl = {'"': '\u201d', "'": '\u2019', '`': '\u2018'} + return tdl[c] if c in tdl else _h_to_f(c) + +class Segment(object): + def __init__(self, enchars='', jachars=''): + self._enchars = enchars + self._jachars = jachars + + def append(self, enchar): + raise NotImplementedError('append() is not implemented') + + def prepend(self, enchar): + raise NotImplementedError('prepend() is not implemented') + + def pop(self, index=-1): + raise NotImplementedError('pop() is not implemented') + + def is_finished(self): + raise NotImplementedError('is_finised() is not implemented') + + def set_enchars(self, enchars): + self.enchars = enchars + + def get_enchars(self): + return self._enchars + + def set_jachars(self, jachars): + self._jachars = jachars + + def get_jachars(self): + return self._jachars + + def to_hiragana(self): + if self._jachars: + return self._jachars + return self._enchars + + def to_katakana(self): + if self._jachars: + return ''.join([hiragana_katakana_table.get(c, (c, c, c))[0] for c in self._jachars]) + return self._enchars + + def to_half_width_katakana(self): + if self._jachars: + return ''.join([hiragana_katakana_table.get(c, (c, c, c))[1] for c in self._jachars]) + return self._enchars + + def to_latin(self): + return self._enchars + + def to_wide_latin(self): + return ''.join(map(unichar_half_to_full, self._enchars)) + + def is_empty(self): + if self._enchars or self._jachars: + return False + return True diff --git a/engine/python3/tables.py b/engine/python3/tables.py new file mode 100644 index 0000000..b2c4cac --- /dev/null +++ b/engine/python3/tables.py @@ -0,0 +1,731 @@ +# vim:set et sts=4 sw=4: +# -*- coding: utf-8 -*- +# +# ibus-anthy - The Anthy engine for IBus +# +# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com> +# Copyright (c) 2010-2014 Takao Fujiwara <takao.fujiwara1@gmail.com> +# Copyright (c) 2007-2014 Red Hat, Inc. +# +# 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 of the License, 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +# string, result, cont +romaji_typing_rule_static = { + '-' : 'ー', + 'a' : 'あ', + 'i' : 'い', + 'u' : 'う', + 'e' : 'え', + 'o' : 'お', + 'xa' : 'ぁ', + 'xi' : 'ぃ', + 'xu' : 'ぅ', + 'xe' : 'ぇ', + 'xo' : 'ぉ', + 'la' : 'ぁ', + 'li' : 'ぃ', + 'lu' : 'ぅ', + 'le' : 'ぇ', + 'lo' : 'ぉ', + 'wha' : 'うぁ', + 'whi' : 'うぃ', + 'whe' : 'うぇ', + 'who' : 'うぉ', + 'va' : 'ヴぁ', + 'vi' : 'ヴぃ', + 'vu' : 'ヴ', + 've' : 'ヴぇ', + 'vo' : 'ヴぉ', + 'ka' : 'か', + 'ki' : 'き', + 'ku' : 'く', + 'ke' : 'け', + 'ko' : 'こ', + 'lka' : 'ヵ', + 'lke' : 'ヶ', +# u'xka' : u'ゕ', + 'xka' : 'ヵ', +# u'xke' : u'ゖ', + 'xke' : 'ヶ', + 'ga' : 'が', + 'gi' : 'ぎ', + 'gu' : 'ぐ', + 'ge' : 'げ', + 'go' : 'ご', + 'kya' : 'きゃ', + 'kyi' : 'きぃ', + 'kyu' : 'きゅ', + 'kye' : 'きぇ', + 'kyo' : 'きょ', + 'kwa' : 'くぁ', + 'gya' : 'ぎゃ', + 'gyi' : 'ぎぃ', + 'gyu' : 'ぎゅ', + 'gye' : 'ぎぇ', + 'gyo' : 'ぎょ', + 'gwa' : 'ぐぁ', + 'sa' : 'さ', + 'si' : 'し', + 'su' : 'す', + 'se' : 'せ', + 'so' : 'そ', + 'za' : 'ざ', + 'zi' : 'じ', + 'zu' : 'ず', + 'ze' : 'ぜ', + 'zo' : 'ぞ', + 'sya' : 'しゃ', + 'syi' : 'しぃ', + 'syu' : 'しゅ', + 'sye' : 'しぇ', + 'syo' : 'しょ', + 'sha' : 'しゃ', + 'shi' : 'し', + 'shu' : 'しゅ', + 'she' : 'しぇ', + 'sho' : 'しょ', + 'zya' : 'じゃ', + 'zyi' : 'じぃ', + 'zyu' : 'じゅ', + 'zye' : 'じぇ', + 'zyo' : 'じょ', + 'ja' : 'じゃ', + 'jya' : 'じゃ', + 'ji' : 'じ', + 'jyi' : 'じぃ', + 'ju' : 'じゅ', + 'jyu' : 'じゅ', + 'je' : 'じぇ', + 'jye' : 'じぇ', + 'jo' : 'じょ', + 'jyo' : 'じょ', + 'ta' : 'た', + 'ti' : 'ち', + 'tu' : 'つ', + 'tsu' : 'つ', + 'te' : 'て', + 'to' : 'と', + 'da' : 'だ', + 'di' : 'ぢ', + 'du' : 'づ', + 'de' : 'で', + 'do' : 'ど', + 'xtu' : 'っ', + 'xtsu' : 'っ', + 'ltu' : 'っ', + 'ltsu' : 'っ', + 'tya' : 'ちゃ', + 'tyi' : 'ちぃ', + 'tyu' : 'ちゅ', + 'tye' : 'ちぇ', + 'tyo' : 'ちょ', + 'cya' : 'ちゃ', + 'cyi' : 'ちぃ', + 'cyu' : 'ちゅ', + 'cye' : 'ちぇ', + 'cyo' : 'ちょ', + 'cha' : 'ちゃ', + 'chi' : 'ち', + 'chu' : 'ちゅ', + 'che' : 'ちぇ', + 'cho' : 'ちょ', + 'dya' : 'ぢゃ', + 'dyi' : 'ぢぃ', + 'dyu' : 'ぢゅ', + 'dye' : 'ぢぇ', + 'dyo' : 'ぢょ', + 'tsa' : 'つぁ', + 'tsi' : 'つぃ', + 'tse' : 'つぇ', + 'tso' : 'つぉ', + 'tha' : 'てゃ', + 'thi' : 'てぃ', + 'thu' : 'てゅ', + 'the' : 'てぇ', + 'tho' : 'てょ', + 'twu' : 'とぅ', + 'dha' : 'でゃ', + 'dhi' : 'でぃ', + 'dhu' : 'でゅ', + 'dhe' : 'でぇ', + 'dho' : 'でょ', + 'dwu' : 'どぅ', + 'na' : 'な', + 'ni' : 'に', + 'nu' : 'ぬ', + 'ne' : 'ね', + 'no' : 'の', + 'nya' : 'にゃ', + 'nyi' : 'にぃ', + 'nyu' : 'にゅ', + 'nye' : 'にぇ', + 'nyo' : 'にょ', + 'ha' : 'は', + 'hi' : 'ひ', + 'hu' : 'ふ', + 'he' : 'へ', + 'ho' : 'ほ', + 'ba' : 'ば', + 'bi' : 'び', + 'bu' : 'ぶ', + 'be' : 'べ', + 'bo' : 'ぼ', + 'pa' : 'ぱ', + 'pi' : 'ぴ', + 'pu' : 'ぷ', + 'pe' : 'ぺ', + 'po' : 'ぽ', + 'hya' : 'ひゃ', + 'hyi' : 'ひぃ', + 'hyu' : 'ひゅ', + 'hye' : 'ひぇ', + 'hyo' : 'ひょ', + 'bya' : 'びゃ', + 'byi' : 'びぃ', + 'byu' : 'びゅ', + 'bye' : 'びぇ', + 'byo' : 'びょ', + 'pya' : 'ぴゃ', + 'pyi' : 'ぴぃ', + 'pyu' : 'ぴゅ', + 'pye' : 'ぴぇ', + 'pyo' : 'ぴょ', + 'fa' : 'ふぁ', + 'fi' : 'ふぃ', + 'fu' : 'ふ', + 'fe' : 'ふぇ', + 'fo' : 'ふぉ', + 'fya' : 'ふゃ', + 'fyi' : 'ふぃ', + 'fyu' : 'ふゅ', + 'fye' : 'ふぇ', + 'fyo' : 'ふょ', + 'ma' : 'ま', + 'mi' : 'み', + 'mu' : 'む', + 'me' : 'め', + 'mo' : 'も', + 'mya' : 'みゃ', + 'myi' : 'みぃ', + 'myu' : 'みゅ', + 'mye' : 'みぇ', + 'myo' : 'みょ', + 'ya' : 'や', + 'yi' : 'い', + 'yu' : 'ゆ', + 'ye' : 'いぇ', + 'yo' : 'よ', + 'lya' : 'ゃ', + 'lyi' : 'ぃ', + 'lyu' : 'ゅ', + 'lye' : 'ぇ', + 'lyo' : 'ょ', + 'xya' : 'ゃ', + 'xyi' : 'ぃ', + 'xyu' : 'ゅ', + 'xye' : 'ぇ', + 'xyo' : 'ょ', + 'ra' : 'ら', + 'ri' : 'り', + 'ru' : 'る', + 're' : 'れ', + 'ro' : 'ろ', + 'rya' : 'りゃ', + 'ryi' : 'りぃ', + 'ryu' : 'りゅ', + 'rye' : 'りぇ', + 'ryo' : 'りょ', + 'wa' : 'わ', + 'wi' : 'うぃ', + 'wu' : 'う', + 'we' : 'うぇ', + 'wo' : 'を', + 'lwa' : 'ゎ', + 'xwa' : 'ゎ', + 'n\'' : 'ん', + 'nn' : 'ん', + 'wyi' : 'ゐ', + 'wye' : 'ゑ', +} + +symbol_rule = { + # symbols + ' ' : ' ', + ',' : '、', + '.' : '。', + '!' : '!', + '"' : '\u201d', + '#' : '#', + '$' : '$', + '%' : '%', + '&' : '&', + '\'' : '\u2019', + '(' : '(', + ')' : ')', + '~' : '\uff5e', + '-' : 'ー', + '=' : '=', + '^' : '^', + '\\' : '\', + '|' : '|', + '`' : '\u2018', + '@' : '@', + '{' : '{', + '[' : '「', + '+' : '+', + ';' : ';', + '*' : '*', + ':' : ':', + '}' : '}', + ']' : '」', + '<' : '<', + '>' : '>', + '?' : '?', + '/' : '/', + '_' : '_', + '¥' : '¥', + + # numbers + '0': '0', + '1': '1', + '2': '2', + '3': '3', + '4': '4', + '5': '5', + '6': '6', + '7': '7', + '8': '8', + '9': '9', +} + +# this is only used with romaji_typing_rule +romaji_double_consonat_typing_rule = { + # double consonant rule + 'bb' : ('っ', 'b'), + 'cc' : ('っ', 'c'), + 'dd' : ('っ', 'd'), + 'ff' : ('っ', 'f'), + 'gg' : ('っ', 'g'), + 'hh' : ('っ', 'h'), + 'jj' : ('っ', 'j'), + 'kk' : ('っ', 'k'), + 'mm' : ('っ', 'm'), + 'pp' : ('っ', 'p'), + 'rr' : ('っ', 'r'), + 'ss' : ('っ', 's'), + 'tt' : ('っ', 't'), + 'vv' : ('っ', 'v'), + 'ww' : ('っ', 'w'), + 'xx' : ('っ', 'x'), + 'yy' : ('っ', 'y'), + 'zz' : ('っ', 'z'), +} + +# this is only used with romaji_typing_rule +romaji_correction_rule = { + 'nb' : ('ん', 'b'), + 'nc' : ('ん', 'c'), + 'nd' : ('ん', 'd'), + 'nf' : ('ん', 'f'), + 'ng' : ('ん', 'g'), + 'nh' : ('ん', 'h'), + 'nj' : ('ん', 'j'), + 'nk' : ('ん', 'k'), + 'nl' : ('ん', 'l'), + 'nm' : ('ん', 'm'), + 'np' : ('ん', 'p'), + 'nr' : ('ん', 'r'), + 'ns' : ('ん', 's'), + 'nt' : ('ん', 't'), + 'nv' : ('ん', 'v'), + 'nw' : ('ん', 'w'), + 'nx' : ('ん', 'x'), + 'nz' : ('ん', 'z'), + 'n\0' : ('ん', ''), + 'n,' : ('ん', ','), + 'n.' : ('ん', '.'), +} + +# EUC-JP and SJIS do not have the chars +romaji_utf8_rule = { + 'う゛' : ['ゔ'], +} + +# Hiragana normalization is needed for the personal dict. +romaji_normalize_rule = { + 'ヴ' : ['う゛'], +} + +# a port of 101kana.sty from scim-anthy +kana_typing_rule_static = { + # no modifiers keys + '1' : 'ぬ', + '2' : 'ふ', + '3' : 'あ', + '4' : 'う', + '5' : 'え', + '6' : 'お', + '7' : 'や', + '8' : 'ゆ', + '9' : 'よ', + '0' : 'わ', + '-' : 'ほ', + '^' : 'へ', + + 'q' : 'た', + 'w' : 'て', + 'e' : 'い', + 'r' : 'す', + 't' : 'か', + 'y' : 'ん', + 'u' : 'な', + 'i' : 'に', + 'o' : 'ら', + 'p' : 'せ', + '@' : '゛', + '[' : '゜', + + 'a' : 'ち', + 's' : 'と', + 'd' : 'し', + 'f' : 'は', + 'g' : 'き', + 'h' : 'く', + 'j' : 'ま', + 'k' : 'の', + 'l' : 'り', + ';' : 'れ', + ':' : 'け', + ']' : 'む', + + 'z' : 'つ', + 'x' : 'さ', + 'c' : 'そ', + 'v' : 'ひ', + 'b' : 'こ', + 'n' : 'み', + 'm' : 'も', + ',' : 'ね', + '.' : 'る', + '/' : 'め', + # u'\\' : u'ー', + '\\' : 'ろ', + + # shift modifiered keys + '!' : 'ぬ', + '"' : 'ふ', + '#' : 'ぁ', + '$' : 'ぅ', + '%' : 'ぇ', + '&' : 'ぉ', + '\'' : 'ゃ', + '(' : 'ゅ', + ')' : 'ょ', + '~' : 'を', + '=' : 'ほ', + '|' : 'ー', + + 'Q' : 'た', + 'W' : 'て', + 'E' : 'ぃ', + 'R' : 'す', + 'T' : 'ヵ', + 'Y' : 'ん', + 'U' : 'な', + 'I' : 'に', + 'O' : 'ら', + 'P' : 'せ', + '`' : '゛', + + '{' : '「', + + 'A' : 'ち', + 'S' : 'と', + 'D' : 'し', + 'F' : 'ゎ', + 'G' : 'き', + 'H' : 'く', + 'J' : 'ま', + 'K' : 'の', + 'L' : 'り', + '+' : 'れ', + '*' : 'ヶ', + + '}' : '」', + + 'Z' : 'っ', + 'X' : 'さ', + 'C' : 'そ', + 'V' : 'ゐ', + 'B' : 'こ', + 'M' : 'も', + 'N' : 'み', + '<' : '、', + '>' : '。', + + '?' : '・', + '_' : 'ろ', + + '¥' : 'ー', +} + +kana_voiced_consonant_no_rule = { + 'か' : 'が', + 'き' : 'ぎ', + 'く' : 'ぐ', + 'け' : 'げ', + 'こ' : 'ご', + 'さ' : 'ざ', + 'し' : 'じ', + 'す' : 'ず', + 'せ' : 'ぜ', + 'そ' : 'ぞ', + 'た' : 'だ', + 'ち' : 'ぢ', + 'つ' : 'づ', + 'て' : 'で', + 'と' : 'ど', + 'は' : 'ば', + 'ひ' : 'び', + 'ふ' : 'ぶ', + 'へ' : 'べ', + 'ほ' : 'ぼ', +} + +kana_semi_voiced_consonant_no_rule = { + 'は' : 'ぱ', + 'ひ' : 'ぴ', + 'ふ' : 'ぷ', + 'へ' : 'ぺ', + 'ほ' : 'ぽ', +} + +# Create the table dynamically with kana_voiced_consonant_no_rule +# +#kana_voiced_consonant_rule = { +# u'か@' : u'が', +# u'き@' : u'ぎ', +# u'く@' : u'ぐ', +# u'け@' : u'げ', +# u'こ@' : u'ご', +# u'さ@' : u'ざ', +# u'し@' : u'じ', +# u'す@' : u'ず', +# u'せ@' : u'ぜ', +# u'そ@' : u'ぞ', +# u'た@' : u'だ', +# u'ち@' : u'ぢ', +# u'つ@' : u'づ', +# u'て@' : u'で', +# u'と@' : u'ど', +# u'は@' : u'ば', +# u'ひ@' : u'び', +# u'ふ@' : u'ぶ', +# u'へ@' : u'べ', +# u'ほ@' : u'ぼ', +# u'か`' : u'が', +# u'き`' : u'ぎ', +# u'く`' : u'ぐ', +# u'け`' : u'げ', +# u'こ`' : u'ご', +# u'さ`' : u'ざ', +# u'し`' : u'じ', +# u'す`' : u'ず', +# u'せ`' : u'ぜ', +# u'そ`' : u'ぞ', +# u'た`' : u'だ', +# u'ち`' : u'ぢ', +# u'つ`' : u'づ', +# u'て`' : u'で', +# u'と`' : u'ど', +# u'は`' : u'ば', +# u'ひ`' : u'び', +# u'ふ`' : u'ぶ', +# u'へ`' : u'べ', +# u'ほ`' : u'ぼ', +# u'は[' : u'ぱ', +# u'ひ[' : u'ぴ', +# u'ふ[' : u'ぷ', +# u'へ[' : u'ぺ', +# u'ほ[' : u'ぽ', +#} +# +#kana_voiced_consonant_us_rule = { +# u'か[' : u'が', +# u'き[' : u'ぎ', +# u'く[' : u'ぐ', +# u'け[' : u'げ', +# u'こ[' : u'ご', +# u'さ[' : u'ざ', +# u'し[' : u'じ', +# u'す[' : u'ず', +# u'せ[' : u'ぜ', +# u'そ[' : u'ぞ', +# u'た[' : u'だ', +# u'ち[' : u'ぢ', +# u'つ[' : u'づ', +# u'て[' : u'で', +# u'と[' : u'ど', +# u'は[' : u'ば', +# u'ひ[' : u'び', +# u'ふ[' : u'ぶ', +# u'へ[' : u'べ', +# u'ほ[' : u'ぼ', +# u'は]' : u'ぱ', +# u'ひ]' : u'ぴ', +# u'ふ]' : u'ぷ', +# u'へ]' : u'ぺ', +# u'ほ]' : u'ぽ', +#} + +#hiragana, katakana, half_katakana +hiragana_katakana_table = { + 'あ' : ('ア', 'ア'), + 'い' : ('イ', 'イ'), + 'う' : ('ウ', 'ウ'), + 'え' : ('エ', 'エ'), + 'お' : ('オ', 'オ'), + 'か' : ('カ', 'カ'), + 'き' : ('キ', 'キ'), + 'く' : ('ク', 'ク'), + 'け' : ('ケ', 'ケ'), + 'こ' : ('コ', 'コ'), + 'が' : ('ガ', 'ガ'), + 'ぎ' : ('ギ', 'ギ'), + 'ぐ' : ('グ', 'グ'), + 'げ' : ('ゲ', 'ゲ'), + 'ご' : ('ゴ', 'ゴ'), + 'さ' : ('サ', 'サ'), + 'し' : ('シ', 'シ'), + 'す' : ('ス', 'ス'), + 'せ' : ('セ', 'セ'), + 'そ' : ('ソ', 'ソ'), + 'ざ' : ('ザ', 'ザ'), + 'じ' : ('ジ', 'ジ'), + 'ず' : ('ズ', 'ズ'), + 'ぜ' : ('ゼ', 'ゼ'), + 'ぞ' : ('ゾ', 'ゾ'), + 'た' : ('タ', 'タ'), + 'ち' : ('チ', 'チ'), + 'つ' : ('ツ', 'ツ'), + 'て' : ('テ', 'テ'), + 'と' : ('ト', 'ト'), + 'だ' : ('ダ', 'ダ'), + 'ぢ' : ('ヂ', 'ヂ'), + 'づ' : ('ヅ', 'ヅ'), + 'で' : ('デ', 'デ'), + 'ど' : ('ド', 'ド'), + 'な' : ('ナ', 'ナ'), + 'に' : ('ニ', 'ニ'), + 'ぬ' : ('ヌ', 'ヌ'), + 'ね' : ('ネ', 'ネ'), + 'の' : ('ノ', 'ノ'), + 'は' : ('ハ', 'ハ'), + 'ひ' : ('ヒ', 'ヒ'), + 'ふ' : ('フ', 'フ'), + 'へ' : ('ヘ', 'ヘ'), + 'ほ' : ('ホ', 'ホ'), + 'ば' : ('バ', 'バ'), + 'び' : ('ビ', 'ビ'), + 'ぶ' : ('ブ', 'ブ'), + 'べ' : ('ベ', 'ベ'), + 'ぼ' : ('ボ', 'ボ'), + 'ぱ' : ('パ', 'パ'), + 'ぴ' : ('ピ', 'ピ'), + 'ぷ' : ('プ', 'プ'), + 'ぺ' : ('ペ', 'ペ'), + 'ぽ' : ('ポ', 'ポ'), + 'ま' : ('マ', 'マ'), + 'み' : ('ミ', 'ミ'), + 'む' : ('ム', 'ム'), + 'め' : ('メ', 'メ'), + 'も' : ('モ', 'モ'), + 'や' : ('ヤ', 'ヤ'), + 'ゆ' : ('ユ', 'ユ'), + 'よ' : ('ヨ', 'ヨ'), + 'ら' : ('ラ', 'ラ'), + 'り' : ('リ', 'リ'), + 'る' : ('ル', 'ル'), + 'れ' : ('レ', 'レ'), + 'ろ' : ('ロ', 'ロ'), + 'わ' : ('ワ', 'ワ'), + 'を' : ('ヲ', 'ヲ'), + 'ん' : ('ン', 'ン'), + 'ぁ' : ('ァ', 'ァ'), + 'ぃ' : ('ィ', 'ィ'), + 'ぅ' : ('ゥ', 'ゥ'), + 'ぇ' : ('ェ', 'ェ'), + 'ぉ' : ('ォ', 'ォ'), + 'っ' : ('ッ', 'ッ'), + 'ゃ' : ('ャ', 'ャ'), + 'ゅ' : ('ュ', 'ュ'), + 'ょ' : ('ョ', 'ョ'), + 'ヵ' : ('ヵ', 'カ'), + 'ヶ' : ('ヶ', 'ケ'), + 'ゎ' : ('ヮ', 'ワ'), + 'ゐ' : ('ヰ', 'ィ'), + 'ゑ' : ('ヱ', 'ェ'), + 'ヴ' : ('ヴ', 'ヴ'), + + # symbols + 'ー' : ('ー', 'ー'), + '、' : ('、', '、'), + '。' : ('。', '。'), + '!' : ('!', '!'), + '\u201d' : ('\u201d', '"'), + '#' : ('#', '#'), + '$' : ('$', '$'), + '%' : ('%', '%'), + '&' : ('&', '&'), + '\u2019' : ('\u2019', '\''), + '(' : ('(', '('), + ')' : (')', ')'), + '\uff5e' : ('\uff5e', '~'), + '=' : ('=', '='), + '^' : ('^', '^'), + '\' : ('\', '\\'), + '|' : ('|', '|'), + '\u2018' : ('\u2018', '`'), + '@' : ('@', '@'), + '゛' : ('゛', '゙'), + '{' : ('{', '{'), + '゜' : ('゜', '゚'), + '「' : ('「', '「'), + '+' : ('+', '+'), + ';' : (';', ';'), + '*' : ('*', '*'), + ':' : (':', ':'), + '}' : ('}', '}'), + '」' : ('」', '」'), + '<' : ('<', '<'), + '>' : ('>', '>'), + '?' : ('?', '?'), + '・' : ('・', '・'), + '/' : ('/', '/'), + '_' : ('_', '_'), + '¥' : ('¥', '¥'), + + # numbers + '0': ('0', '0'), + '1': ('1', '1'), + '2': ('2', '2'), + '3': ('3', '3'), + '4': ('4', '4'), + '5': ('5', '5'), + '6': ('6', '6'), + '7': ('7', '7'), + '8': ('8', '8'), + '9': ('9', '9'), +} diff --git a/engine/python3/test.py b/engine/python3/test.py new file mode 100644 index 0000000..cd67997 --- /dev/null +++ b/engine/python3/test.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +import anthy +import sys + +ctx = anthy.anthy_context () +ctx._set_encoding (2) +if len(sys.argv) >= 2: + ctx.set_string (sys.argv[1]) +else: + ctx.set_string ("かまぁく") +conv_stat = anthy.anthy_conv_stat () +seg_stat = anthy.anthy_segment_stat () +ctx.get_stat (conv_stat) +for i in range (0, conv_stat.nr_segment): + ctx.get_segment_stat (i, seg_stat) + buf = " " + i = ctx.get_segment (i, 0, buf, 10) + print buf[:i] +# anthy.anthy_release_context (ctx) +ctx = None diff --git a/engine/python3/thumb.py b/engine/python3/thumb.py new file mode 100644 index 0000000..93a3967 --- /dev/null +++ b/engine/python3/thumb.py @@ -0,0 +1,657 @@ +# -*- coding: utf-8 -*- +# vim:set et sts=4 sw=4: +# +# ibus-anthy - The Anthy engine for IBus +# +# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com> +# Copyright (c) 2009 Hideaki ABE <abe.sendai@gmail.com> +# Copyright (c) 2010-2014 Takao Fujiwara <takao.fujiwara1@gmail.com> +# Copyright (c) 2007-2014 Red Hat, Inc. +# +# 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 of the License, 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +__all__ = ( + 'ThumbShiftKeyboard', + 'ThumbShiftSegment', + ) + +from gi.repository import GLib +from gi.repository import IBus + +import segment + +_THUMB_BASIC_METHOD = 'base' + +_table_static = { + 'q': ['。', '', 'ぁ'], + 'w': ['か', 'が', 'え'], + 'e': ['た', 'だ', 'り'], + 'r': ['こ', 'ご', 'ゃ'], + 't': ['さ', 'ざ', 'れ'], + + 'y': ['ら', 'よ', 'ぱ'], + 'u': ['ち', 'に', 'ぢ'], + 'i': ['く', 'る', 'ぐ'], + 'o': ['つ', 'ま', 'づ'], + 'p': [',', 'ぇ', 'ぴ'], + '@': ['、', '', ''], + '[': ['゛', '゜', ''], + + 'a': ['う', '', 'を'], + 's': ['し', 'じ', 'あ'], + 'd': ['て', 'で', 'な'], + 'f': ['け', 'げ', 'ゅ'], + 'g': ['せ', 'ぜ', 'も'], + + 'h': ['は', 'み', 'ば'], + 'j': ['と', 'お', 'ど'], + 'k': ['き', 'の', 'ぎ'], + 'l': ['い', 'ょ', 'ぽ'], + ';': ['ん', 'っ', ''], + + 'z': ['.', '', 'ぅ'], + 'x': ['ひ', 'び', 'ー'], + 'c': ['す', 'ず', 'ろ'], + 'v': ['ふ', 'ぶ', 'や'], + 'b': ['へ', 'べ', 'ぃ'], + + 'n': ['め', 'ぬ', 'ぷ'], + 'm': ['そ', 'ゆ', 'ぞ'], + ',': ['ね', 'む', 'ぺ'], + '.': ['ほ', 'わ', 'ぼ'], + '/': ['・', 'ぉ', ''], + + '1': ['1', '', '?'], + '2': ['2', '', '/'], + '4': ['4', '', '「'], + '5': ['5', '', '」'], + + '6': ['6', '[', ''], + '7': ['7', ']', ''], + '8': ['8', '(', ''], + '9': ['9', ')', ''], + '\\': ['¥', '', ''], +} + +_nicola_j_table_static = { + ':': [':', '', ''], + '@': ['、', '', ''], + '[': ['゛', '゜', ''], + ']': ['」', '', ''], + '8': ['8', '(', ''], + '9': ['9', ')', ''], + '0': ['0', '', ''], +} + +_nicola_a_table_static = { + ':': [':', '', ''], + '@': ['@', '', ''], + '[': ['、', '', ''], + ']': ['゛', '゜', ''], + '8': ['8', '', ''], + '9': ['9', '(', ''], + '0': ['0', ')', ''], +} + +_nicola_f_table_static = { + ':': ['、', '', ''], + '@': ['@', '', ''], + '[': ['゛', '゜', ''], + ']': ['」', '', ''], + '8': ['8', '(', ''], + '9': ['9', ')', ''], + '0': ['0', '', ''], +} + +_kb231_j_fmv_table_static = { + '3': ['3', '', '~'], + '0': ['0', '『', ''], + '-': ['-', '』', ''], + '=': ['=', '', ''], +} + +_kb231_a_fmv_table_static = { + '3': ['3', '', '~'], + '0': ['0', ')', ''], + '-': ['-', '『', ''], + '=': ['=', '』', ''], +} + +_kb231_f_fmv_table_static = { + '3': ['3', '', '~'], + '0': ['0', '『', ''], + '-': ['-', '』', ''], + '=': ['=', '', ''], +} + +_kb611_j_fmv_table_static = { + '`': ['‘', '', ''], + '^': ['々', '£', ''], + ':': [':', '', ''], + '@': ['、', '¢', ''], + '[': ['゛', '゜', ''], + # keysyms are same and keycodes depend on the platforms. + #'¥': [u'¥', u'¬', u''], + '\\': ['¥', '¦', ''], +} + +_kb611_a_fmv_table_static = { + '`': ['々', '', '£'], + ':': [':', '', ''], + '@': ['@', '', ''], + '[': ['、', '¢', ''], + #'¥': [u'¥', u'¬', u''], + '\\': ['¥', '¦', ''], +} + +_kb611_f_fmv_table_static = { + '`': ['‘', '', ''], + '^': ['々', '£', ''], + ':': ['、', '¢', ''], + '@': ['@', '', ''], + '[': ['゛', '゜', ''], + #'¥': [u'¥', u'¬', u''], + '\\': ['¥', '¦', ''], +} + +_shift_table = { + 'H': 'ぱ', + 'X': 'ぴ', + 'V': 'ぷ', + 'B': 'ぺ', + '>': 'ぽ', +} + +table_static = {} +r_table_static = {} + +for k in list(_table_static.keys()): + table_static[ord(k)] = _table_static[k] + for c in _table_static[k]: + r_table_static[c] = k + +kana_voiced_consonant_rule = { + 'か゛' : 'が', + 'き゛' : 'ぎ', + 'く゛' : 'ぐ', + 'け゛' : 'げ', + 'こ゛' : 'ご', + 'さ゛' : 'ざ', + 'し゛' : 'じ', + 'す゛' : 'ず', + 'せ゛' : 'ぜ', + 'そ゛' : 'ぞ', + 'た゛' : 'だ', + 'ち゛' : 'ぢ', + 'つ゛' : 'づ', + 'て゛' : 'で', + 'と゛' : 'ど', + 'は゛' : 'ば', + 'ひ゛' : 'び', + 'ふ゛' : 'ぶ', + 'へ゛' : 'べ', + 'ほ゛' : 'ぼ', + 'は゜' : 'ぱ', + 'ひ゜' : 'ぴ', + 'ふ゜' : 'ぷ', + 'へ゜' : 'ぺ', + 'ほ゜' : 'ぽ', +} + +_UNFINISHED_HIRAGANA = set('かきくけこさしすせそたちつてとはひふへほ') + +class ThumbShiftKeyboard: + def __init__(self, prefs=None): + self.__prefs = prefs + self.__table = table_static + self.__r_table = r_table_static + self.__shift_table = {} + self.__ls = 0 + self.__rs = 0 + self.__t1 = 0 + self.__t2 = 0 + self.__layout = 0 + self.__fmv_extension = 2 + self.__handakuten = False + self.__thumb_typing_rule_section_base = None + self.__thumb_typing_rule_section = None + self.__init_thumb_typing_rule() + self.__init_layout_table() + if self.__prefs != None: + self.reset() + self.__reset_shift_table(False) + + def __init_thumb_typing_rule(self): + prefs = self.__prefs + if prefs == None: + self.__thumb_typing_rule_section = None + return + method = prefs.get_value('thumb_typing_rule', 'method') + if method == None: + method = _THUMB_BASIC_METHOD + self.__thumb_typing_rule_section_base = 'thumb_typing_rule' + self.__thumb_typing_rule_section = \ + self.__thumb_typing_rule_section_base + '/' + method + if self.__thumb_typing_rule_section not in prefs.sections(): + self.__thumb_typing_rule_section = None + + def __init_layout_table(self): + if self.__table != {}: + self.__table.clear() + if self.__r_table != {}: + self.__r_table.clear() + section_base = self.__thumb_typing_rule_section_base + section = self.__thumb_typing_rule_section + if section != None: + prefs = self.__prefs + for k in prefs.keys(section): + value = prefs.get_value(section, k) + ch = prefs.typing_from_config_key(k) + if ch == '': + continue + self.__set_bus_table(ch, value) + for k in prefs.get_value(section_base, 'newkeys'): + value = prefs.get_value_direct(section, k) + ch = prefs.typing_from_config_key(k) + if ch == '': + continue + self.__set_bus_table(ch, value) + else: + for k in list(_table.keys()): + self.__table[ord(k)] = _table_static[k] + for c in _table_static[k]: + self.__r_table[c] = k + + def __set_bus_table(self, key, value): + prefs = self.__prefs + if value == None or len(value) != 3: + return + if value[0] == '' and \ + value[1] == '' and value[2] == '': + return + self.__table[ord(key)] = value + for c in value: + self.__r_table[c] = key + + def __reset_layout_table(self, init, + j_table_label, j_table, + a_table_label, a_table, + f_table_label, f_table): + if init: + self.__init_layout_table() + method = None + sub_table = None + if self.__layout == 0: + method = j_table_label + sub_table = j_table + elif self.__layout == 1: + method = a_table_label + sub_table = a_table + elif self.__layout == 2: + method = f_table_label + sub_table = f_table + if method == None or sub_table == None: + return + section_base = self.__thumb_typing_rule_section_base + section = self.__thumb_typing_rule_section + sub_section = section_base + '/' + method + if section != None: + prefs = self.__prefs + for k in prefs.keys(sub_section): + value = prefs.get_value(sub_section, k) + ch = prefs.typing_from_config_key(k) + if ch == '': + continue + self.__set_bus_table(ch, value) + for k in prefs.get_value(section_base, method + '_newkeys'): + value = prefs.get_value_direct(sub_section, k) + ch = prefs.typing_from_config_key(k) + if ch == '': + continue + self.__set_bus_table(ch, value) + else: + for k in list(sub_table.keys()): + self.__table[ord(str(k))] = sub_table[k] + for c in sub_table[k]: + self.__r_table[c] = k + + def __reset_extension_table(self, init): + self.__reset_layout_table(init, + 'nicola_j_table', + _nicola_j_table_static, + 'nicola_a_table', + _nicola_a_table_static, + 'nicola_f_table', + _nicola_f_table_static) + if self.__fmv_extension == 0: + return + if self.__fmv_extension >= 1: + self.__reset_layout_table(False, + 'kb231_j_fmv_table', + _kb231_j_fmv_table_static, + 'kb231_a_fmv_table', + _kb231_a_fmv_table_static, + 'kb231_f_fmv_table', + _kb231_f_fmv_table_static) + if self.__fmv_extension >= 2: + self.__reset_layout_table(False, + 'kb611_j_fmv_table', + _kb611_j_fmv_table_static, + 'kb611_a_fmv_table', + _kb611_a_fmv_table_static, + 'kb611_f_fmv_table', + _kb611_f_fmv_table_static) + + def __reset_shift_table(self, init): + self.__reset_extension_table(init) + if self.__handakuten: + for k in list(_shift_table.keys()): + self.__shift_table[ord(k)] = _shift_table[k] + self.__r_table[_shift_table[k]] = k + elif self.__shift_table != {}: + for k in list(_shift_table.keys()): + if ord(k) in self.__shift_table: + del self.__shift_table[ord(k)] + if _shift_table[k] in self.__r_table: + del self.__r_table[_shift_table[k]] + + def __s_to_key_raw(self, s): + keyval = IBus.keyval_from_name(s.split('+')[-1]) + s = s.lower() + state = ('shift+' in s and IBus.ModifierType.SHIFT_MASK or 0) | ( + 'ctrl+' in s and IBus.ModifierType.CONTROL_MASK or 0) | ( + 'alt+' in s and IBus.ModifierType.MOD1_MASK or 0) + return (keyval, state) + + def __get_xkb_layout(self): + # Until Gdk.property_get is fixed + ''' + # Move importing Gdk into ThumbShiftKeyboard from the header + # because ibus-engine-anthy --xml does not requre to open X. + try: + from gi.repository import Gdk + get_default_root_window = Gdk.get_default_root_window + property_get = Gdk.property_get + intern = Gdk.Atom.intern + except ImportError: + get_default_root_window = lambda : None + property_get = lambda : None + intern = lambda : None + except RuntimeError: + # Do we support the engine without display? + print >> sys.stderr, "Gdk couldn't be initialized" + print >> sys.stderr, 'Could not open display' + get_default_root_window = lambda : None + property_get = lambda : None + intern = lambda : None + + root_window = get_default_root_window() + if not root_window: + return 0 + xkb_rules_names = intern('_XKB_RULES_NAMES', False) + xa_string = intern('STRING', False) + try: + prop = property_get(root_window, + xkb_rules_names, xa_string, + 0, 1024, 0)[3] + layout_list = prop.split('\0') + except TypeError: + import sys + print >> sys.stderr, \ + 'This problem is fixed in the latest gobject-introspection' + print >> sys.stderr, \ + 'https://bugzilla.gnome.org/show_bug.cgi?id=670509' + return 0 + layout = 0 + for data in layout_list: + if data == 'jp': + layout = 0 + elif data == 'us': + layout = 1 + elif data.find('japan:nicola_f_bs') >= 0: + layout = 2 + elif data.find('japan:') >= 0: + layout = 0 + return layout + ''' + + layout = 0 + argv = ['setxkbmap', '-query'] + (ret, std_out, std_error, exit_status) = \ + GLib.spawn_sync(None, argv, None, + GLib.SpawnFlags.SEARCH_PATH_FROM_ENVP, + None, None) + if not ret: + print(std_error, file=sys.stderr) + return layout + for line in std_out.split('\n'): + if line.startswith('layout:'): + data = line.split()[1] + if data == 'jp': + layout = 0 + elif data == 'us': + layout = 1 + elif line.startswith('options:'): + data = line.split()[1] + if data.find('japan:nicola_f_bs') >= 0: + layout = 2 + elif data.find('japan:') >= 0: + layout = 0 + return 0 + + def __reset_layout_and_handakuten(self): + mode = self.__prefs.get_value('thumb', 'keyboard_layout_mode') + layout = 0 + if mode == 1: + layout = self.__get_xkb_layout() + else: + layout = self.__prefs.get_value('thumb', 'keyboard_layout') + self.set_layout(layout) + + fmv_extension = self.__prefs.get_value('thumb', 'fmv_extension') + self.set_fmv_extension(fmv_extension) + handakuten = self.__prefs.get_value('thumb', 'handakuten') + self.set_handakuten(handakuten) + + def reset(self): + s = self.__prefs.get_value('thumb', 'ls') + ls, state = self.__s_to_key_raw(s) + if ls == 0xffffff: + ls = IBus.KEY_Muhenkan + self.set_ls(ls) + + s = self.__prefs.get_value('thumb', 'rs') + rs, state = self.__s_to_key_raw(s) + if rs == 0xffffff: + rs = IBus.KEY_Henkan + self.set_rs(rs) + + t1 = self.__prefs.get_value('thumb', 't1') + t2 = self.__prefs.get_value('thumb', 't2') + self.set_t1(t1) + self.set_t2(t2) + + GLib.idle_add(self.__reset_layout_and_handakuten, + priority = GLib.PRIORITY_LOW) + + def get_ls(self): + return self.__ls + + def set_ls(self, ls): + self.__ls = ls + + def get_rs(self): + return self.__rs + + def set_rs(self, rs): + self.__rs = rs + + def get_t1(self): + return self.__t1 + + def set_t1(self, t1): + self.__t1 = t1 + + def get_t2(self): + return self.__t2 + + def set_t2(self, t2): + self.__t2 = t2 + + def get_layout(self): + return self.__layout + + def set_layout(self, layout): + if self.__layout == layout: + return + self.__layout = layout + self.__reset_shift_table(True) + + def get_fmv_extension (self): + return self.__fmv_extension + + def set_fmv_extension (self, fmv_extension): + if self.__fmv_extension == fmv_extension: + return + self.__fmv_extension = fmv_extension + self.__reset_shift_table(True) + + def get_handakuten(self): + return self.__handakuten + + def set_handakuten(self, handakuten): + if self.__handakuten == handakuten: + return + self.__handakuten = handakuten + self.__reset_shift_table(True) + + def get_char(self, key, fallback=None): + return self.__table.get(key, fallback) + + def get_chars(self): + return list(self.__table.keys()) + + def get_r_char(self, key, fallback=None): + return self.__r_table.get(key, fallback) + + def get_r_chars(self): + return list(self.__r_table.keys()) + + def get_shift_char(self, key, fallback=None): + return self.__shift_table.get(key, fallback) + + def get_shift_chars(self): + return list(self.__shift_table.keys()) + + +class ThumbShiftSegment(segment.Segment): + _prefs = None + _thumb_typing_rule_section_base = None + _thumb_typing_rule_section = None + _r_table = {} + + def __init__(self, enchars='', jachars=''): + if not jachars: + if '!' <= enchars <= '~': + jachars = segment.unichar_half_to_full(enchars) + else: + jachars = enchars + enchars = self._r_table.get(jachars, '') + super(ThumbShiftSegment, self).__init__(enchars, jachars) + + @classmethod + def INIT_THUMB_TYPING_RULE(cls, prefs): + cls._prefs = prefs + if prefs == None: + cls._thumb_typing_rule_section = None + return + method = prefs.get_value('thumb_typing_rule', 'method') + if method == None: + method = _THUMB_BASIC_METHOD + cls._thumb_typing_rule_section_base = 'thumb_typing_rule' + cls._thumb_typing_rule_section = \ + cls._thumb_typing_rule_section_base + '/' + method + if cls._thumb_typing_rule_section not in prefs.sections(): + cls._thumb_typing_rule_section = None + cls._init_layout_table() + + @classmethod + def _init_layout_table(cls): + if cls._r_table != {}: + cls._r_table.clear() + section_base = cls._thumb_typing_rule_section_base + section = cls._thumb_typing_rule_section + if section != None: + prefs = cls._prefs + for k in prefs.keys(section): + value = prefs.get_value(section, k) + ch = prefs.typing_from_config_key(k) + if ch == '': + continue + cls._set_bus_table(ch, value) + for k in prefs.get_value(section_base, 'newkeys'): + value = prefs.get_value_direct(section, k) + ch = prefs.typing_from_config_key(k) + if ch == '': + continue + cls._set_bus_table(ch, value) + else: + for k in list(_table.keys()): + for c in _table_static[k]: + cls._r_table[c] = k + + @classmethod + def _set_bus_table(cls, key, value): + prefs = cls._prefs + if value == None or len(value) != 3: + return + if value[0] == '' and \ + value[1] == '' and value[2] == '': + return + for c in value: + cls._r_table[c] = key + + def is_finished(self): + return not (self._jachars in _UNFINISHED_HIRAGANA) + + def append(self, enchar): + if enchar == '\0' or enchar == '': + return [] + text = self._jachars + enchar + jachars = kana_voiced_consonant_rule.get(text, None) + if jachars: + self._enchars = self._enchars + self._r_table.get(enchar, '') + self._jachars = jachars + return [] + return [ThumbShiftSegment(enchar)] + + def prepend(self, enchar): + if enchar == '\0' or enchar == '': + return [] + if self._jachars == '': + if 0x21 <= enchars <= 0x7e: + self._enchars = enchar + self._jachars = segment.unichar_half_to_full(enchars) + else: + self._enchars = self._r_table.get(enchar, '') + self._jachars = enchar + return [] + return [ThumbShiftSegment(enchar)] + + def pop(self, index=-1): + self._enchars = '' + self._jachars = '' + return + diff --git a/setup/Makefile.am b/setup/Makefile.am index f1a8e8d..3c64425 100644 --- a/setup/Makefile.am +++ b/setup/Makefile.am @@ -2,10 +2,8 @@ # # ibus-anthy - The Anthy engine for IBus # -# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com> -# Copyright (c) 2009 Hideaki ABE <abe.sendai@gmail.com> -# Copyright (c) 2010-2013 Takao Fujiwara <takao.fujiwara1@gmail.com> -# Copyright (c) 2007-2013 Red Hat, Inc. +# Copyright (c) 2014 Takao Fujiwara <takao.fujiwara1@gmail.com> +# Copyright (c) 2014 Red Hat, Inc. # # 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 @@ -21,96 +19,12 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -desktop_in_in_files = ibus-setup-anthy.desktop.in.in -desktop_in_files = $(desktop_in_in_files:.in.in=.in) +SUBDIRS = -$(desktop_in_files): %.desktop.in: %.desktop.in.in Makefile - $(AM_V_GEN) sed \ - -e "s|\@libexecdir\@|$(libexecdir)|" \ - -e "s|\@pkgdatadir\@|$(pkgdatadir)|" \ - $< > $@.tmp && mv $@.tmp $@ - -desktopdir=$(datadir)/applications -desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) - -@INTLTOOL_DESKTOP_RULE@ - -BUILT_SOURCES = \ - _config.py \ - anthyprefs.py \ - $(NULL) - -libexec_SCRIPTS = ibus-setup-anthy - -setup_anthy_PYTHON = \ - _config.py \ - anthyprefs.py \ - main.py \ - prefs.py \ - setup.ui \ - $(NULL) - -setup_anthy_built_files = \ - $(BUILT_SOURCES) \ - $(libexec_SCRIPTS) \ - $(NULL) - -setup_anthy_built_in_files = $(addsuffix .in, $(setup_anthy_built_files)) - -setup_anthydir = $(datadir)/ibus-anthy/setup - -CONFIG_CLEAN_FILES = \ - $(BUILT_SOURCES) \ - $(libexec_SCRIPTS) \ - $(NULL) - -CLEANFILES = \ - $(BUILT_SOURCES) \ - $(desktop_DATA) \ - $(desktop_in_files) \ - *.pyc \ - $(NULL) - -EXTRA_DIST = \ - $(desktop_in_in_files) \ - $(setup_anthy_built_in_files) \ - $(NULL) - -anthyprefs.py: anthyprefs.py.in - sed -e "s|\@ANTHY_ZIPCODE_FILE\@|$(ANTHY_ZIPCODE_FILE)|g" \ - -e "s|\@KASUMI_EXEC_FILE\@|$(KASUMI_EXEC_FILE)|g" \ - -e "s|\@KASUMI_ICON_FILE\@|$(KASUMI_ICON_FILE)|g" \ - -e "s|\@ON_OFF_KEYS\@|$(ON_OFF_KEYS)|g" \ - -e "s|\@VERSION\@|$(VERSION)|g" \ - -e "s|\@pkgdatadir\@|$(pkgdatadir)|g" \ - $< > $@ - -_config.py: _config.py.in - ( \ - PKGDATADIR=$(pkgdatadir); \ - LIBEXECDIR=$(libexecdir); \ - DATADIR=$(datadir); \ - LAYOUT=$(LAYOUT); \ - SYMBOL_CHAR_INT=$(SYMBOL_CHAR_INT); \ - ICON_PREFERENCE=$(ICON_PREFERENCE); \ - s=`cat $<`; \ - eval "echo \"$${s}\""; \ - ) > $@ - -# Need a time lag between .py and .py.in files to build .py files -# because *_PYTHON valuables are installed in the tarball. -dist-hook: - @sleep 1; \ - for in_file in $(setup_anthy_built_in_files) ; do \ - if [ -f $(distdir)/$(srcdir)/$$in_file ] ; then \ - touch $(distdir)/$(srcdir)/$$in_file; \ - fi; \ - done; - -test: - $(ENV_IBUS_TEST) DBUS_DEBUG=true \ - LANG=en_US \ - PYTHONPATH=$(abs_top_srcdir):$(pyexecdir) \ - IBUS_LOCALEDIR=@localedir@ \ - $(PYTHON) $(srcdir)/main.py +if ENABLE_PYTHON2 +SUBDIRS += python2 +endif +if ENABLE_PYTHON3 +SUBDIRS += python3 +endif diff --git a/setup/_config.py.in b/setup/_config.py.in deleted file mode 120000 index d646d61..0000000 --- a/setup/_config.py.in +++ /dev/null @@ -1 +0,0 @@ -../engine/_config.py.in
\ No newline at end of file diff --git a/setup/python2/Makefile.am b/setup/python2/Makefile.am new file mode 100644 index 0000000..f1a8e8d --- /dev/null +++ b/setup/python2/Makefile.am @@ -0,0 +1,116 @@ +# vim:set noet ts=4: +# +# ibus-anthy - The Anthy engine for IBus +# +# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com> +# Copyright (c) 2009 Hideaki ABE <abe.sendai@gmail.com> +# Copyright (c) 2010-2013 Takao Fujiwara <takao.fujiwara1@gmail.com> +# Copyright (c) 2007-2013 Red Hat, Inc. +# +# 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 of the License, 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +desktop_in_in_files = ibus-setup-anthy.desktop.in.in +desktop_in_files = $(desktop_in_in_files:.in.in=.in) + +$(desktop_in_files): %.desktop.in: %.desktop.in.in Makefile + $(AM_V_GEN) sed \ + -e "s|\@libexecdir\@|$(libexecdir)|" \ + -e "s|\@pkgdatadir\@|$(pkgdatadir)|" \ + $< > $@.tmp && mv $@.tmp $@ + +desktopdir=$(datadir)/applications +desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) + +@INTLTOOL_DESKTOP_RULE@ + +BUILT_SOURCES = \ + _config.py \ + anthyprefs.py \ + $(NULL) + +libexec_SCRIPTS = ibus-setup-anthy + +setup_anthy_PYTHON = \ + _config.py \ + anthyprefs.py \ + main.py \ + prefs.py \ + setup.ui \ + $(NULL) + +setup_anthy_built_files = \ + $(BUILT_SOURCES) \ + $(libexec_SCRIPTS) \ + $(NULL) + +setup_anthy_built_in_files = $(addsuffix .in, $(setup_anthy_built_files)) + +setup_anthydir = $(datadir)/ibus-anthy/setup + +CONFIG_CLEAN_FILES = \ + $(BUILT_SOURCES) \ + $(libexec_SCRIPTS) \ + $(NULL) + +CLEANFILES = \ + $(BUILT_SOURCES) \ + $(desktop_DATA) \ + $(desktop_in_files) \ + *.pyc \ + $(NULL) + +EXTRA_DIST = \ + $(desktop_in_in_files) \ + $(setup_anthy_built_in_files) \ + $(NULL) + +anthyprefs.py: anthyprefs.py.in + sed -e "s|\@ANTHY_ZIPCODE_FILE\@|$(ANTHY_ZIPCODE_FILE)|g" \ + -e "s|\@KASUMI_EXEC_FILE\@|$(KASUMI_EXEC_FILE)|g" \ + -e "s|\@KASUMI_ICON_FILE\@|$(KASUMI_ICON_FILE)|g" \ + -e "s|\@ON_OFF_KEYS\@|$(ON_OFF_KEYS)|g" \ + -e "s|\@VERSION\@|$(VERSION)|g" \ + -e "s|\@pkgdatadir\@|$(pkgdatadir)|g" \ + $< > $@ + +_config.py: _config.py.in + ( \ + PKGDATADIR=$(pkgdatadir); \ + LIBEXECDIR=$(libexecdir); \ + DATADIR=$(datadir); \ + LAYOUT=$(LAYOUT); \ + SYMBOL_CHAR_INT=$(SYMBOL_CHAR_INT); \ + ICON_PREFERENCE=$(ICON_PREFERENCE); \ + s=`cat $<`; \ + eval "echo \"$${s}\""; \ + ) > $@ + +# Need a time lag between .py and .py.in files to build .py files +# because *_PYTHON valuables are installed in the tarball. +dist-hook: + @sleep 1; \ + for in_file in $(setup_anthy_built_in_files) ; do \ + if [ -f $(distdir)/$(srcdir)/$$in_file ] ; then \ + touch $(distdir)/$(srcdir)/$$in_file; \ + fi; \ + done; + +test: + $(ENV_IBUS_TEST) DBUS_DEBUG=true \ + LANG=en_US \ + PYTHONPATH=$(abs_top_srcdir):$(pyexecdir) \ + IBUS_LOCALEDIR=@localedir@ \ + $(PYTHON) $(srcdir)/main.py + diff --git a/setup/python2/_config.py.in b/setup/python2/_config.py.in new file mode 120000 index 0000000..a064604 --- /dev/null +++ b/setup/python2/_config.py.in @@ -0,0 +1 @@ +../../engine/python2/_config.py.in
\ No newline at end of file diff --git a/setup/anthyprefs.py.in b/setup/python2/anthyprefs.py.in index a685da1..a685da1 100644 --- a/setup/anthyprefs.py.in +++ b/setup/python2/anthyprefs.py.in diff --git a/setup/ibus-setup-anthy.desktop.in.in b/setup/python2/ibus-setup-anthy.desktop.in.in index 1dd35f9..1dd35f9 100644 --- a/setup/ibus-setup-anthy.desktop.in.in +++ b/setup/python2/ibus-setup-anthy.desktop.in.in diff --git a/setup/ibus-setup-anthy.in b/setup/python2/ibus-setup-anthy.in index f8832fd..f8832fd 100644 --- a/setup/ibus-setup-anthy.in +++ b/setup/python2/ibus-setup-anthy.in diff --git a/setup/main.py b/setup/python2/main.py index 98486ad..98486ad 100644 --- a/setup/main.py +++ b/setup/python2/main.py diff --git a/setup/prefs.py b/setup/python2/prefs.py index 1b88908..1b88908 100644 --- a/setup/prefs.py +++ b/setup/python2/prefs.py diff --git a/setup/setup.ui b/setup/python2/setup.ui index d9ec626..d9ec626 100644 --- a/setup/setup.ui +++ b/setup/python2/setup.ui diff --git a/setup/python3/Makefile.am b/setup/python3/Makefile.am new file mode 100644 index 0000000..f1a8e8d --- /dev/null +++ b/setup/python3/Makefile.am @@ -0,0 +1,116 @@ +# vim:set noet ts=4: +# +# ibus-anthy - The Anthy engine for IBus +# +# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com> +# Copyright (c) 2009 Hideaki ABE <abe.sendai@gmail.com> +# Copyright (c) 2010-2013 Takao Fujiwara <takao.fujiwara1@gmail.com> +# Copyright (c) 2007-2013 Red Hat, Inc. +# +# 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 of the License, 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +desktop_in_in_files = ibus-setup-anthy.desktop.in.in +desktop_in_files = $(desktop_in_in_files:.in.in=.in) + +$(desktop_in_files): %.desktop.in: %.desktop.in.in Makefile + $(AM_V_GEN) sed \ + -e "s|\@libexecdir\@|$(libexecdir)|" \ + -e "s|\@pkgdatadir\@|$(pkgdatadir)|" \ + $< > $@.tmp && mv $@.tmp $@ + +desktopdir=$(datadir)/applications +desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) + +@INTLTOOL_DESKTOP_RULE@ + +BUILT_SOURCES = \ + _config.py \ + anthyprefs.py \ + $(NULL) + +libexec_SCRIPTS = ibus-setup-anthy + +setup_anthy_PYTHON = \ + _config.py \ + anthyprefs.py \ + main.py \ + prefs.py \ + setup.ui \ + $(NULL) + +setup_anthy_built_files = \ + $(BUILT_SOURCES) \ + $(libexec_SCRIPTS) \ + $(NULL) + +setup_anthy_built_in_files = $(addsuffix .in, $(setup_anthy_built_files)) + +setup_anthydir = $(datadir)/ibus-anthy/setup + +CONFIG_CLEAN_FILES = \ + $(BUILT_SOURCES) \ + $(libexec_SCRIPTS) \ + $(NULL) + +CLEANFILES = \ + $(BUILT_SOURCES) \ + $(desktop_DATA) \ + $(desktop_in_files) \ + *.pyc \ + $(NULL) + +EXTRA_DIST = \ + $(desktop_in_in_files) \ + $(setup_anthy_built_in_files) \ + $(NULL) + +anthyprefs.py: anthyprefs.py.in + sed -e "s|\@ANTHY_ZIPCODE_FILE\@|$(ANTHY_ZIPCODE_FILE)|g" \ + -e "s|\@KASUMI_EXEC_FILE\@|$(KASUMI_EXEC_FILE)|g" \ + -e "s|\@KASUMI_ICON_FILE\@|$(KASUMI_ICON_FILE)|g" \ + -e "s|\@ON_OFF_KEYS\@|$(ON_OFF_KEYS)|g" \ + -e "s|\@VERSION\@|$(VERSION)|g" \ + -e "s|\@pkgdatadir\@|$(pkgdatadir)|g" \ + $< > $@ + +_config.py: _config.py.in + ( \ + PKGDATADIR=$(pkgdatadir); \ + LIBEXECDIR=$(libexecdir); \ + DATADIR=$(datadir); \ + LAYOUT=$(LAYOUT); \ + SYMBOL_CHAR_INT=$(SYMBOL_CHAR_INT); \ + ICON_PREFERENCE=$(ICON_PREFERENCE); \ + s=`cat $<`; \ + eval "echo \"$${s}\""; \ + ) > $@ + +# Need a time lag between .py and .py.in files to build .py files +# because *_PYTHON valuables are installed in the tarball. +dist-hook: + @sleep 1; \ + for in_file in $(setup_anthy_built_in_files) ; do \ + if [ -f $(distdir)/$(srcdir)/$$in_file ] ; then \ + touch $(distdir)/$(srcdir)/$$in_file; \ + fi; \ + done; + +test: + $(ENV_IBUS_TEST) DBUS_DEBUG=true \ + LANG=en_US \ + PYTHONPATH=$(abs_top_srcdir):$(pyexecdir) \ + IBUS_LOCALEDIR=@localedir@ \ + $(PYTHON) $(srcdir)/main.py + diff --git a/setup/python3/_config.py.in b/setup/python3/_config.py.in new file mode 120000 index 0000000..5f5764f --- /dev/null +++ b/setup/python3/_config.py.in @@ -0,0 +1 @@ +../../engine/python3/_config.py.in
\ No newline at end of file diff --git a/setup/python3/anthyprefs.py.in b/setup/python3/anthyprefs.py.in new file mode 100644 index 0000000..53c9d1d --- /dev/null +++ b/setup/python3/anthyprefs.py.in @@ -0,0 +1,1329 @@ +# -*- coding: utf-8 -*- +# vim:set noet ts=4: +# +# ibus-anthy - The Anthy engine for IBus +# +# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com> +# Copyright (c) 2009 Hideaki ABE <abe.sendai@gmail.com> +# Copyright (c) 2010-2014 Takao Fujiwara <takao.fujiwara1@gmail.com> +# Copyright (c) 2007-2014 Red Hat, Inc. +# +# 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 of the License, 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import sys + +from prefs import Prefs + +N_ = lambda a : a + +__all__ = ['AnthyPrefs'] + + +class AnthyPrefs(Prefs): + _prefix = 'engine/anthy' + _char_to_config_key = None + + def __init__(self, bus=None, config=None): + super(AnthyPrefs, self).__init__(bus, config) + if _config != None: + self.default = _config + self.set_no_key_warning(True) + self.fetch_all() + self.set_no_key_warning(False) + + def __update_key (self, section, old_key, new_key): + file = __file__ + if __file__.find('/') >= 0: + file = __file__[__file__.rindex('/') + 1:] + warning_message = \ + '(' + file + ') ibus-anthy-WARNING **: ' \ + 'The key (' + old_key + ') will be removed in the future. ' \ + 'Currently the key (' + new_key + ') is used instead. ' \ + 'The ibus keys are defined in ' + \ + '/'.join(['/desktop/ibus', self._prefix, section]) + ' .' + + if not self.fetch_item(section, old_key, True): + return + print(warning_message, file=sys.stderr) + if self.fetch_item(section, new_key, True): + return + + self.fetch_item(section, old_key) + value = self.get_value(section, old_key) + self.set_value(section, new_key, value) + self.commit_item(section, new_key) + self.undo_item(section, new_key) + + def keys(self, section): + if section.startswith('shortcut/'): + return _cmd_keys + return list(self.default[section].keys()) + + def get_japanese_ordered_list(self): + return _japanese_ordered_list + + def get_version(self): + return '@VERSION@' + + # Convert typing sequences to gsettings key. + # E.g. 'largea-bracketleft' to 'A[' + def typing_from_config_key(self, gkeys): + retval = '' + for key in gkeys.split('-'): + if key in _supported_gsettings_key_chars: + retval += key + continue + try: + ch = _config_key_to_char[key] + except KeyError: + print('Not supported key in gsettings', gkeys, file=sys.stderr) + retval = '' + break + retval += ch + return retval + + # Convert typing sequences to gsettings key. + # E.g. 'A[' to 'largea-bracketleft' + def typing_to_config_key(self, typing): + retval = '' + if self._char_to_config_key == None: + self._char_to_config_key = {} + for _key, _ch in list(_config_key_to_char.items()): + self._char_to_config_key[_ch] = _key + for ch in typing: + if ch in _supported_gsettings_key_chars: + if retval != '': + retval += '-' + retval += ch + continue + try: + key = self._char_to_config_key[ch] + except KeyError: + print('Not supported key in gsettings', typing, file=sys.stderr) + retval = '' + break + if retval != '': + retval += '-' + retval += key + return retval + +# Sad! dict.keys() doesn't return the saved order. +# locale.strcoll() also just returns the Unicode code point. +# Unicode order is wrong in Japanese large 'a' and small 'a'. +# The workaround is to save the order here... +_japanese_ordered_list = [ + 'あ', 'い', 'う', 'え', 'お', + 'ぁ', 'ぃ', 'ぅ', 'ぇ', 'ぉ', + 'いぇ', + 'うぁ', 'うぃ', 'うぅ', 'うぇ', 'うぉ', + 'うゃ', 'うゅ', 'うょ', + 'か', 'き', 'く', 'け', 'こ', + 'ゕ', 'ゖ', 'ヵ', 'ヶ', + 'が', 'ぎ', 'ぐ', 'げ', 'ご', + 'きゃ', 'きぃ', 'きゅ', 'きぇ', 'きょ', + 'くぁ', 'くぃ', 'くぅ', 'くぇ', 'くぉ', + 'ぎゃ', 'ぎぃ', 'ぎゅ', 'ぎぇ', 'ぎょ', + 'ぐぁ', 'ぐぃ', 'ぐぅ', 'ぐぇ', 'ぐぉ', + 'さ', 'し', 'す', 'せ', 'そ', + 'ざ', 'じ', 'ず', 'ぜ', 'ぞ', + 'しゃ', 'しぃ', 'しゅ', 'しぇ', 'しょ', + 'じゃ', 'じぃ', 'じゅ', 'じぇ', 'じょ', + 'すぅぃ', 'すぇ', + 'ずぇ', + 'た', 'ち', 'つ', 'て', 'と', + 'だ', 'ぢ', 'づ', 'で', 'ど', + 'っ', + 'ちゃ', 'ちぃ', 'ちゅ', 'ちぇ', 'ちょ', + 'ぢぃ', 'ぢぇ', + 'ぢゃ', 'ぢゅ', 'ぢょ', + 'つぁ', 'つぃ', 'つぇ', 'つぉ', + 'つゃ', 'つぃぇ', 'つゅ', 'つょ', + 'づぁ', 'づぃ', 'づぇ', 'づぉ', + 'づゃ', 'づぃぇ', 'づゅ', 'づょ', + 'てぃ', 'てぇ', + 'てゃ', 'てゅ', 'てょ', + 'とぅ', + 'でぃ', 'でぇ', + 'でゃ', 'でゅ', 'でょ', + 'どぅ', + 'な', 'に', 'ぬ', 'ね', 'の', + 'にぃ', 'にぇ', + 'にゃ', 'にゅ', 'にょ', + 'は', 'ひ', 'ふ', 'へ', 'ほ', + 'ば', 'び', 'ぶ', 'べ', 'ぼ', + 'ぱ', 'ぴ', 'ぷ', 'ぺ', 'ぽ', + 'ひぃ', 'ひぇ', + 'ひゃ', 'ひゅ', 'ひょ', + 'びぃ', 'びぇ', + 'びゃ', 'びゅ', 'びょ', + 'ぴぃ', 'ぴぇ', + 'ぴゃ', 'ぴゅ', 'ぴょ', + 'ふぁ', 'ふぃ', 'ふぇ', 'ふぉ', + 'ふゃ', 'ふゅ', 'ふょ', + 'ぶぁ', 'ぶぇ', 'ぶぉ', + 'ぷぁ', 'ぷぇ', 'ぷぉ', + 'ま', 'み', 'む', 'め', 'も', + 'みぃ', 'みぇ', + 'みゃ', 'みゅ', 'みょ', + 'や', 'ゆ', 'よ', + 'ゃ', 'ゅ', 'ょ', + 'ら', 'り', 'る', 'れ', 'ろ', + 'りぃ', 'りぇ', + 'りゃ', 'りゅ', 'りょ', + 'わ', 'を', 'ん', + 'ゎ', + 'ゐ', 'ゑ', + 'ー', + 'ヴぁ', 'ヴぃ', 'ヴ', 'ヴぇ', 'ヴぉ', + 'ヴゃ', 'ヴぃぇ', 'ヴゅ', 'ヴょ', +] + +# http://git.gnome.org/browse/glib/tree/gio/glib-compile-schemas.c#n765 +# gsettings supports keys named by "abcdefghijklmnopqrstuvwxyz0123456789-" +# and ibus-anthy uses '-' as the delimiter. +_supported_gsettings_key_chars = "abcdefghijklmnopqrstuvwxyz0123456789" + +_config_key_to_char = { + # no modifiers keys + 'minus' : '-', + 'asciicircum' : '^', + 'at' : '@', + 'bracketleft' : '[', + 'semicolon' : ';', + 'colon' : ':', + 'bracketright' : ']', + 'comma' : ',', + 'period' : '.', + 'slash' : '/', + 'backslash' : '\\', + + # shift modifiered keys + 'exclam' : '!', + 'quotedbl' : '"', + 'numbersign' : '#', + 'dollar' : '$', + 'percent' : '%', + 'ampersand' : '&', + 'apostrophe' : '\'', + 'parenleft' : '(', + 'parenright' : ')', + 'asciitilde' : '~', + 'equal' : '=', + 'bar' : '|', + + 'largeq' : 'Q', + 'largew' : 'W', + 'largee' : 'E', + 'larger' : 'R', + 'larget' : 'T', + 'largey' : 'Y', + 'largeu' : 'U', + 'largei' : 'I', + 'largeo' : 'O', + 'largep' : 'P', + 'grave' : '`', + + 'braceleft' : '{', + + 'largea' : 'A', + 'larges' : 'S', + 'larged' : 'D', + 'largef' : 'F', + 'largeg' : 'G', + 'largeh' : 'H', + 'largej' : 'J', + 'largek' : 'K', + 'largel' : 'L', + 'plus' : '+', + 'asterisk' : '*', + + 'braceright' : '}', + + 'largez' : 'Z', + 'largex' : 'X', + 'largec' : 'C', + 'largev' : 'V', + 'largeb' : 'B', + 'largen' : 'N', + 'largem' : 'M', + 'less' : '<', + 'greater' : '>', + + 'question' : '?', + 'underscore' : '_', + + 'yen' : '¥', +} + +_cmd_keys = [ + 'on_off', + 'circle_input_mode', + 'circle_kana_mode', + 'circle_typing_method', + 'circle_dict_method', + 'latin_mode', + 'wide_latin_mode', + 'hiragana_mode', + 'katakana_mode', + 'half_katakana_mode', +# 'cancel_pseudo_ascii_mode_key', + + 'hiragana_for_latin_with_shift', + + 'insert_space', + 'insert_alternate_space', + 'insert_half_space', + 'insert_wide_space', + 'backspace', + 'delete', + 'commit', + 'convert', + 'predict', + 'cancel', + 'cancel_all', + 'reconvert', +# 'do_nothing', + + 'select_first_candidate', + 'select_last_candidate', + 'select_next_candidate', + 'select_prev_candidate', + 'candidates_page_up', + 'candidates_page_down', + + 'move_caret_first', + 'move_caret_last', + 'move_caret_forward', + 'move_caret_backward', + + 'select_first_segment', + 'select_last_segment', + 'select_next_segment', + 'select_prev_segment', + 'shrink_segment', + 'expand_segment', + 'commit_first_segment', + 'commit_selected_segment', + + 'select_candidates_1', + 'select_candidates_2', + 'select_candidates_3', + 'select_candidates_4', + 'select_candidates_5', + 'select_candidates_6', + 'select_candidates_7', + 'select_candidates_8', + 'select_candidates_9', + 'select_candidates_0', + + 'convert_to_char_type_forward', + 'convert_to_char_type_backward', + 'convert_to_hiragana', + 'convert_to_katakana', + 'convert_to_half', + 'convert_to_half_katakana', + 'convert_to_wide_latin', + 'convert_to_latin', + + 'dict_admin', + 'add_word', + + 'start_setup', +] + +_config = { + 'common': { + 'input_mode': 0, + 'typing_method': 0, + 'conversion_segment_mode': 0, + + 'show-input-mode': True, + 'show-typing-method': False, + 'show-segment-mode': False, + 'show-dict-mode': True, + 'show-dict-config': False, + 'show-preferences': True, + + 'period_style': 0, + 'symbol_style': 1, + 'ten_key_mode': 1, + 'behavior_on_focus_out': 0, + 'behavior_on_period': 0, + + 'page_size': 10, + 'half_width_symbol': False, + 'half_width_number': False, + 'half_width_space': False, + 'latin_with_shift': True, + + 'shortcut_type': 'default', + + 'dict_admin_command': ['@KASUMI_EXEC_FILE@', 'kasumi'], + 'add_word_command': ['@KASUMI_EXEC_FILE@', 'kasumi', '-a'], + 'dict_config_icon': '@KASUMI_ICON_FILE@', + 'keyboard_layouts': [ + 'default', 'jp', 'us', + # XKB options requires ibus 1.5. + 'jp[ctrl:swapcaps]', 'us[ctrl:swapcaps]', + 'jp[ctrl:swapcaps,compose:rctrl]', + 'us[ctrl:swapcaps,compose:rctrl]', + 'jp[japan:kana_lock]', + 'jp[japan:nicola_f_bs]', + 'jp[japan:nicola_f_bs,ctrl:swapcaps]', + 'jp[japan:hztg_escape]', + 'jp[japan:hztg_escape,ctrl:swapcaps]', + ], + }, + + 'romaji_typing_rule': { + 'method': 'default', + # The newkeys list is saved for every romaji_typing_rule/$method + # so that prefs.get_value_direct() is not used. + # prefs.fetch_section() doesn't get the keys if they exist + # in gconf only. + 'newkeys': [], + }, + + ##0 MS-IME + # http://www.filibeto.org/sun/lib/solaris10-docs/E19253-01/819-7844/appe-1-4/index.html + ##1 ATOK + # http://www.filibeto.org/sun/lib/solaris10-docs/E19253-01/819-7844/appe-1-3/index.html + ##2 Gairaigo http://ja.wikipedia.org/wiki/%E5%A4%96%E6%9D%A5%E8%AA%9E + ##3 ANSI/BSI Suggestions http://en.wikipedia.org/wiki/Katakana + ##4 Historical kana http://en.wikipedia.org/wiki/Romanization_of_Japanese + # Maybe we need a compatibility between MS-IME and ibus-anthy. + 'romaji_typing_rule/default': { + 'minus' : 'ー', + 'a' : 'あ', + 'i' : 'い', + 'u' : 'う', + 'e' : 'え', + 'o' : 'お', + 'x-a' : 'ぁ', + 'x-i' : 'ぃ', + 'x-u' : 'ぅ', + 'x-e' : 'ぇ', + 'x-o' : 'ぉ', + 'l-a' : 'ぁ', + 'l-i' : 'ぃ', + 'l-u' : 'ぅ', + 'l-e' : 'ぇ', + 'l-o' : 'ぉ', + 'w-h-a' : 'うぁ', + 'w-h-i' : 'うぃ', + 'w-h-e' : 'うぇ', + 'w-h-o' : 'うぉ', + 'w-y-a' : 'うゃ', ##2 + 'w-y-u' : 'うゅ', ##2 + 'w-y-o' : 'うょ', ##2 + 'v-a' : 'ヴぁ', + 'v-i' : 'ヴぃ', + 'v-u' : 'ヴ', + 'v-e' : 'ヴぇ', + 'v-o' : 'ヴぉ', + 'v-y-a' : 'ヴゃ', ##2 + 'v-y-u' : 'ヴゅ', ##2 + 'v-y-e' : 'ヴぃぇ', ##2 + 'v-y-o' : 'ヴょ', ##2 + 'k-a' : 'か', + 'k-i' : 'き', + 'k-u' : 'く', + 'k-e' : 'け', + 'k-o' : 'こ', + 'l-k-a' : 'ヵ', + 'l-k-e' : 'ヶ', +# 'x-k-a' : 'ゕ', + 'x-k-a' : 'ヵ', +# 'x-k-e' : 'ゖ', + 'x-k-e' : 'ヶ', + 'g-a' : 'が', + 'g-i' : 'ぎ', + 'g-u' : 'ぐ', + 'g-e' : 'げ', + 'g-o' : 'ご', + 'k-y-a' : 'きゃ', + 'k-y-i' : 'きぃ', + 'k-y-u' : 'きゅ', + 'k-y-e' : 'きぇ', + 'k-y-o' : 'きょ', + 'k-w-a' : 'くぁ', + 'k-w-i' : 'くぃ', ##2 + 'k-w-u' : 'くぅ', ##2 + 'k-w-e' : 'くぇ', ##2 + 'k-w-o' : 'くぉ', ##2 + 'g-y-a' : 'ぎゃ', + 'g-y-i' : 'ぎぃ', + 'g-y-u' : 'ぎゅ', + 'g-y-e' : 'ぎぇ', + 'g-y-o' : 'ぎょ', + 'g-w-a' : 'ぐぁ', + 'g-w-i' : 'ぐぃ', ##2 + 'g-w-u' : 'ぐぅ', ##2 + 'g-w-e' : 'ぐぇ', ##2 + 'g-w-o' : 'ぐぉ', ##2 + 's-a' : 'さ', + 's-i' : 'し', + 's-u' : 'す', + 's-e' : 'せ', + 's-o' : 'そ', + 'z-a' : 'ざ', + 'z-i' : 'じ', + 'z-u' : 'ず', + 'z-e' : 'ぜ', + 'z-o' : 'ぞ', + 's-y-a' : 'しゃ', + 's-y-i' : 'しぃ', + 's-y-u' : 'しゅ', + 's-y-e' : 'しぇ', + 's-y-o' : 'しょ', + 's-h-a' : 'しゃ', + 's-h-i' : 'し', + 's-h-u' : 'しゅ', + 's-h-e' : 'しぇ', + 's-h-o' : 'しょ', + 'z-y-a' : 'じゃ', + 'z-y-i' : 'じぃ', + 'z-y-u' : 'じゅ', + 'z-y-e' : 'じぇ', + 'z-y-o' : 'じょ', + 'j-a' : 'じゃ', + 'j-y-a' : 'じゃ', + 'j-i' : 'じ', + 'j-y-i' : 'じぃ', + 'j-u' : 'じゅ', + 'j-y-u' : 'じゅ', + 'j-e' : 'じぇ', + 'j-y-e' : 'じぇ', + 'j-o' : 'じょ', + 'j-y-o' : 'じょ', + 's-w-i' : 'すぅぃ', ##2 + 's-w-e' : 'すぇ', ##2 + 'z-w-e' : 'ずぇ', ##2 + 't-a' : 'た', + 't-i' : 'ち', + 't-u' : 'つ', + 't-s-u' : 'つ', + 't-e' : 'て', + 't-o' : 'と', + 'd-a' : 'だ', + 'd-i' : 'ぢ', + 'd-u' : 'づ', + 'd-e' : 'で', + 'd-o' : 'ど', + 'x-t-u' : 'っ', + 'x-t-s-u' : 'っ', + 'l-t-u' : 'っ', + 'l-t-s-u' : 'っ', + 't-y-a' : 'ちゃ', + 't-y-i' : 'ちぃ', + 't-y-u' : 'ちゅ', + 't-y-e' : 'ちぇ', + 't-y-o' : 'ちょ', + 'c-y-a' : 'ちゃ', + 'c-y-i' : 'ちぃ', + 'c-y-u' : 'ちゅ', + 'c-y-e' : 'ちぇ', + 'c-y-o' : 'ちょ', + 'c-h-a' : 'ちゃ', + 'c-h-i' : 'ち', + 'c-h-u' : 'ちゅ', + 'c-h-e' : 'ちぇ', + 'c-h-o' : 'ちょ', + 'd-y-a' : 'ぢゃ', + 'd-y-i' : 'ぢぃ', + 'd-y-u' : 'ぢゅ', + 'd-y-e' : 'ぢぇ', + 'd-y-o' : 'ぢょ', + 't-s-a' : 'つぁ', + 't-s-i' : 'つぃ', + 't-s-e' : 'つぇ', + 't-s-o' : 'つぉ', + 't-s-y-a' : 'つゃ', ##3 + 't-s-y-u' : 'つゅ', ##3 + 't-s-y-e' : 'つぃぇ', ##3 + 't-s-y-o' : 'つょ', ##3 + 'd-z-a' : 'づぁ', ##3 + 'd-z-i' : 'づぃ', ##3 + 'd-z-u' : 'づ', ##4 + 'd-z-e' : 'づぇ', ##3 + 'd-z-o' : 'づぉ', ##3 + 'd-z-y-a' : 'づゃ', ##3 + 'd-z-y-u' : 'づゅ', ##3 + 'd-z-y-e' : 'づぃぇ', ##3 + 'd-z-y-o' : 'づょ', ##3 + 't-h-a' : 'てゃ', + 't-h-i' : 'てぃ', + 't-h-u' : 'てゅ', + 't-h-e' : 'てぇ', + 't-h-o' : 'てょ', + 't-w-u' : 'とぅ', + 'd-h-a' : 'でゃ', + 'd-h-i' : 'でぃ', + 'd-h-u' : 'でゅ', + 'd-h-e' : 'でぇ', + 'd-h-o' : 'でょ', + 'd-w-u' : 'どぅ', + 'n-a' : 'な', + 'n-i' : 'に', + 'n-u' : 'ぬ', + 'n-e' : 'ね', + 'n-o' : 'の', + 'n-y-a' : 'にゃ', + 'n-y-i' : 'にぃ', + 'n-y-u' : 'にゅ', + 'n-y-e' : 'にぇ', + 'n-y-o' : 'にょ', + 'h-a' : 'は', + 'h-i' : 'ひ', + 'h-u' : 'ふ', + 'h-e' : 'へ', + 'h-o' : 'ほ', + 'b-a' : 'ば', + 'b-i' : 'び', + 'b-u' : 'ぶ', + 'b-e' : 'べ', + 'b-o' : 'ぼ', + 'p-a' : 'ぱ', + 'p-i' : 'ぴ', + 'p-u' : 'ぷ', + 'p-e' : 'ぺ', + 'p-o' : 'ぽ', + 'h-y-a' : 'ひゃ', + 'h-y-i' : 'ひぃ', + 'h-y-u' : 'ひゅ', + 'h-y-e' : 'ひぇ', + 'h-y-o' : 'ひょ', + 'b-y-a' : 'びゃ', + 'b-y-i' : 'びぃ', + 'b-y-u' : 'びゅ', + 'b-y-e' : 'びぇ', + 'b-y-o' : 'びょ', + 'p-y-a' : 'ぴゃ', + 'p-y-i' : 'ぴぃ', + 'p-y-u' : 'ぴゅ', + 'p-y-e' : 'ぴぇ', + 'p-y-o' : 'ぴょ', + 'f-a' : 'ふぁ', + 'f-i' : 'ふぃ', + 'f-u' : 'ふ', + 'f-e' : 'ふぇ', + 'f-o' : 'ふぉ', + 'f-y-a' : 'ふゃ', + 'f-y-i' : 'ふぃ', + 'f-y-u' : 'ふゅ', + 'f-y-e' : 'ふぇ', + 'f-y-o' : 'ふょ', + 'b-w-a' : 'ぶぁ', ##2 + 'b-w-e' : 'ぶぇ', ##2 + 'b-w-o' : 'ぶぉ', ##2 + 'p-w-a' : 'ぷぁ', ##2 + 'p-w-e' : 'ぷぇ', ##2 + 'p-w-o' : 'ぷぉ', ##2 + 'm-a' : 'ま', + 'm-i' : 'み', + 'm-u' : 'む', + 'm-e' : 'め', + 'm-o' : 'も', + 'm-y-a' : 'みゃ', + 'm-y-i' : 'みぃ', + 'm-y-u' : 'みゅ', + 'm-y-e' : 'みぇ', + 'm-y-o' : 'みょ', + 'y-a' : 'や', + 'y-i' : 'い', + 'y-u' : 'ゆ', + 'y-e' : 'いぇ', + 'y-o' : 'よ', + 'l-y-a' : 'ゃ', + 'l-y-i' : 'ぃ', + 'l-y-u' : 'ゅ', + 'l-y-e' : 'ぇ', + 'l-y-o' : 'ょ', + 'x-y-a' : 'ゃ', + 'x-y-i' : 'ぃ', + 'x-y-u' : 'ゅ', + 'x-y-e' : 'ぇ', + 'x-y-o' : 'ょ', + 'r-a' : 'ら', + 'r-i' : 'り', + 'r-u' : 'る', + 'r-e' : 'れ', + 'r-o' : 'ろ', + 'r-y-a' : 'りゃ', + 'r-y-i' : 'りぃ', + 'r-y-u' : 'りゅ', + 'r-y-e' : 'りぇ', + 'r-y-o' : 'りょ', + 'w-a' : 'わ', + 'w-i' : 'うぃ', + 'w-u' : 'う', + 'w-e' : 'うぇ', + 'w-o' : 'を', + 'l-w-a' : 'ゎ', + 'x-w-a' : 'ゎ', + 'n-apostrophe' : 'ん', + 'n-n' : 'ん', + 'w-y-i' : 'ゐ', + 'w-y-e' : 'ゑ', + }, + + 'kana_typing_rule': { + 'method': 'jp', + 'newkeys': [], + }, + + 'kana_typing_rule/jp': { + # no modifiers keys + '1' : 'ぬ', + '2' : 'ふ', + '3' : 'あ', + '4' : 'う', + '5' : 'え', + '6' : 'お', + '7' : 'や', + '8' : 'ゆ', + '9' : 'よ', + '0' : 'わ', + 'minus' : 'ほ', + 'asciicircum' : 'へ', + + 'q' : 'た', + 'w' : 'て', + 'e' : 'い', + 'r' : 'す', + 't' : 'か', + 'y' : 'ん', + 'u' : 'な', + 'i' : 'に', + 'o' : 'ら', + 'p' : 'せ', + 'at' : '゛', + 'bracketleft' : '゜', + + 'a' : 'ち', + 's' : 'と', + 'd' : 'し', + 'f' : 'は', + 'g' : 'き', + 'h' : 'く', + 'j' : 'ま', + 'k' : 'の', + 'l' : 'り', + 'semicolon' : 'れ', + 'colon' : 'け', + 'bracketright' : 'む', + + 'z' : 'つ', + 'x' : 'さ', + 'c' : 'そ', + 'v' : 'ひ', + 'b' : 'こ', + 'n' : 'み', + 'm' : 'も', + 'comma' : 'ね', + 'period' : 'る', + 'slash' : 'め', + # 'backslash' : 'ー', + 'backslash' : 'ろ', + + # shift modifiered keys + 'exclam' : 'ぬ', + 'quotedbl' : 'ふ', + 'numbersign' : 'ぁ', + 'dollar' : 'ぅ', + 'percent' : 'ぇ', + 'ampersand' : 'ぉ', + 'apostrophe' : 'ゃ', + 'parenleft' : 'ゅ', + 'parenright' : 'ょ', + 'asciitilde' : 'を', + 'equal' : 'ゑ', + 'bar' : 'ー', + + 'largeq' : 'た', + 'largew' : 'て', + 'largee' : 'ぃ', + 'larger' : 'す', + 'larget' : 'ヵ', + 'largey' : 'ん', + 'largeu' : 'な', + 'largei' : 'に', + 'largeo' : 'ら', + 'largep' : 'せ', + 'grave' : '゛', + + 'braceleft' : '「', + + 'largea' : 'ち', + 'larges' : 'と', + 'larged' : 'し', + 'largef' : 'ゎ', + 'largeg' : 'き', + 'largeh' : 'く', + 'largej' : 'ま', + 'largek' : 'の', + 'largel' : 'り', + 'plus' : 'れ', + 'asterisk' : 'ヶ', + + 'braceright' : '」', + + 'largez' : 'っ', + 'largex' : 'さ', + 'largec' : 'そ', + 'largev' : 'ゐ', + 'largeb' : 'こ', + 'largen' : 'み', + 'largem' : 'も', + 'less' : '、', + 'greater' : '。', + + 'question' : '・', + 'underscore' : 'ろ', + + 'yen' : 'ー', + }, + + 'kana_typing_rule/us': { + # no modifiers keys + 'grave' : 'ろ', + '1' : 'ぬ', + '2' : 'ふ', + '3' : 'あ', + '4' : 'う', + '5' : 'え', + '6' : 'お', + '7' : 'や', + '8' : 'ゆ', + '9' : 'よ', + '0' : 'わ', + 'minus' : 'ほ', + 'equal' : 'へ', + + 'q' : 'た', + 'w' : 'て', + 'e' : 'い', + 'r' : 'す', + 't' : 'か', + 'y' : 'ん', + 'u' : 'な', + 'i' : 'に', + 'o' : 'ら', + 'p' : 'せ', + 'bracketleft' : '゛', + 'bracketright' : '゜', + # 'backslash' : 'ー', + 'backslash' : 'む', + + 'a' : 'ち', + 's' : 'と', + 'd' : 'し', + 'f' : 'は', + 'g' : 'き', + 'h' : 'く', + 'j' : 'ま', + 'k' : 'の', + 'l' : 'り', + 'semicolon' : 'れ', + 'apostrophe' : 'け', + + 'z' : 'つ', + 'x' : 'さ', + 'c' : 'そ', + 'v' : 'ひ', + 'b' : 'こ', + 'n' : 'み', + 'm' : 'も', + 'comma' : 'ね', + 'period' : 'る', + 'slash' : 'め', + + # shift modifiered keys + 'asciitilde' : 'ろ', + 'exclam' : 'ぬ', + 'at' : 'ふ', + 'numbersign' : 'ぁ', + 'dollar' : 'ぅ', + 'percent' : 'ぇ', + 'asciicircum' : 'ぉ', + 'ampersand' : 'ゃ', + 'asterisk' : 'ゅ', + 'parenleft' : 'ょ', + 'parenright' : 'を', + 'underscore' : 'ー', + 'plus' : 'ゑ', + + 'largeq' : 'た', + 'largew' : 'て', + 'largee' : 'ぃ', + 'larger' : 'す', + 'larget' : 'ヵ', + 'largey' : 'ん', + 'largeu' : 'な', + 'largei' : 'に', + 'largeo' : 'ら', + 'largep' : 'せ', + 'braceleft' : '「', + + 'braceright' : '」', + + 'bar' : 'む', + + 'largea' : 'ち', + 'larges' : 'と', + 'larged' : 'し', + 'largef' : 'ゎ', + 'largeg' : 'き', + 'largeh' : 'く', + 'largej' : 'ま', + 'largek' : 'の', + 'largel' : 'り', + 'colon' : 'れ', + 'quotedbl' : 'ヶ', + + 'largez' : 'っ', + 'largex' : 'さ', + 'largec' : 'そ', + 'largev' : 'ゐ', + 'largeb' : 'こ', + 'largen' : 'み', + 'largem' : 'も', + 'less' : '、', + 'greater' : '。', + + 'question' : '・', + }, + 'thumb': { + 'keyboard_layout_mode': True, + 'keyboard_layout': 0, + 'fmv_extension': 2, + 'handakuten': False, + 'rs': 'Henkan', + 'ls': 'Muhenkan', + 't1': 100, + 't2': 75, + }, + + 'thumb_typing_rule': { + 'method': 'base', + 'newkeys': [], + 'nicola_j_table_newkeys': [], + 'nicola_a_table_newkeys': [], + 'nicola_f_table_newkeys': [], + 'kb231_j_fmv_table_newkeys': [], + 'kb231_a_fmv_table_newkeys': [], + 'kb231_f_fmv_table_newkeys': [], + 'kb611_j_fmv_table_newkeys': [], + 'kb611_a_fmv_table_newkeys': [], + 'kb611_f_fmv_table_newkeys': [], + }, + + 'thumb_typing_rule/base': { + 'q' : ['。', '', 'ぁ'], + 'w' : ['か', 'が', 'え'], + 'e' : ['た', 'だ', 'り'], + 'r' : ['こ', 'ご', 'ゃ'], + 't' : ['さ', 'ざ', 'れ'], + + 'y' : ['ら', 'よ', 'ぱ'], + 'u' : ['ち', 'に', 'ぢ'], + 'i' : ['く', 'る', 'ぐ'], + 'o' : ['つ', 'ま', 'づ'], + 'p' : [',', 'ぇ', 'ぴ'], + 'at' : ['、', '', ''], + 'bracketleft' : ['゛', '゜', ''], + + 'a' : ['う', '', 'を'], + 's' : ['し', 'じ', 'あ'], + 'd' : ['て', 'で', 'な'], + 'f' : ['け', 'げ', 'ゅ'], + 'g' : ['せ', 'ぜ', 'も'], + + 'h' : ['は', 'み', 'ば'], + 'j' : ['と', 'お', 'ど'], + 'k' : ['き', 'の', 'ぎ'], + 'l' : ['い', 'ょ', 'ぽ'], + 'semicolon' : ['ん', 'っ', ''], + + 'z' : ['.', '', 'ぅ'], + 'x' : ['ひ', 'び', 'ー'], + 'c' : ['す', 'ず', 'ろ'], + 'v' : ['ふ', 'ぶ', 'や'], + 'b' : ['へ', 'べ', 'ぃ'], + + 'n' : ['め', 'ぬ', 'ぷ'], + 'm' : ['そ', 'ゆ', 'ぞ'], + 'comma' : ['ね', 'む', 'ぺ'], + 'period' : ['ほ', 'わ', 'ぼ'], + 'slash' : ['・', 'ぉ', ''], + + '1' : ['1', '', '?'], + '2' : ['2', '', '/'], + '4' : ['4', '', '「'], + '5' : ['5', '', '」'], + + '6' : ['6', '[', ''], + '7' : ['7', ']', ''], + '8' : ['8', '(', ''], + '9' : ['9', ')', ''], + 'backslash' : ['¥', '', ''], + }, + + 'thumb_typing_rule/nicola_j_table': { + 'colon' : [':', '', ''], + 'at' : ['、', '', ''], + 'bracketleft' : ['゛', '゜', ''], + 'bracketright' : ['」', '', ''], + '8' : ['8', '(', ''], + '9' : ['9', ')', ''], + '0' : ['0', '', ''], + }, + + 'thumb_typing_rule/nicola_a_table': { + 'colon' : [':', '', ''], + 'at' : ['@', '', ''], + 'bracketleft' : ['、', '', ''], + 'bracketright' : ['゛', '゜', ''], + '8' : ['8', '', ''], + '9' : ['9', '(', ''], + '0' : ['0', ')', ''], + }, + + 'thumb_typing_rule/nicola_f_table': { + 'colon' : ['、', '', ''], + 'at' : ['@', '', ''], + 'bracketleft' : ['゛', '゜', ''], + 'bracketright' : ['」', '', ''], + '8' : ['8', '(', ''], + '9' : ['9', ')', ''], + '0' : ['0', '', ''], + }, + + 'thumb_typing_rule/kb231_j_fmv_table': { + '3' : ['3', '', '~'], + '0' : ['0', '『', ''], + 'minus' : ['-', '』', ''], + 'equal' : ['=', '', ''], + }, + + 'thumb_typing_rule/kb231_a_fmv_table': { + '3' : ['3', '', '~'], + '0' : ['0', ')', ''], + 'minus' : ['-', '『', ''], + 'equal' : ['=', '』', ''], + }, + + 'thumb_typing_rule/kb231_f_fmv_table': { + '3' : ['3', '', '~'], + '0' : ['0', '『', ''], + 'minus' : ['-', '』', ''], + 'equal' : ['=', '', ''], + }, + + 'thumb_typing_rule/kb611_j_fmv_table': { + 'grave' : ['‘', '', ''], + 'asciicircum' : ['々', '£', ''], + 'colon' : [':', '', ''], + 'at' : ['、', '¢', ''], + 'bracketleft' : ['゛', '゜', ''], + # keysyms are same and keycodes depend on the platforms. + #'¥' : [u'¥', u'¬', u''], + 'backslash' : ['¥', '¦', ''], + }, + + 'thumb_typing_rule/kb611_a_fmv_table': { + 'grave' : ['々', '', '£'], + 'colon' : [':', '', ''], + 'at' : ['@', '', ''], + 'bracketleft' : ['、', '¢', ''], + #'¥' : [u'¥', u'¬', u''], + 'backslash' : ['¥', '¦', ''], + }, + + 'thumb_typing_rule/kb611_f_fmv_table': { + 'grave' : ['‘', '', ''], + 'asciicircum' : ['々', '£', ''], + 'colon' : ['、', '¢', ''], + 'at' : ['@', '', ''], + 'bracketleft' : ['゛', '゜', ''], + #'¥' : [u'¥', u'¬', u''], + 'backslash' : ['¥', '¦', ''], + }, + + 'dict': { + 'zipcode': ['@pkgdatadir@/dicts/zipcode.t'], + 'symbol': ['@pkgdatadir@/dicts/symbol.t'], + 'oldchar': ['@pkgdatadir@/dicts/oldchar.t'], + 'era': ['@pkgdatadir@/dicts/era.t'], + 'files': [ + '@pkgdatadir@/dicts/zipcode.t', + '@pkgdatadir@/dicts/symbol.t', + '@pkgdatadir@/dicts/oldchar.t', + '@pkgdatadir@/dicts/era.t', + ], + }, + + 'dict/file/default': { + 'embed': False, + 'single': True, + 'icon': None, + 'short_label': None, + 'long_label': None, + 'preview_lines': 30, + 'reverse': False, + 'is_system': False, + 'encoding': 'utf-8', + }, + + 'dict/file/embedded': { + 'embed': True, + 'single': True, + 'icon': None, + 'short_label': '般', + 'long_label': N_("General"), + 'preview_lines': 0, + 'reverse': False, + 'is_system': True, + }, + + 'dict/file/zipcode': { + 'embed': False, + 'single': True, + 'icon': None, + 'short_label': '〒', + 'long_label': N_("Zip Code Conversion"), + 'preview_lines': 30, + 'reverse': False, + 'is_system': True, + }, + + 'dict/file/symbol': { + 'embed': True, + 'single': False, + 'icon': None, + 'short_label': '記', + 'long_label': N_("Symbol"), + 'preview_lines': -1, + 'reverse': False, + 'is_system': True, + }, + + 'dict/file/oldchar': { + 'embed': False, + 'single': True, + 'icon': None, + 'short_label': '旧', + 'long_label': N_("Old Character Style"), + 'preview_lines': -1, + 'reverse': False, + 'is_system': True, + }, + 'dict/file/era': { + 'embed': False, + 'single': True, + 'icon': None, + 'short_label': '年', + 'long_label': N_("Era"), + 'preview_lines': -1, + 'reverse': False, + 'is_system': True, + }, +} + +_shortcut_default = { + 'on_off': [@ON_OFF_KEYS@], + 'circle_input_mode': ['Ctrl+comma', 'Ctrl+less'], + # Removed Hiragana_Katakana key in circle_kana_mode for latin_with_shift. + 'circle_kana_mode': ['Ctrl+period', 'Ctrl+greater'], +# 'cancel_pseudo_ascii_mode_key': ['Escape'], + 'circle_typing_method': ['Alt+Romaji', 'Ctrl+slash'], + 'circle_dict_method': ['Alt+Henkan'], + + 'insert_space': ['space'], + 'insert_alternate_space': ['Shift+space'], + 'backspace': ['BackSpace', 'Ctrl+H'], + 'delete': ['Delete', 'Ctrl+D'], + 'commit': ['Return', 'KP_Enter', 'Ctrl+J', 'Ctrl+M'], + 'convert': ['space', 'KP_Space', 'Henkan'], + 'predict': ['Tab', 'ISO_Left_Tab'], + 'cancel': ['Escape', 'Ctrl+G'], + 'reconvert': ['Shift+Henkan'], + + 'move_caret_first': ['Ctrl+A', 'Home'], + 'move_caret_last': ['Ctrl+E', 'End'], + 'move_caret_forward': ['Right', 'Ctrl+F'], + 'move_caret_backward': ['Left', 'Ctrl+B'], + + 'select_first_segment': ['Ctrl+A', 'Home'], + 'select_last_segment': ['Ctrl+E', 'End'], + 'select_next_segment': ['Right', 'Ctrl+F'], + 'select_prev_segment': ['Left', 'Ctrl+B'], + 'shrink_segment': ['Shift+Left', 'Ctrl+I'], + 'expand_segment': ['Shift+Right', 'Ctrl+O'], + 'commit_first_segment': ['Shift+Down'], + 'commit_selected_segment': ['Ctrl+Down'], + + 'select_first_candidate': ['Home'], + 'select_last_candidate': ['End'], + 'select_next_candidate': ['space', 'KP_Space', 'Tab', 'ISO_Left_Tab', 'Henkan', 'Down', 'KP_Add', 'Ctrl+N'], + 'select_prev_candidate': ['Shift+Tab', 'Shift+ISO_Left_Tab', 'Up', 'KP_Subtract', 'Ctrl+P'], + 'candidates_page_up': ['Page_Up'], + 'candidates_page_down': ['Page_Down', 'KP_Tab'], + + 'select_candidates_1': ['1'], + 'select_candidates_2': ['2'], + 'select_candidates_3': ['3'], + 'select_candidates_4': ['4'], + 'select_candidates_5': ['5'], + 'select_candidates_6': ['6'], + 'select_candidates_7': ['7'], + 'select_candidates_8': ['8'], + 'select_candidates_9': ['9'], + 'select_candidates_0': ['0'], + + 'convert_to_char_type_forward': ['Muhenkan'], + 'convert_to_hiragana': ['F6'], + 'convert_to_katakana': ['F7'], + 'convert_to_half': ['F8'], + 'convert_to_half_katakana': ['Shift+F8'], + 'convert_to_wide_latin': ['F9'], + 'convert_to_latin': ['F10'], + + 'dict_admin': ['F11'], + 'add_word': ['F12'], + + 'hiragana_for_latin_with_shift': ['Hiragana_Katakana'], +} + +_config['shortcut/default'] = dict.fromkeys(_cmd_keys, []) +_config['shortcut/default'].update(_shortcut_default) + +_shortcut_atok = { + 'on_off': ['Henkan', 'Eisu_toggle', 'Zenkaku_Hankaku'], + 'circle_input_mode': ['F10'], + 'hiragana_mode': ['Hiragana_Katakana'], + 'katakana_mode': ['Shift+Hiragana_Katakana'], + 'circle_typing_method': ['Romaji', 'Alt+Romaji'], + 'circle_dict_method': ['Alt+Henkan'], + 'convert': ['space', 'Henkan', 'Shift+space', 'Shift+Henkan'], + 'predict': ['Tab'], + 'cancel': ['Escape', 'BackSpace', 'Ctrl+H', 'Ctrl+bracketleft'], + 'commit': ['Return', 'Ctrl+M'], + 'reconvert': ['Shift+Henkan'], + + 'insert_space': ['space'], + 'insert_alternate_space': ['Shift+space'], + 'backspace': ['BackSpace', 'Ctrl+H'], + 'delete': ['Delete', 'Ctrl+G'], + + 'move_caret_backward': ['Left', 'Ctrl+K'], + 'move_caret_forward': ['Right', 'Ctrl+L'], + 'move_caret_first': ['Ctrl+Left'], + 'move_caret_last': ['Ctrl+Right'], + + 'select_prev_segment': ['Shift+Left'], + 'select_next_segment': ['Shift+Right'], + 'select_first_segment': ['Ctrl+Left'], + 'select_last_segment': ['Ctrl+Right'], + 'expand_segment': ['Right', 'Ctrl+L'], + 'shrink_segment': ['Left', 'Ctrl+K'], + 'commit_selected_segment': ['Down', 'Ctrl+N'], + + 'candidates_page_up': ['Shift+Henkan', 'Page_Up'], + 'candidates_page_down': ['Henkan', 'Page_Down'], + 'select_next_candidate': ['space', 'Tab', 'Henkan', 'Shift+space', 'Shift+Henkan'], + 'select_prev_candidate': ['Up'], + + 'select_candidates_1': ['1'], + 'select_candidates_2': ['2'], + 'select_candidates_3': ['3'], + 'select_candidates_4': ['4'], + 'select_candidates_5': ['5'], + 'select_candidates_6': ['6'], + 'select_candidates_7': ['7'], + 'select_candidates_8': ['8'], + 'select_candidates_9': ['9'], + 'select_candidates_0': ['0'], + + 'convert_to_hiragana': ['F6', 'Ctrl+U'], + 'convert_to_katakana': ['F7', 'Ctrl+I'], + 'convert_to_half': ['F8', 'Ctrl+O'], + 'convert_to_half_katakana': ['Shift+F8'], + 'convert_to_wide_latin': ['F9', 'Ctrl+P'], + 'convert_to_latin': ['F10', 'Ctrl+at'], + + 'dict_admin': ['F11'], + 'add_word': ['Ctrl+F7'], + + 'hiragana_for_latin_with_shift': ['Ctrl+J'], +} + +_config['shortcut/atok'] = dict.fromkeys(_cmd_keys, []) +_config['shortcut/atok'].update(_shortcut_atok) + +_shortcut_wnn = { + 'on_off': ['Shift+space'], + 'convert': ['space'], + 'predict': ['Ctrl+Q'], + 'cancel': ['Escape', 'Ctrl+G', 'Alt+Down', 'Muhenkan'], + 'commit': ['Ctrl+L', 'Ctrl+M', 'Ctrl+J', 'Return'], + 'insert_space': ['space'], + 'backspace': ['Ctrl+H', 'BackSpace'], + 'delete': ['Ctrl+D', 'Delete'], + 'circle_dict_method': ['Alt+Henkan'], + + 'move_caret_backward': ['Ctrl+B', 'Left'], + 'move_caret_forward': ['Ctrl+F', 'Right'], + 'move_caret_first': ['Ctrl+A', 'Alt+Left'], + 'move_caret_last': ['Ctrl+E', 'Alt+Right'], + + 'select_prev_segment': ['Ctrl+B', 'Left'], + 'select_next_segment': ['Ctrl+F', 'Right'], + 'select_first_segment': ['Ctrl+A', 'Alt+Left'], + 'select_last_segment': ['Ctrl+E', 'Alt+Right'], + 'expand_segment': ['Ctrl+O', 'F14'], + 'shrink_segment': ['Ctrl+I', 'F13'], + + 'candidates_page_up': ['Tab'], + 'candidates_page_down': ['Shift+Tab'], + 'select_next_candidate': ['space', 'Ctrl+Q', 'Ctrl+P', 'Down'], + 'select_prev_candidate': ['Ctrl+N', 'Up'], + + 'select_candidates_1': ['1'], + 'select_candidates_2': ['2'], + 'select_candidates_3': ['3'], + 'select_candidates_4': ['4'], + 'select_candidates_5': ['5'], + 'select_candidates_6': ['6'], + 'select_candidates_7': ['7'], + 'select_candidates_8': ['8'], + 'select_candidates_9': ['9'], + 'select_candidates_0': ['0'], + + 'convert_to_hiragana': ['F6'], + 'convert_to_katakana': ['F7'], + 'convert_to_half': ['F8'], + 'convert_to_wide_latin': ['F9'], + 'convert_to_latin': ['F10'], + + 'dict_admin': ['F11'], + 'add_word': ['F12'], + + 'hiragana_for_latin_with_shift': ['Hiragana_Katakana'], +} + +_config['shortcut/wnn'] = dict.fromkeys(_cmd_keys, []) +_config['shortcut/wnn'].update(_shortcut_wnn) + diff --git a/setup/python3/ibus-setup-anthy.desktop.in.in b/setup/python3/ibus-setup-anthy.desktop.in.in new file mode 100644 index 0000000..1dd35f9 --- /dev/null +++ b/setup/python3/ibus-setup-anthy.desktop.in.in @@ -0,0 +1,8 @@ +[Desktop Entry] +_Name=IBus Anthy Setup +_Comment=Set up IBus Anthy engine +Exec=@libexecdir@/ibus-setup-anthy +Icon=ibus-anthy +NoDisplay=true +Type=Application +StartupNotify=true diff --git a/setup/python3/ibus-setup-anthy.in b/setup/python3/ibus-setup-anthy.in new file mode 100644 index 0000000..f8832fd --- /dev/null +++ b/setup/python3/ibus-setup-anthy.in @@ -0,0 +1,28 @@ +#!/bin/sh +# vim:set noet ts=4: +# +# ibus-tmpl - The Input Bus template project +# +# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com> +# Copyright (c) 2010-2013 Takao Fujiwara <takao.fujiwara1@gmail.com> +# Copyright (c) 2007-2013 Red Hat, Inc. +# +# 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 of the License, 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +prefix=@prefix@ +datarootdir=@datarootdir@ +export IBUS_LOCALEDIR=@localedir@ +exec @PYTHON@ @prefix@/share/ibus-anthy/setup/main.py $@ + diff --git a/setup/python3/main.py b/setup/python3/main.py new file mode 100644 index 0000000..fec03a6 --- /dev/null +++ b/setup/python3/main.py @@ -0,0 +1,1729 @@ +# vim:set noet ts=4: +# +# ibus-anthy - The Anthy engine for IBus +# +# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com> +# Copyright (c) 2009 Hideaki ABE <abe.sendai@gmail.com> +# Copyright (c) 2010-2014 Takao Fujiwara <takao.fujiwara1@gmail.com> +# Copyright (c) 2007-2014 Red Hat, Inc. +# +# 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 of the License, 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +from os import environ, getuid, path +import binascii +import codecs +import functools +import locale +import os, sys +import xml.dom.minidom +import gettext +from gettext import dgettext + +from gi.repository import GLib + +# set_prgname before importing other modules to show the name in warning +# messages when import modules are failed. E.g. Gtk. +GLib.set_prgname('ibus-setup-anthy') + +from gi.repository import Gtk +from gi.repository import Gdk +from gi.repository import GdkX11 +from gi.repository import Pango +from gi.repository import IBus + +import _config as config +from anthyprefs import AnthyPrefs + +DOMAINNAME = 'ibus-anthy' +_ = lambda a : dgettext('ibus-anthy', a) + +def l_to_s(l): + return str(sorted([str(s) for s in l])).replace('\'', '') + +def s_to_l(s): + return [] if s == '[]' else s[1:-1].replace(' ', '').split(',') + + +class AnthySetup(object): + def __init__(self): + # Python's locale module doesn't provide all methods on some + # operating systems like FreeBSD + try: + locale.bindtextdomain(DOMAINNAME, config.LOCALEDIR) + locale.bind_textdomain_codeset(DOMAINNAME, 'UTF-8') + except AttributeError: + pass + gettext.bindtextdomain(DOMAINNAME, config.LOCALEDIR) + gettext.bind_textdomain_codeset(DOMAINNAME, 'UTF-8') + + # IBus.Bus() calls ibus_bus_new(). + # Gtk.Builder().add_from_file() also calls ibus_bus_new_async() + # via ibus_im_context_new(). + # Then if IBus.Bus() is called after Gtk.Builder().add_from_file(), + # the connection delay would be happened without an async + # finish function. + ibus_address = IBus.get_address() + bus = None + if ibus_address != None: + bus = IBus.Bus(connect_async='True') + + builder_file = path.join(path.dirname(__file__), 'setup.ui') + self.__builder = builder = Gtk.Builder() + builder.set_translation_domain(DOMAINNAME) + builder.add_from_file(builder_file) + + toplevel = builder.get_object('main') + + try: + gnome_control_center_xid = int(environ['GNOME_CONTROL_CENTER_XID']) + except: + gnome_control_center_xid = 0 + + if gnome_control_center_xid != 0: + def set_transient(obj, pspec): + window = toplevel.get_window() + if window == None: + return + parent_window = GdkX11.X11Window.foreign_new_for_display(Gdk.Display.get_default(), + gnome_control_center_xid) + if parent_window != None: + window.set_transient_for(parent_window) + toplevel.set_wmclass('gnome-control-center', 'Gnome-control-center') + toplevel.set_modal(True) + toplevel.set_type_hint(Gdk.WindowTypeHint.DIALOG) + toplevel.connect('notify::window', set_transient) + + toplevel.show() + + if ibus_address == None: + builder.connect_signals(self) + # self.__run_message_dialog needs self.__builder. + self.__run_message_dialog(_("ibus is not running."), + Gtk.MessageType.ERROR) + return + + if bus.is_connected(): + self.__init_bus_connected(bus) + else: + bus.connect('connected', self.__init_bus_connected) + + def __init_bus_connected(self, bus): + self.__config = bus.get_config() + builder = self.__builder + + self.__thumb_kb_layout_mode = None + self.__thumb_kb_layout = None + self.__japanese_ordered_dict = {} + self.prefs = prefs = AnthyPrefs(None, self.__config) + + # glade 'icon_name' property has a custom scaling and it seems + # to be difficult to show the complicated small icon in metacity. + # This can add the pixbuf without scaling. + anthydir = path.dirname(path.dirname(__file__)) + if not anthydir: + anthydir = '/usr/share/ibus-anthy' + icon_path = path.join(anthydir, 'icons', 'ibus-anthy.png') + if path.exists(icon_path): + builder.get_object('main').set_icon_from_file(icon_path) + else: + icon_path = 'ibus-anthy' + builder.get_object('main').set_icon_name(icon_path) + + for name in ['input_mode', 'typing_method', 'conversion_segment_mode', + 'period_style', 'symbol_style', 'ten_key_mode', + 'behavior_on_focus_out', 'behavior_on_period', + 'half_width_symbol', 'half_width_number', 'half_width_space', + 'latin_with_shift', + 'thumb:keyboard_layout_mode', 'thumb:keyboard_layout', + 'thumb:fmv_extension', 'thumb:handakuten']: + section, key = self.__get_section_key(name) + builder.get_object(name).set_active(prefs.get_value(section, key)) + + tv = builder.get_object('menu_visible:treeview') + ls = Gtk.ListStore(str, bool, str) + tv.set_model(ls) + + column = Gtk.TreeViewColumn(' ') + renderer = Gtk.CellRendererToggle() + renderer.set_radio(False) + renderer.connect('toggled', self.__renderer_toggled_cb, ls) + column.pack_start(renderer, False) + column.set_cell_data_func(renderer, + self.__toggle_menu_visible_cell_cb, + 1) + tv.append_column(column) + + column = Gtk.TreeViewColumn(_("Menu label")) + renderer = Gtk.CellRendererText() + column.pack_start(renderer, False) + column.set_cell_data_func(renderer, + self.__text_menu_visible_cell_cb, + 2) + tv.append_column(column) + + self.__append_menus_in_model() + + l = ['default', 'atok', 'wnn'] + s_type = prefs.get_value('common', 'shortcut_type') + s_type = s_type if s_type in l else 'default' + builder.get_object('shortcut_type').set_active(l.index(s_type)) + + builder.get_object('page_size').set_value(prefs.get_value('common', + 'page_size')) + + tv = builder.get_object('shortcut') + tv.append_column(Gtk.TreeViewColumn(_("Command"), + Gtk.CellRendererText(), text=0)) + renderer = Gtk.CellRendererText() + renderer.set_property('ellipsize', Pango.EllipsizeMode.END) + tv.append_column(Gtk.TreeViewColumn(_("Shortcut"), + renderer, text=1)) + tv.get_selection().connect_after('changed', + self.on_selection_changed, 0) + ls = Gtk.ListStore(str, str) + sec = 'shortcut/' + s_type + for k in self.prefs.keys(sec): + ls.append([k, l_to_s(self.prefs.get_value(sec, k))]) + tv.set_model(ls) + + self.__keymap = None + GLib.idle_add(self.__update_keymap_label, + priority = GLib.PRIORITY_LOW) + + self.__thumb_kb_layout_mode = builder.get_object('thumb:keyboard_layout_mode') + self.__thumb_kb_layout = builder.get_object('thumb:keyboard_layout') + self.__set_thumb_kb_label() + + for name in ['thumb:ls', 'thumb:rs']: + section, key = self.__get_section_key(name) + builder.get_object(name).set_text(prefs.get_value(section, key)) + + tv = builder.get_object('es:treeview') + tv.append_column(Gtk.TreeViewColumn('', Gtk.CellRendererText(), text=0)) + tv.get_selection().connect_after('changed', + self.on_selection_changed, 1) + tv.set_model(Gtk.ListStore(str)) + + key = 'dict_admin_command' + cli = self.__get_dict_cli_from_list(prefs.get_value('common', key)) + name = 'dict:entry_edit_dict_command' + builder.get_object(name).set_text(cli) + key = 'add_word_command' + cli = self.__get_dict_cli_from_list(prefs.get_value('common', key)) + name = 'dict:entry_add_word_command' + builder.get_object(name).set_text(cli) + + tv = builder.get_object('dict:view') + + column = Gtk.TreeViewColumn(' ') + renderer = Gtk.CellRendererText() + column.pack_start(renderer, False) + column.set_cell_data_func(renderer, self.__text_cell_data_cb, 1) + tv.append_column(column) + + column = Gtk.TreeViewColumn(_("Description")) + renderer = Gtk.CellRendererText() + column.pack_start(renderer, False) + column.set_cell_data_func(renderer, self.__text_cell_data_cb, 2) + column.set_expand(True) + tv.append_column(column) + + # Translators: "Embd" is an abbreviation of "embedded". + column = Gtk.TreeViewColumn(_("Embd")) + renderer = Gtk.CellRendererToggle() + renderer.set_radio(False) + column.pack_start(renderer, False) + column.set_cell_data_func(renderer, self.__toggle_cell_data_cb, 3) + tv.append_column(column) + + # Translators: "Sgl" is an abbreviation of "single". + column = Gtk.TreeViewColumn(_("Sgl")) + renderer = Gtk.CellRendererToggle() + renderer.set_radio(False) + column.pack_start(renderer, False) + column.set_cell_data_func(renderer, self.__toggle_cell_data_cb, 4) + tv.append_column(column) + + ''' + Unfortunately reverse conversion is too slow. + # Translators: "Rev" is an abbreviation of "reverse". + column = Gtk.TreeViewColumn(_("Rev")) + renderer = Gtk.CellRendererToggle() + renderer.set_radio(False) + column.pack_start(renderer, False) + column.set_cell_data_func(renderer, self.__toggle_cell_data_cb, 5) + tv.append_column(column) + ''' + + ls = Gtk.ListStore(str, str, str, bool, bool, bool) + tv.set_model(ls) + self.__append_dicts_in_model() + + self.__init_japanese_sort() + self.__init_about_vbox(icon_path) + + builder.connect_signals(self) + + def __init_japanese_sort(self): + japanese_ordered_dict = {} + japanese_ordered_list = self.prefs.get_japanese_ordered_list() + for index, c in enumerate(japanese_ordered_list): + japanese_ordered_dict[c] = index + self.__japanese_ordered_dict = japanese_ordered_dict; + + def __init_about_vbox(self, icon_path): + about_dialog = self.__builder.get_object('about_dialog') + about_vbox = self.__builder.get_object('about_vbox') + about_dialog.set_version(self.prefs.get_version()) + if icon_path != None: + if icon_path[0] == '/': + image = Gtk.Image.new_from_file(icon_path) + about_dialog.set_logo(image.get_pixbuf()) + else: + icon_theme = Gtk.IconTheme.get_default() + try: + pixbuf = icon_theme.load_icon(icon_path, 48, 0) + about_dialog.set_logo(pixbuf) + except Exception as err: + print('Not found icon', str(err), file=sys.stderr) + print('Need to run gtk-update-icon-cache', file=sys.stderr) + content_area = about_dialog.get_content_area() + list = content_area.get_children() + vbox = list[0] + for w in vbox.get_children(): + old_parent = w.props.parent + w.unparent() + w.emit('parent-set', old_parent) + about_vbox.pack_start(w, False, False, 0) + + def __get_userhome(self): + if 'HOME' not in environ: + import pwd + userhome = pwd.getpwuid(getuid()).pw_dir + else: + userhome = environ['HOME'] + userhome = userhome.rstrip('/') + return userhome + + def __get_section_key(self, name): + i = name.find(':') + if i > 0: + section = name[:i] + key = name[i + 1:] + else: + section = 'common' + key = name + return (section, key) + + def __run_message_dialog(self, message, type=Gtk.MessageType.INFO): + dlg = Gtk.MessageDialog(parent=self.__builder.get_object('main'), + flags=Gtk.DialogFlags.MODAL, + message_type=type, + buttons=Gtk.ButtonsType.OK, + message_format=message) + dlg.run() + dlg.destroy() + + def __japanese_tuple_sort(self, a, b): + if a[1] == b[1]: + # http://docs.python.org/3.0/whatsnew/3.0.html#ordering-comparisons + return (a[0] > b[0]) - (a[0] < b[0]) + elif a[1] in self.__japanese_ordered_dict and \ + b[1] in self.__japanese_ordered_dict: + return self.__japanese_ordered_dict[a[1]] - \ + self.__japanese_ordered_dict[b[1]] + elif a[1] not in self.__japanese_ordered_dict and \ + b[1] in self.__japanese_ordered_dict: + return 1 + elif a[1] in self.__japanese_ordered_dict and \ + b[1] not in self.__japanese_ordered_dict: + return -1 + else: + return (a[1] > b[1]) - (a[1] < b[1]) + + def __japanese_thumb_sort(self, a, b): + # http://docs.python.org/3.0/whatsnew/3.0.html#ordering-comparisons + return (a[0] > b[0]) - (a[0] < b[0]) + + def __renderer_toggled_cb(self, renderer, path, model): + prefs = self.prefs + enabled = not model[path][1] + model[path][1] = enabled + key = model[path][0] + prefs.set_value('common', key, enabled) + self.__builder.get_object('btn_apply').set_sensitive(True) + + def __toggle_menu_visible_cell_cb(self, column, renderer, model, iter, id): + l = self.__builder.get_object('menu_visible:treeview').get_model() + active = l.get_value(iter, id) + renderer.set_property('active', active) + + def __text_menu_visible_cell_cb(self, column, renderer, model, iter, id): + l = self.__builder.get_object('menu_visible:treeview').get_model() + text = l.get_value(iter, id) + renderer.set_property('text', text) + + def __append_menus_in_model(self): + prefs = self.prefs + l = self.__builder.get_object('menu_visible:treeview').get_model() + l.append(['show-input-mode', + prefs.get_value('common', 'show-input-mode'), + _("Input mode")]) + l.append(['show-typing-method', + prefs.get_value('common', 'show-typing-method'), + _("Typing method")]) + l.append(['show-segment-mode', + prefs.get_value('common', 'show-segment-mode'), + _("Segment mode")]) + l.append(['show-dict-mode', + prefs.get_value('common', 'show-dict-mode'), + _("Dictionary mode")]) + l.append(['show-dict-config', + prefs.get_value('common', 'show-dict-config'), + _("Dictionary - Anthy")]) + l.append(['show-preferences', + prefs.get_value('common', 'show-preferences'), + _("Preferences - Anthy")]) + + def __get_romaji_treeview_custom_key_table(self, method): + prefs = self.prefs + rule = {} + ls = Gtk.ListStore(str, str, str) + tv = self.__builder.get_object('treeview_custom_key_table') + section_base = 'romaji_typing_rule' + section = section_base + '/' + prefs.str(method) + for key in prefs.keys(section): + key = prefs.str(key) + value = prefs.get_value(section, key) + ch = prefs.typing_from_config_key(key) + if ch == '': + continue + # config.set_value(key, None) is not supported. + if value != None and value != '': + rule[ch] = prefs.str(value) + for key in prefs.get_value(section_base, 'newkeys'): + key = prefs.str(key) + value = self.prefs.get_value_direct(section, key) + ch = prefs.typing_from_config_key(key) + if ch == '': + continue + # config.set_value(key, None) is not supported. + if value != None and value != '': + rule[ch] = prefs.str(value) + for key, value in sorted(list(rule.items()), \ + key = functools.cmp_to_key(self.__japanese_tuple_sort)): + ls.append(['romaji', key, value]) + tv.append_column(Gtk.TreeViewColumn(_(_("Input Chars")), + Gtk.CellRendererText(), text=1)) + tv.append_column(Gtk.TreeViewColumn(_(_("Output Chars")), + Gtk.CellRendererText(), text=2)) + tv.set_model(ls) + return tv + + def __get_kana_treeview_custom_key_table(self, method): + prefs = self.prefs + rule = {} + ls = Gtk.ListStore(str, str, str) + tv = self.__builder.get_object('treeview_custom_key_table') + section_base = 'kana_typing_rule' + section = section_base + '/' + prefs.str(method) + for key in prefs.keys(section): + key = prefs.str(key) + value = prefs.get_value(section, key) + ch = prefs.typing_from_config_key(key) + if ch == '': + continue + # config.set_value(key, None) is not supported. + if value != None and value != '': + rule[ch] = prefs.str(value) + for key in prefs.get_value(section_base, 'newkeys'): + key = prefs.str(key) + value = self.prefs.get_value_direct(section, key) + ch = prefs.typing_from_config_key(key) + if ch == '': + continue + # config.set_value(key, None) is not supported. + if value != None and value != '': + rule[ch] = prefs.str(value) + for key, value in sorted(list(rule.items()), \ + key = functools.cmp_to_key(self.__japanese_tuple_sort)): + ls.append(['kana', key, value]) + tv.append_column(Gtk.TreeViewColumn(_(_("Input Chars")), + Gtk.CellRendererText(), text=1)) + tv.append_column(Gtk.TreeViewColumn(_(_("Output Chars")), + Gtk.CellRendererText(), text=2)) + tv.set_model(ls) + return tv + + def __get_thumb_treeview_custom_key_table(self, method): + prefs = self.prefs + rule = {} + ls = Gtk.ListStore(str, str, str, str, str) + tv = self.__builder.get_object('treeview_custom_key_table') + section_base = 'thumb_typing_rule' + section = section_base + '/' + prefs.str(method) + for key in prefs.keys(section): + key = prefs.str(key) + value = prefs.get_value(section, key) + ch = prefs.typing_from_config_key(key) + if ch == '': + continue + # config.set_value(key, None) is not supported. + if value != None and len(value) == 3 and \ + ((value[0] != None and value[0] != '') or \ + (value[1] != None and value[1] != '') or \ + (value[2] != None and value[2] != '')): + rule[ch] = {} + rule[ch][0] = prefs.str(value[0]) + rule[ch][1] = prefs.str(value[1]) + rule[ch][2] = prefs.str(value[2]) + for key in prefs.get_value(section_base, 'newkeys'): + key = prefs.str(key) + value = self.prefs.get_value_direct(section, key) + ch = prefs.typing_from_config_key(key) + if ch == '': + continue + # config.set_value(key, None) is not supported. + if value != None and len(value) == 3 and \ + ((value[0] != None and value[0] != '') or \ + (value[1] != None and value[1] != '') or \ + (value[2] != None and value[2] != '')): + rule[ch] = {} + rule[ch][0] = prefs.str(value[0]) + rule[ch][1] = prefs.str(value[1]) + rule[ch][2] = prefs.str(value[2]) + for key, value in sorted(list(rule.items()), \ + key = functools.cmp_to_key(self.__japanese_thumb_sort)): + ls.append(['thumb', key, value[0], value[2], value[1]]) + tv.append_column(Gtk.TreeViewColumn(_(_("Input")), + Gtk.CellRendererText(), text=1)) + tv.append_column(Gtk.TreeViewColumn(_(_("Single")), + Gtk.CellRendererText(), text=2)) + tv.append_column(Gtk.TreeViewColumn(_(_("Left")), + Gtk.CellRendererText(), text=3)) + tv.append_column(Gtk.TreeViewColumn(_(_("Right")), + Gtk.CellRendererText(), text=4)) + tv.set_model(ls) + return tv + + def __show_dialog_custom_key_table_extention(self, mode): + hbox_combo = self.__builder.get_object('hbox_for_combobox_custom_key_table') + label_left = self.__builder.get_object('label_left_thumb_shift_custom_key') + entry_left = self.__builder.get_object('entry_left_thumb_shift_custom_key') + label_right = self.__builder.get_object('label_right_thumb_shift_custom_key') + entry_right = self.__builder.get_object('entry_right_thumb_shift_custom_key') + if mode == 'thumb': + hbox_combo.show() + label_left.show() + entry_left.show() + label_right.show() + entry_right.show() + elif mode == 'kana': + hbox_combo.show() + label_left.hide() + entry_left.hide() + label_right.hide() + entry_right.hide() + else: + hbox_combo.hide() + label_left.hide() + entry_left.hide() + label_right.hide() + entry_right.hide() + + def __connect_dialog_custom_key_table_buttons(self, mode): + tv = self.__builder.get_object('treeview_custom_key_table') + tv.get_selection().connect_after('changed', + self.on_selection_custom_key_table_changed, 0) + entry = self.__builder.get_object('entry_input_custom_key') + entry.connect('changed', self.on_entry_custom_key_changed, mode) + entry = self.__builder.get_object('entry_output_custom_key') + entry.connect('changed', self.on_entry_custom_key_changed, mode) + entry = self.__builder.get_object('entry_left_thumb_shift_custom_key') + entry.connect('changed', self.on_entry_custom_key_changed, mode) + entry = self.__builder.get_object('entry_right_thumb_shift_custom_key') + entry.connect('changed', self.on_entry_custom_key_changed, mode) + button = self.__builder.get_object('button_add_custom_key') + button.set_sensitive(False) + button.connect('clicked', self.on_btn_add_custom_key, mode) + button = self.__builder.get_object('button_remove_custom_key') + button.set_sensitive(False) + button.connect('clicked', self.on_btn_remove_custom_key, tv) + + def __disconnect_dialog_custom_key_table_buttons(self): + tv = self.__builder.get_object('treeview_custom_key_table') + combobox = self.__builder.get_object('combobox_custom_key_table') + if tv != None: + for column in tv.get_columns(): + tv.remove_column(column) + for child in tv.get_children(): + tv.remove(child) + entry = self.__builder.get_object('entry_input_custom_key') + entry.disconnect_by_func(self.on_entry_custom_key_changed) + entry.set_text('') + entry = self.__builder.get_object('entry_output_custom_key') + entry.disconnect_by_func(self.on_entry_custom_key_changed) + entry.set_text('') + entry = self.__builder.get_object('entry_left_thumb_shift_custom_key') + entry.disconnect_by_func(self.on_entry_custom_key_changed) + entry = self.__builder.get_object('entry_right_thumb_shift_custom_key') + entry.disconnect_by_func(self.on_entry_custom_key_changed) + button = self.__builder.get_object('button_add_custom_key') + button.disconnect_by_func(self.on_btn_add_custom_key) + button = self.__builder.get_object('button_remove_custom_key') + button.disconnect_by_func(self.on_btn_remove_custom_key) + combobox.clear() + combobox.disconnect_by_func(self.on_cb_custom_key_table_changed) + + def __run_dialog_custom_key_table(self, mode): + prefs = self.prefs + dlg = self.__builder.get_object('dialog_custom_key_table') + label = self.__builder.get_object('label_custom_key_table') + label_output = self.__builder.get_object('label_output_custom_key') + list_labels = [] + if mode == 'romaji': + dlg.set_title(_("Customize Romaji Key Table")) + label.set_label(_("_Romaji Key Table:")) + label_output.set_label(_("_Output Chars")) + list_labels = [['default', _("Default")]] + self.__show_dialog_custom_key_table_extention(mode) + elif mode == 'kana': + dlg.set_title(_("Customize Kana Key Table")) + label.set_label(_("_Kana Key Table:")) + label_output.set_label(_("_Output Chars")) + list_labels = [['jp', _("Japanese Keyboard Layout")], + ['us', _("U.S. Keyboard Layout")]] + self.__show_dialog_custom_key_table_extention(mode) + elif mode == 'thumb': + dlg.set_title(_("Customize Thumb Shift Key Table")) + label.set_label(_("_Thumb Shift Key Table:")) + label_output.set_label(_("Single _Output Chars")) + list_labels = [['base', _("Base")], + ['nicola_j_table', _("NICOLA-J key extension")], + ['nicola_a_table', _("NICOLA-A key extension")], + ['nicola_f_table', _("NICOLA-F key extension")], + ['kb231_j_fmv_table', _("FMV KB231-J key extension")], + ['kb231_a_fmv_table', _("FMV KB231-A key extension")], + ['kb231_f_fmv_table', _("FMV KB231-F key extension")], + ['kb611_j_fmv_table', _("FMV KB611-J key extension")], + ['kb611_a_fmv_table', _("FMV KB611-A key extension")], + ['kb611_f_fmv_table', _("FMV KB611-F key extension")], + ] + self.__show_dialog_custom_key_table_extention(mode) + ls = Gtk.ListStore(str, str) + for s in list_labels: + ls.append([s[1], s[0]]) + renderer = Gtk.CellRendererText() + combobox = self.__builder.get_object('combobox_custom_key_table') + combobox.pack_start(renderer, True) + combobox.add_attribute(renderer, 'text', 0) + combobox.set_model(ls) + + tv = None + if mode == 'romaji': + method = prefs.get_value('romaji_typing_rule', 'method') + if method == None: + method = 'default' + tv = self.__get_romaji_treeview_custom_key_table(method) + if mode == 'kana': + method = prefs.get_value('kana_typing_rule', 'method') + if method == None: + method = 'jp' + tv = self.__get_kana_treeview_custom_key_table(method) + if mode == 'thumb': + method = prefs.get_value('thumb_typing_rule', 'method') + if method == None: + method = 'base' + tv = self.__get_thumb_treeview_custom_key_table(method) + + self.__connect_dialog_custom_key_table_buttons(mode) + + id = 0 + # thumb uses all tables so the default is always 0. + if mode != 'thumb': + for index, labels in enumerate(list_labels): + if labels[0] == method: + id = index + break + combobox.set_active(id) + combobox.connect('changed', self.on_cb_custom_key_table_changed, mode) + + id = dlg.run() + dlg.hide() + + self.__disconnect_dialog_custom_key_table_buttons() + + def __set_thumb_kb_label(self): + if self.__thumb_kb_layout_mode == None or \ + self.__thumb_kb_layout == None: + return + section, key = self.__get_section_key( + Gtk.Buildable.get_name(self.__thumb_kb_layout_mode)) + layout_mode = self.prefs.get_value(section, key) + if layout_mode: + self.__thumb_kb_layout.set_sensitive(False) + else: + self.__thumb_kb_layout.set_sensitive(True) + + def __get_dict_cli_from_list(self, cli_list): + cli_str = cli_list[0] + if len(cli_list) <= 2: + return cli_str + cli_str = cli_str + ' ' + ' '.join(cli_list[2:]) + return cli_str + + def __get_quoted_id(self, file): + id = file + has_mbcs = False + + for i in range(0, len(id)): + if ord(id[i]) >= 0x7f: + has_mbcs = True + break + if has_mbcs: + id = str(binascii.hexlify(id.encode()), 'ascii') + + if id.find('/') >=0: + id = id[id.rindex('/') + 1:] + if id.find('.') >=0: + id = id[:id.rindex('.')] + + if id.startswith('0x'): + id = str(binascii.hexlify(id.encode()), 'ascii') + has_mbcs = True + if has_mbcs: + id = '0x' + id + return id + + def __get_dict_file_from_id(self, selected_id): + files = self.prefs.get_value('dict', 'files') + retval = None + + for file in files: + id = self.__get_quoted_id(file) + # The selected_id is already quoted. + if selected_id == id: + retval = file + break + return retval + + def __is_system_dict_file_from_id(self, selected_id): + prefs = self.prefs + section = 'dict/file/' + selected_id + key = 'is_system' + + if key not in prefs.keys(section): + return False + return prefs.get_value(section, key) + + def __append_dict_id_in_model(self, id, is_gettext): + prefs = self.prefs + section = 'dict/file/' + id + # user value is dbus.String + prefs.set_value(section, 'short_label', + prefs.str(prefs.get_value(section, 'short_label'))) + prefs.set_value(section, 'long_label', + prefs.str(prefs.get_value(section, 'long_label'))) + short_label = prefs.get_value(section, 'short_label') + long_label = prefs.get_value(section, 'long_label') + embed = prefs.get_value(section, 'embed') + single = prefs.get_value(section, 'single') + reverse = prefs.get_value(section, 'reverse') + if is_gettext: + long_label = _(long_label) + l = self.__builder.get_object('dict:view').get_model() + l.append([id, short_label, long_label, embed, single, reverse]) + + def __append_dicts_in_model(self): + prefs = self.prefs + for file in prefs.get_value('dict', 'files'): + if not path.exists(file): + continue + id = self.__get_quoted_id(file) + section = 'dict/file/' + id + if section not in prefs.sections(): + self.__fetch_dict_values(section) + is_system_dict = self.__is_system_dict_file_from_id(id) + self.__append_dict_id_in_model(id, is_system_dict) + + def __append_user_dict_from_dialog(self, file, id, new): + files = self.prefs.get_value('dict', 'files') + + if new: + if file in files: + self.__run_message_dialog(_("Your choosed file has already been added: ") + file, + Gtk.MessageType.ERROR) + return + if not path.exists(file): + self.__run_message_dialog(_("The file you have chosen does not exist: ") + file, + Gtk.MessageType.ERROR) + return + if path.isdir(file): + self.__run_message_dialog(_("Your choosed file is a directory: " + file), + Gtk.MessageType.ERROR) + return + if file.startswith(self.__get_userhome() + '/.anthy'): + self.__run_message_dialog(_("You cannot add dictionaries in the anthy private directory: " + file), + Gtk.MessageType.ERROR) + return + + if new: + id = self.__get_quoted_id(file) + if id == None or id == '': + self.__run_message_dialog(_("Your file path is not good: ") + file, + Gtk.MessageType.ERROR) + return + + single = self.__builder.get_object('dict:single').get_active() + embed = self.__builder.get_object('dict:embed').get_active() + reverse = self.__builder.get_object('dict:reverse').get_active() + short_label = self.__builder.get_object('dict:short_entry').get_text() + if len(short_label) > 1: + short_label = short_label[0] + long_label = self.__builder.get_object('dict:long_entry').get_text() + + if new: + files.append(file) + self.prefs.set_value('dict', 'files', files) + + if short_label == None or short_label == '': + short_label = id[0] + if long_label == None or long_label == '': + long_label = id + self.__update_dict_values(new, id, short_label, long_label, embed, single, reverse) + self.__builder.get_object('btn_apply').set_sensitive(True) + files = [] + + def __init_dict_chooser_dialog(self): + self.__builder.get_object('dict:single').set_active(True) + self.__builder.get_object('dict:embed').set_active(False) + self.__builder.get_object('dict:reverse').set_active(False) + short_entry = self.__builder.get_object('dict:short_entry') + short_entry.set_text('') + short_entry.set_editable(True) + long_entry = self.__builder.get_object('dict:long_entry') + long_entry.set_text('') + long_entry.set_editable(True) + + def __get_selected_dict_id(self): + l, it = self.__builder.get_object('dict:view').get_selection().get_selected() + + if not it: + return None + return l.get_value(it, 0) + + def __set_selected_dict_to_dialog(self): + selected_id = self.__get_selected_dict_id() + if selected_id == None: + return None + + is_system_dict = self.__is_system_dict_file_from_id(selected_id) + + prefs = self.prefs + section = 'dict/file/' + selected_id + short_label = prefs.get_value(section, 'short_label') + long_label = prefs.get_value(section, 'long_label') + embed = prefs.get_value(section, 'embed') + single = prefs.get_value(section, 'single') + reverse = prefs.get_value(section, 'reverse') + + if len(short_label) > 1: + short_label = short_label[0] + self.__builder.get_object('dict:single').set_active(single) + self.__builder.get_object('dict:embed').set_active(embed) + self.__builder.get_object('dict:reverse').set_active(reverse) + short_entry = self.__builder.get_object('dict:short_entry') + short_entry.set_text(short_label) + long_entry = self.__builder.get_object('dict:long_entry') + if is_system_dict: + short_entry.set_editable(False) + long_entry.set_text(_(long_label)) + long_entry.set_editable(False) + else: + short_entry.set_editable(True) + long_entry.set_text(long_label) + long_entry.set_editable(True) + + return selected_id + + def __fetch_dict_values(self, section): + prefs = self.prefs + prefs.set_new_section(section) + prefs.set_new_key(section, 'short_label') + prefs.fetch_item(section, 'short_label') + # user value is dbus.String + prefs.set_value(section, 'short_label', + prefs.str(prefs.get_value(section, 'short_label'))) + prefs.set_new_key(section, 'long_label') + prefs.fetch_item(section, 'long_label') + prefs.set_value(section, 'long_label', + prefs.str(prefs.get_value(section, 'long_label'))) + prefs.set_new_key(section, 'embed') + prefs.fetch_item(section, 'embed') + prefs.set_new_key(section, 'single') + prefs.fetch_item(section, 'single') + prefs.set_new_key(section, 'reverse') + prefs.fetch_item(section, 'reverse') + + def __update_dict_values(self, new, id, short_label, long_label, embed, single, reverse): + prefs = self.prefs + section = 'dict/file/' + id + if section not in prefs.sections(): + prefs.set_new_section(section) + + is_system_dict = self.__is_system_dict_file_from_id(id) + if is_system_dict: + if 'short_label' in prefs.keys(section): + short_label = prefs.get_value(section, 'short_label') + if 'long_label' in prefs.keys(section): + long_label = prefs.get_value(section, 'long_label') + + if new: + l = self.__builder.get_object('dict:view').get_model() + l.append([id, short_label, long_label, embed, single, reverse]) + else: + l, i = self.__builder.get_object('dict:view').get_selection().get_selected() + if i : + l[i] = [id, short_label, long_label, embed, single, reverse] + + key = 'short_label' + prefs.set_value(section, key, short_label) + key = 'long_label' + prefs.set_value(section, key, long_label) + key = 'embed' + prefs.set_value(section, key, embed) + key = 'single' + prefs.set_value(section, key, single) + key = 'reverse' + prefs.set_value(section, key, reverse) + + def __text_cell_data_cb(self, column, renderer, model, iter, id): + l = self.__builder.get_object('dict:view').get_model() + text = l.get_value(iter, id) + renderer.set_property('text', text) + + def __toggle_cell_data_cb(self, column, renderer, model, iter, id): + l = self.__builder.get_object('dict:view').get_model() + active = l.get_value(iter, id) + renderer.set_property('active', active) + + def __resync_engine_file(self): + user_config = path.join(self.__get_userhome(), '.config', + 'ibus-anthy', 'engines.xml') + system_config = path.join(config.PKGDATADIR, 'engine', 'default.xml') + if not path.exists(user_config): + return + if not path.exists(system_config): + os.unlink(user_config) + return + + # path.getmtime depends on the build time rather than install time. + def __get_engine_file_version(engine_file): + version_str = '' + dom = xml.dom.minidom.parse(engine_file) + elements = dom.getElementsByTagName('version') + nodes = [] + if len(elements) > 0: + nodes = elements[0].childNodes + if len(nodes) > 0: + version_str = nodes[0].data + if version_str != '': + version_str = version_str.strip() + return version_str + + user_config_version = __get_engine_file_version(user_config) + system_config_version = __get_engine_file_version(system_config) + if system_config_version > user_config_version: + import shutil + shutil.copyfile(system_config, user_config) + + def __get_engine_file(self): + user_config = path.join(self.__get_userhome(), '.config', + 'ibus-anthy', 'engines.xml') + system_config = path.join(config.PKGDATADIR, 'engine', 'default.xml') + engine_file = None + for f in [user_config, system_config]: + if path.exists(f): + engine_file = f + break + if engine_file == None: + self.__run_message_dialog(_("The engine xml file does not exist: ") + system_config, + Gtk.MessageType.ERROR) + return None + return engine_file + + def __get_keymap(self): + keymap = '' + layout = '' + variant = '' + option = '' + engine_file = self.__get_engine_file() + if engine_file == None: + return None + + dom = xml.dom.minidom.parse(engine_file) + nodes = dom.getElementsByTagName('layout')[0].childNodes + if len(nodes) > 0: + layout = nodes[0].data + if layout != '': + keymap = layout.strip() + nodes = dom.getElementsByTagName('layout_variant')[0].childNodes + if len(nodes) > 0: + variant = nodes[0].data + if variant != '': + keymap += '(' + varaint.strip() + ')' + nodes = dom.getElementsByTagName('layout_option')[0].childNodes + if len(nodes) > 0: + option = nodes[0].data + if option != '': + keymap += '[' + option.strip() + ']' + return keymap + + def __parse_keymap(self, keymap): + layout = None + variant = None + option = None + + length = keymap.find('(') + if length >= 0: + if layout == None: + layout = keymap[0:length] + keymap = keymap[length + 1:] + length = keymap.find(')') + if length > 0: + variant = keymap[0:length] + keymap = keymap[length + 1:] + else: + print('Invalid keymap', keymap, file=sys.stderr) + return ('', '', '') + length = keymap.find('[') + if length >= 0: + if layout == None: + layout = keymap[0:length] + keymap = keymap[length + 1:] + length = keymap.find(']') + if length > 0: + option = keymap[0:length] + keymap = keymap[length + 1:] + else: + print('Invalid keymap', keymap, file=sys.stderr) + return ('', '', '') + + if layout == None: + layout = keymap + if layout == None: + layout = '' + if variant == None: + variant = '' + if option == None: + option = '' + return (layout, variant, option) + + def __save_keymap(self): + engine_file = self.__get_engine_file() + if engine_file == None: + return None + + (layout, variant, option) = self.__parse_keymap(self.__keymap) + + dom = xml.dom.minidom.parse(engine_file) + nodes = dom.getElementsByTagName('layout')[0].childNodes + if len(nodes) == 0: + nodes.append(dom.createTextNode(layout)) + else: + nodes[0].data = layout + nodes = dom.getElementsByTagName('layout_variant')[0].childNodes + if len(nodes) == 0: + nodes.append(dom.createTextNode(variant)) + else: + nodes[0].data = variant + nodes = dom.getElementsByTagName('layout_option')[0].childNodes + if len(nodes) == 0: + nodes.append(dom.createTextNode(option)) + else: + nodes[0].data = option + nodes = dom.getElementsByTagName('symbol')[0].childNodes + user_config = path.join(self.__get_userhome(), '.config', + 'ibus-anthy', 'engines.xml') + dir = path.dirname(user_config) + if not path.exists(dir): + os.makedirs(dir, 0o700) + # io.open() causes TypeError for unicode. + f = codecs.open(user_config, 'w', 'utf-8') + dom.writexml(f, '', '', '', 'utf-8') + f.close() + os.chmod(user_config, 0o600) + self.__keymap = None + self.__run_message_dialog(_("Anthy keyboard layout is changed. " + "Please restart ibus to reload the layout.")) + + def __update_keymap_label(self): + self.__resync_engine_file() + prefs = self.prefs + keymap = self.__get_keymap() + if keymap == None: + return + if keymap == '': + keymap = 'default' + keymap_list = prefs.get_value('common', 'keyboard_layouts') + if keymap != None and not keymap in keymap_list: + keymap_list.append(keymap) + index = -1 + if keymap != None: + index = keymap_list.index(keymap) + model = Gtk.ListStore(str) + for k in keymap_list: + if k == 'default': + k = _("Default") + model.append([k]) + combobox = self.__builder.get_object('keymap:combobox_custom_table') + combobox.set_model(model) + combobox.set_active(0) + if index >= 0: + combobox.set_active(index) + combobox.connect_after('changed', + self.on_cb_keymap_changed, + 0) + + def __save_preferences(self): + self.prefs.commit_all() + if self.__keymap != None: + self.__save_keymap() + + def on_selection_changed(self, widget, id): + set_sensitive = lambda a, b: self.__builder.get_object(a).set_sensitive(b) + flg = True if widget.get_selected()[1] else False + for name in [['btn_default', 'btn_edit'], ['es:button_refresh', 'es:button_del']][id]: + set_sensitive(name, flg) + + def on_selection_custom_key_table_changed(self, widget, id): + l, i = widget.get_selected() + # if 'combobox_custom_key_table' is changed, + # 'treeview_custom_key_table' also receives this signal + # but no selection. + if i == None: + return + button = self.__builder.get_object('button_remove_custom_key') + button.set_sensitive(True) + + def on_main_delete(self, widget, event): + self.on_btn_cancel_clicked(widget) + return True + + def on_btn_ok_clicked(self, widget): + if self.__builder.get_object('btn_apply').get_state() == \ + Gtk.StateType.INSENSITIVE: + Gtk.main_quit() + return True + dlg = self.__builder.get_object('quit_check') + dlg.set_markup('<big><b>%s</b></big>' % _("Confirmation")) + dlg.format_secondary_text( + _("You are about to close the setup dialog, is that OK?")) + id = dlg.run() + dlg.hide() + if id == Gtk.ResponseType.YES: + self.__save_preferences() + Gtk.main_quit() + return True + + def on_btn_cancel_clicked(self, widget): + if self.__builder.get_object('btn_apply').get_state() == \ + Gtk.StateType.INSENSITIVE: + Gtk.main_quit() + return True + dlg = self.__builder.get_object('quit_check_without_save') + dlg.set_markup('<big><b>%s</b></big>' % _("Notice!")) + dlg.format_secondary_text( + _("You are about to close the setup dialog without saving your changes, is that OK?")) + id = dlg.run() + dlg.hide() + if id == Gtk.ResponseType.YES: + Gtk.main_quit() + return True + + def on_btn_apply_clicked(self, widget): + self.__save_preferences() + widget.set_sensitive(False) + + def on_cb_changed(self, widget): + section, key = self.__get_section_key(Gtk.Buildable.get_name(widget)) + self.prefs.set_value(section, key, widget.get_active()) + self.__builder.get_object('btn_apply').set_sensitive(True) + + def on_cb_keymap_changed(self, widget, id): + it = widget.get_active() + model = widget.get_model() + keymap = model[it][0] + if keymap == _("Default"): + keymap = 'default' + if self.__keymap == keymap: + return + self.__keymap = keymap + self.__builder.get_object('btn_apply').set_sensitive(True) + + def on_cb_custom_key_table_changed(self, widget, user_data): + prefs = self.prefs + tv = self.__builder.get_object('treeview_custom_key_table') + mode = user_data + id = widget.get_active() + model = widget.get_model() + method = model[id][1] + if tv != None: + for column in tv.get_columns(): + tv.remove_column(column) + for child in tv.get_children(): + tv.remove(child) + if mode == 'romaji': + tv = self.__get_romaji_treeview_custom_key_table(method) + elif mode == 'kana': + prefs.set_value('kana_typing_rule', 'method', method) + self.__builder.get_object('btn_apply').set_sensitive(True) + tv = self.__get_kana_treeview_custom_key_table(method) + elif mode == 'thumb': + # thumb uses all tables so do not save the method. + tv = self.__get_thumb_treeview_custom_key_table(method) + + def on_sb_changed(self, widget): + section, key = self.__get_section_key(Gtk.Buildable.get_name(widget)) + self.prefs.set_value(section, key, widget.get_value_as_int()) + self.__builder.get_object('btn_apply').set_sensitive(True) + + def on_ck_toggled(self, widget): + section, key = self.__get_section_key(Gtk.Buildable.get_name(widget)) + self.prefs.set_value(section, key, widget.get_active()) + self.__builder.get_object('btn_apply').set_sensitive(True) + if self.__thumb_kb_layout_mode and \ + Gtk.Buildable.get_name(widget) == \ + Gtk.Buildable.get_name(self.__thumb_kb_layout_mode): + self.__set_thumb_kb_label() + + def on_btn_edit_clicked(self, widget): + ls, it = self.__builder.get_object('shortcut').get_selection().get_selected() + m = self.__builder.get_object('es:treeview').get_model() + m.clear() + for s in s_to_l(ls.get(it, 1)[0]): + m.append([s]) + self.__builder.get_object('es:entry').set_text('') + for w in ['es:checkbutton_ctrl', 'es:checkbutton_alt', 'es:checkbutton_shift']: + self.__builder.get_object(w).set_active(False) + dlg = self.__builder.get_object('edit_shortcut') + id = dlg.run() + dlg.hide() + if id == Gtk.ResponseType.OK: + new = l_to_s([m[i][0] for i in range(len(m))]) + if new != ls.get(it, 1)[0]: + sec = self._get_shortcut_sec() + self.prefs.set_value(sec, ls.get(it, 0)[0], s_to_l(new)) + ls.set(it, 1, new) + self.__builder.get_object('btn_apply').set_sensitive(True) + + def on_btn_default_clicked(self, widget): + ls, it = self.__builder.get_object('shortcut').get_selection().get_selected() + sec = self._get_shortcut_sec() + new = l_to_s(self.prefs.default[sec][ls.get(it, 0)[0]]) + if new != ls.get(it, 1)[0]: + self.prefs.set_value(sec, ls.get(it, 0)[0], s_to_l(new)) + ls.set(it, 1, new) + self.__builder.get_object('btn_apply').set_sensitive(True) + + def on_btn_romaji_custom_table_clicked(self, widget): + self.__run_dialog_custom_key_table('romaji') + + def on_btn_kana_custom_table_clicked(self, widget): + self.__run_dialog_custom_key_table('kana') + + def on_btn_thumb_custom_table_clicked(self, widget): + self.__run_dialog_custom_key_table('thumb') + + def on_btn_add_custom_key(self, widget, user_data): + prefs = self.prefs + input = self.__builder.get_object('entry_input_custom_key') + output = self.__builder.get_object('entry_output_custom_key') + left = self.__builder.get_object('entry_left_thumb_shift_custom_key') + right = self.__builder.get_object('entry_right_thumb_shift_custom_key') + model = self.__builder.get_object('treeview_custom_key_table').get_model() + combobox = self.__builder.get_object('combobox_custom_key_table') + id = combobox.get_active() + model_combobox = combobox.get_model() + method = model_combobox[id][1] + type = user_data + section_base = None + key = input.get_text() + value = output.get_text() + left_text = left.get_text() + right_text = right.get_text() + + if key == None: + self.__run_message_dialog(_("Please specify Input Chars")) + return + elif value == None: + self.__run_message_dialog(_("Please specify Output Chars")) + return + elif type == 'thumb' and left_text == None: + self.__run_message_dialog(_("Please specify Left Thumb Shift Chars")) + return + elif type == 'thumb' and right_text == None: + self.__run_message_dialog(_("Please specify Right Thumb Shift Chars")) + return + + if type == 'romaji': + section_base = 'romaji_typing_rule' + model.append([type, key, value]) + elif type == 'kana': + section_base = 'kana_typing_rule' + model.append([type, key, value]) + elif type == 'thumb': + section_base = 'thumb_typing_rule' + model.append([type, key, value, left_text, right_text]) + if section_base == None: + self.__run_message_dialog(_("Your custom key is not assigned in any sections. Maybe a bug.")) + return + gkey = prefs.typing_to_config_key(key) + if gkey == '': + return + key = gkey + section = section_base + '/' + method + if key not in prefs.keys(section): + # ibus does not support gconf_client_all_entries(). + # prefs.fetch_section() doesn't get the keys if they exist + # in gconf only. + # Use newkeys for that way. + newkeys = prefs.get_value(section_base, 'newkeys') + if key not in newkeys: + newkeys.append(key) + prefs.set_value(section_base, 'newkeys', newkeys) + if type != 'thumb': + prefs.set_value(section, key, value) + else: + prefs.set_value(section, key, [value, right_text, left_text]) + left.set_text('') + right.set_text('') + input.set_text('') + output.set_text('') + self.__builder.get_object('btn_apply').set_sensitive(True) + + def on_btn_remove_custom_key(self, widget, user_data): + prefs = self.prefs + combobox = self.__builder.get_object('combobox_custom_key_table') + id = combobox.get_active() + model_combobox = combobox.get_model() + method = model_combobox[id][1] + tv = user_data + l, i = tv.get_selection().get_selected() + type = l[i][0] + key = l[i][1] + section_base = None + if type == 'romaji': + section_base = 'romaji_typing_rule' + elif type == 'kana': + section_base = 'kana_typing_rule' + elif type == 'thumb': + section_base = 'thumb_typing_rule' + if section_base == None: + self.__run_message_dialog(_("Your custom key is not assigned in any sections. Maybe a bug.")) + return + section = section_base + '/' + method + newkeys = prefs.get_value(section_base, 'newkeys') + gkey = prefs.typing_to_config_key(key) + if gkey == '': + return + key = gkey + if key in newkeys: + newkeys.remove(key) + prefs.set_value(section_base, 'newkeys', newkeys) + # config.set_value(key, None) is not supported. + if type != 'thumb': + prefs.set_value(section, key, '') + else: + prefs.set_value(section, key, ['', '', '']) + l.remove(i) + widget.set_sensitive(False) + self.__builder.get_object('btn_apply').set_sensitive(True) + + def on_btn_thumb_key_clicked(self, widget): + if Gtk.Buildable.get_name(widget) == 'thumb:button_ls': + entry = 'thumb:ls' + elif Gtk.Buildable.get_name(widget) == 'thumb:button_rs': + entry = 'thumb:rs' + else: + return + text = self.__builder.get_object(entry).get_text() + tv = self.__builder.get_object('es:treeview') + m = tv.get_model() + m.clear() + if text != None: + m.append([text]) + i = m.get_iter_first() + tv.get_selection().select_iter(i) + self.__builder.get_object('es:entry').set_text('') + self.__builder.get_object('es:button_add').hide() + self.__builder.get_object('es:button_refresh').show() + self.__builder.get_object('es:button_del').hide() + for w in ['es:checkbutton_ctrl', 'es:checkbutton_alt', 'es:checkbutton_shift']: + self.__builder.get_object(w).set_active(False) + dlg = self.__builder.get_object('edit_shortcut') + id = dlg.run() + dlg.hide() + self.__builder.get_object('es:button_add').show() + self.__builder.get_object('es:button_refresh').hide() + self.__builder.get_object('es:button_del').show() + if id == Gtk.ResponseType.OK: + l, i = tv.get_selection().get_selected() + new = l[i][0] + if new != text: + section, key = self.__get_section_key(entry) + self.prefs.set_value(section, key, new) + self.__builder.get_object(entry).set_text(new) + self.__builder.get_object('btn_apply').set_sensitive(True) + + def on_btn_dict_command_clicked(self, widget): + if Gtk.Buildable.get_name(widget) == 'dict:btn_edit_dict_command': + key = 'dict_admin_command' + elif Gtk.Buildable.get_name(widget) == 'dict:btn_add_word_command': + key = 'add_word_command' + else: + return + command = self.prefs.get_value('common', key) + if not path.exists(command[0]): + self.__run_message_dialog(_("Your file does not exist: ") + command[0], + Gtk.MessageType.ERROR) + return + os.spawnl(os.P_NOWAIT, *command) + + def on_btn_dict_add_clicked(self, widget): + file = None + id = None + + if Gtk.Buildable.get_name(widget) == 'dict:btn_add': + dlg = Gtk.FileChooserDialog(title=_("Open Dictionary File"), + parent=self.__builder.get_object('main'), + action=Gtk.FileChooserAction.OPEN, + buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, + Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) + if Gtk.Buildable.get_name(widget) == 'dict:btn_edit': + dlg = Gtk.Dialog(title=_("Edit Dictionary File"), + parent=self.__builder.get_object('main'), + flags=Gtk.DialogFlags.MODAL, + buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, + Gtk.STOCK_OK, Gtk.ResponseType.OK)) + + vbox = self.__builder.get_object('dict:add_extra_vbox') + if Gtk.Buildable.get_name(widget) == 'dict:btn_add': + # Need to init for the second time + self.__init_dict_chooser_dialog() + dlg.set_extra_widget(vbox) + if Gtk.Buildable.get_name(widget) == 'dict:btn_edit': + id = self.__set_selected_dict_to_dialog() + if id == None: + self.__run_message_dialog(_("Your choosed file is not correct."), + Gtk.MessageType.ERROR) + return + parent_vbox = dlg.vbox + parent_vbox.add(vbox) + vbox.show_all() + + if dlg.run() == Gtk.ResponseType.OK: + if Gtk.Buildable.get_name(widget) == 'dict:btn_add': + file = dlg.get_filename() + if file[0] != '/': + dir = dlg.get_current_folder() + file = dir + '/' + file + self.__append_user_dict_from_dialog(file, None, True) + elif Gtk.Buildable.get_name(widget) == 'dict:btn_edit': + self.__append_user_dict_from_dialog(None, id, False) + dlg.hide() + vbox.unparent() + + def on_btn_dict_delete_clicked(self, widget): + l, i = self.__builder.get_object('dict:view').get_selection().get_selected() + + if not i: + return + selected_id = l.get_value(i, 0) + + if selected_id == None: + return + if self.__is_system_dict_file_from_id(selected_id): + self.__run_message_dialog(_("You cannot delete the system dictionary."), + Gtk.MessageType.ERROR) + return + + file = self.__get_dict_file_from_id(selected_id) + if file != None: + files = self.prefs.get_value('dict', 'files') + files.remove(file) + self.prefs.set_value('dict', 'files', files) + self.__builder.get_object('btn_apply').set_sensitive(True) + l.remove(i) + return + + l.remove(i) + + def on_btn_dict_view_clicked(self, widget): + dict_file = None + selected_id = self.__get_selected_dict_id() + if selected_id == None: + return + + dict_file = self.__get_dict_file_from_id(selected_id) + if dict_file == None: + self.__run_message_dialog(_("Your file is not good."), + Gtk.MessageType.ERROR) + return + if not path.exists(dict_file): + self.__run_message_dialog(_("Your file does not exist: ") + dict_file, + Gtk.MessageType.ERROR) + return + + if dict_file == None: + return + + # The selected id is already quoted. + section = 'dict/file/' + selected_id + if 'preview_lines' not in self.prefs.keys(section): + section = 'dict/file/default' + nline = self.prefs.get_value(section, 'preview_lines') + + section = 'dict/file/' + selected_id + if 'encoding' not in self.prefs.keys(section): + section = 'dict/file/default' + encoding = self.prefs.get_value(section, 'encoding') + + lines = ''; + for i, line in enumerate(list(codecs.open(dict_file, 'r', 'utf-8'))): + if nline >= 0 and i >= nline: + break; + lines = lines + line + if encoding != None and encoding != 'utf-8': + lines = str(lines, encoding) + + dlg = Gtk.Dialog(title=_("View Dictionary File"), + parent=self.__builder.get_object('main'), + flags=Gtk.DialogFlags.MODAL, + buttons=(Gtk.STOCK_OK, Gtk.ResponseType.OK)) + buffer = Gtk.TextBuffer() + buffer.set_text (lines) + text_view = Gtk.TextView.new_with_buffer(buffer) + text_view.set_editable(False) + sw = Gtk.ScrolledWindow() + sw.add(text_view) + sw.set_min_content_height(400) + parent_vbox = dlg.vbox + parent_vbox.add(sw) + sw.show_all() + dlg.set_default_size(500, 500) + dlg.run() + dlg.destroy() + + def on_btn_dict_order_clicked(self, widget): + dict_file = None + l, it = self.__builder.get_object('dict:view').get_selection().get_selected() + + if not it: + return + selected_path = l.get_path(it) + selected_id = l.get_value(it, 0) + index = selected_path.get_indices()[0] + + if Gtk.Buildable.get_name(widget) == 'dict:btn_up': + if index <= 0: + return + next_path = (index - 1, ) + elif Gtk.Buildable.get_name(widget) == 'dict:btn_down': + if index + 1 >= len(l): + return + next_path = (index + 1, ) + next_it = l.get_iter(next_path) + if next_it: + l.swap(it, next_it) + + dict_file = self.__get_dict_file_from_id(selected_id) + files = self.prefs.get_value('dict', 'files') + + if dict_file == None: + return + + i = files.index(dict_file) + if Gtk.Buildable.get_name(widget) == 'dict:btn_up': + if i <= 0: + return + next_i = i - 1 + elif Gtk.Buildable.get_name(widget) == 'dict:btn_down': + if i + 1 >= len(dict_file): + return + next_i = i + 1 + f = files[i] + files[i] = files[next_i] + files[next_i] = f + self.prefs.set_value('dict', 'files', files) + self.__builder.get_object('btn_apply').set_sensitive(True) + + def _get_shortcut_sec(self): + l = ['default', 'atok', 'wnn'] + iter = self.__builder.get_object('shortcut_type').get_active_iter() + model = self.__builder.get_object('shortcut_type').get_model() + s_type = model[iter][0].lower() + return 'shortcut/' + (s_type if s_type in l else 'default') + + def on_shortcut_type_changed(self, widget): + ls = self.__builder.get_object('shortcut').get_model() + ls.clear() + + sec = self._get_shortcut_sec() + for k in self.prefs.keys(sec): + ls.append([k, l_to_s(self.prefs.get_value(sec, k))]) + + section, key = self.__get_section_key(Gtk.Buildable.get_name(widget)) + self.prefs.set_value(section, key, sec[len('shortcut/'):]) + self.__builder.get_object('btn_apply').set_sensitive(True) + + def on_shortcut_key_release_event(self, widget, event): + if event.hardware_keycode in [36, 65]: + self.on_btn_edit_clicked(None) + + def on_shortcut_click_event(self, widget, event): + if event.type == Gdk.EventType._2BUTTON_PRESS: + widget.dc = True + elif event.type == Gdk.EventType.BUTTON_RELEASE: + if hasattr(widget, 'dc') and widget.dc: + self.on_btn_edit_clicked(None) + widget.dc = False + + def on_key_input_dialog_key_press_event(self, widget, event): + widget.e = (event.keyval, event.get_state()) + return True + + def on_key_input_dialog_key_release_event(self, widget, event): + widget.response(Gtk.ResponseType.OK) + return True + + def on_entry_custom_key_changed(self, widget, user_data): + mode = user_data + input = self.__builder.get_object('entry_input_custom_key') + output = self.__builder.get_object('entry_output_custom_key') + left = self.__builder.get_object('entry_left_thumb_shift_custom_key') + right = self.__builder.get_object('entry_right_thumb_shift_custom_key') + button = self.__builder.get_object('button_add_custom_key') + if mode != 'thumb': + if input.get_text() != '' and output.get_text() != '': + button.set_sensitive(True) + else: + button.set_sensitive(False) + else: + if input.get_text() != '' and output.get_text() != '' and \ + left.get_text() != '' and right.get_text() != '': + button.set_sensitive(True) + else: + button.set_sensitive(False) + + def on_entry_dict_command_changed(self, widget): + if not widget.get_text(): + return + list = widget.get_text().split() + if list[0][0] == '/': + if len(list) == 1: + list.append(list[0][list[0].rfind('/') + 1:]) + else: + list.insert(1, list[0][list[0].rfind('/') + 1:]) + else: + if len(list) == 1: + list[0] = '/usr/bin/' + list[0] + else: + list.insert(0, '/usr/bin/' + list[0]) + list[1] = list[1][list[1].rfind('/') + 1:] + if Gtk.Buildable.get_name(widget) == 'dict:entry_edit_dict_command': + key = 'dict_admin_command' + elif Gtk.Buildable.get_name(widget) == 'dict:entry_add_word_command': + key = 'add_word_command' + else: + return + self.prefs.set_value('common', key, list) + self.__builder.get_object('btn_apply').set_sensitive(True) + + def on_es_entry_changed(self, widget): + if not widget.get_text(): + self.__builder.get_object('es:button_add').set_sensitive(False) + else: + self.__builder.get_object('es:button_add').set_sensitive(True) + + def on_es_button_run_input_clicked(self, widget): + dlg = self.__builder.get_object('key_input_dialog') + dlg.set_markup('<big><b>%s</b></big>' % _("Please press a key (or a key combination)")) + dlg.format_secondary_text(_("The dialog will be closed when the key is released")) + id = dlg.run() + dlg.hide() + if id == Gtk.ResponseType.OK: + key, state = dlg.e + if (state & (IBus.ModifierType.CONTROL_MASK | IBus.ModifierType.MOD1_MASK) and + ord('a') <= key <= ord('z')): + key = ord(chr(key).upper()) + self.__builder.get_object('es:entry').set_text(IBus.keyval_name(key)) + + for w, i in [('es:checkbutton_ctrl', IBus.ModifierType.CONTROL_MASK), + ('es:checkbutton_alt', IBus.ModifierType.MOD1_MASK), + ('es:checkbutton_shift', IBus.ModifierType.SHIFT_MASK)]: + self.__builder.get_object(w).set_active(True if state & i else False) + + def on_es_button_add_clicked(self, widget): + s = self.__builder.get_object('es:entry').get_text() + if not s or not IBus.keyval_from_name(s): + dlg = self.__builder.get_object('invalid_keysym') + dlg.set_markup('<big><b>%s</b></big>' % _("Invalid keysym")) + dlg.format_secondary_text(_("This keysym is not valid")) + dlg.run() + dlg.hide() + return True + for w, m in [('es:checkbutton_ctrl', 'Ctrl+'), + ('es:checkbutton_alt', 'Alt+'), + ('es:checkbutton_shift', 'Shift+')]: + if self.__builder.get_object(w).get_active(): + s = m + s + l = self.__builder.get_object('es:treeview').get_model() + for i in range(len(l)): + if l[i][0] == s: + return True + l.append([s]) + + def on_es_button_refresh_clicked(self, widget): + s = self.__builder.get_object('es:entry').get_text() + if not s or not IBus.keyval_from_name(s): + dlg = self.__builder.get_object('invalid_keysym') + dlg.set_markup('<big><b>%s</b></big>' % _("Invalid keysym")) + dlg.format_secondary_text(_("This keysym is not valid")) + dlg.run() + dlg.hide() + return True + for w, m in [('es:checkbutton_ctrl', 'Ctrl+'), + ('es:checkbutton_alt', 'Alt+'), + ('es:checkbutton_shift', 'Shift+')]: + if self.__builder.get_object(w).get_active(): + s = m + s + tv = self.__builder.get_object('es:treeview') + l, i = tv.get_selection().get_selected() + l[i][0] = s + return True + + def on_es_button_del_clicked(self, widget): + tv = self.__builder.get_object('es:treeview') + l, i = tv.get_selection().get_selected() + if i: + l.remove(i) + + def run(self): + Gtk.main() + +if __name__ == '__main__': + AnthySetup().run() + diff --git a/setup/python3/prefs.py b/setup/python3/prefs.py new file mode 100644 index 0000000..a4af88d --- /dev/null +++ b/setup/python3/prefs.py @@ -0,0 +1,273 @@ +# vim:set noet ts=4: +# +# ibus-anthy - The Anthy engine for IBus +# +# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com> +# Copyright (c) 2009 Hideaki ABE <abe.sendai@gmail.com> +# Copyright (c) 2010-2014 Takao Fujiwara <takao.fujiwara1@gmail.com> +# Copyright (c) 2007-2014 Red Hat, Inc. +# +# 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 of the License, 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import sys + +from gi.repository import GLib +from gi.repository import IBus + +class Prefs(object): + _prefix = 'engine/dummy' + + def __init__(self, bus=None, config=None): + self.default = {} + self.modified = {} + self.new = {} + self.__no_key_warning = False + + # self._config is used by AnthyPrefs . + self._config = config if config else \ + bus.get_config() if bus else \ + IBus.Bus().get_config() + + # ibus_config_get_values enhances the performance. + self.__has_config_get_values = False + + if self._config != None: + self.__has_config_get_values = hasattr(self._config, 'get_values') + else: + self.printerr( + 'ibus-config is not running or bus address is not correct.') + + def __log_handler(self, domain, level, message, data): + if not data: + return + GLib.log_default_handler(domain, level, message, '') + + def variant_to_value(self, variant): + if type(variant) != GLib.Variant: + return variant + type_string = variant.get_type_string() + if type_string == 's': + return variant.get_string() + elif type_string == 'i': + return variant.get_int32() + elif type_string == 'b': + return variant.get_boolean() + elif type_string == 'as': + # Use unpack() instead of dup_strv() in python. + # In the latest pygobject3 3.3.4 or later, g_variant_dup_strv + # returns the allocated strv but in the previous release, + # it returned the tuple of (strv, length) + return variant.unpack() + else: + self.printerr('Unknown variant type: %s' % type_string) + sys.abrt() + return variant + + def set_no_key_warning(self, no_key_warning): + if no_key_warning and hasattr(IBus, 'unset_log_handler'): + self.__no_key_warning = True + else: + self.__no_key_warning = False + + def keys(self, section): + return list(self.default[section].keys()) + + def sections(self): + return list(self.default.keys()) + + def set_new_section(self, section): + self.default.setdefault(section, {}) + + def set_new_key(self, section, key): + self.default[section].setdefault(key) + + def get_value(self, section, key): + try: + return self.new[section][key] + except: + try: + return self.modified[section][key] + except: + return self.default[section][key] + + def get_value_direct(self, section, key, default=None): + if self._config == None: + return default + + s = section + section = '/'.join( + [s for s in '/'.join([self._prefix, section]).split('/') if s]) + try: + if self.__no_key_warning: + IBus.set_log_handler(False) + variant = self._config.get_value(section, key) + if self.__no_key_warning: + IBus.unset_log_handler() + return self.variant_to_value(variant) + except: + return default + + def set_value(self, section, key, value): + if section not in self.sections(): + self.set_new_section(section) + if key not in self.keys(section): + self.set_new_key(section, key) + self.default[section][key] + self.new.setdefault(section, {})[key] = value + + def fetch_all(self): + for s in self.sections(): + self.fetch_section(s) + + def fetch_section(self, section): + if self._config == None: + return + + if not self.__has_config_get_values: + for k in self.keys(section): + self.fetch_item(section, k) + return + + s = '/'.join( + [s for s in '/'.join([self._prefix, section]).split('/') if s]) + variant = self._config.get_values(s) + for key in list(variant.keys()): + v = variant[key] + self.modified.setdefault(section, {})[key] = v if v != [''] else [] + # FIXME: ibus-dconf converts the keys. + if section == 'common': + self.fetch_item(section, 'show-input-mode') + self.fetch_item(section, 'show-typing-method') + self.fetch_item(section, 'show-segment-mode') + self.fetch_item(section, 'show-dict-mode') + self.fetch_item(section, 'show-dict-config') + self.fetch_item(section, 'show-preferences') + + def fetch_item(self, section, key, readonly=False): + if self._config == None: + return + + s = '/'.join( + [s for s in '/'.join([self._prefix, section]).split('/') if s]) + try: + v = None + # gobject-introspection has a bug. + # https://bugzilla.gnome.org/show_bug.cgi?id=670509 + # GLib.log_set_handler("IBUS", GLib.LogLevelFlags.LEVEL_MASK, + # self.__log_handler, False) + if self.__no_key_warning: + IBus.set_log_handler(False) + variant = self._config.get_value(s, key) + if self.__no_key_warning: + IBus.unset_log_handler() + v = self.variant_to_value(variant) + except: + v = None + if readonly: + return v != None + if v != None: + self.modified.setdefault(section, {})[key] = v if v != [''] else [] + return True + + def commit_all(self): + for s in list(self.new.keys()): + self.commit_section(s) + + def commit_section(self, section): + if section in self.new: + for k in list(self.new[section].keys()): + self.commit_item(section, k) + + def commit_item(self, section, key): + if section in self.new and key in self.new[section]: + s = '/'.join( + [s for s in '/'.join([self._prefix, section]).split('/') if s]) + v = self.new[section][key] + if v == []: + v = [''] + variant = None + if type(v) == str: + variant = GLib.Variant.new_string(v) + elif type(v) == int: + variant = GLib.Variant.new_int32(v) + elif type(v) == bool: + variant = GLib.Variant.new_boolean(v) + elif type(v) == list: + variant = GLib.Variant.new_strv(v) + if variant == None: + self.printerr('Unknown value type: %s' % type(v)) + sys.abrt() + if self._config != None: + self._config.set_value(s, key, variant) + self.modified.setdefault(section, {})[key] = v + del(self.new[section][key]) + + def undo_all(self): + self.new.clear() + + def undo_section(self, section): + try: + del(self.new[section]) + except: + pass + + def undo_item(self, section, key): + try: + del(self.new[section][key]) + except: + pass + + def set_default_all(self): + for s in self.sections(): + self.set_default_section(s) + + def set_default_section(self, section): + for k in self.keys(section): + self.set_default_item(section, k) + + def set_default_item(self, section, key): + try: + if key in self.modified[section] or key in self.new[section]: + self.new[section][key] = self.default[section][key] + except: + pass + + # Convert DBus.String to str + # sys.getdefaultencoding() == 'utf-8' with pygtk2 but + # sys.getdefaultencoding() == 'ascii' with gi gtk3 + # so the simple str(unicode_string) causes an error and need to use + # unicode_string.encode('utf-8') instead. + def str(self, uni): + if uni == None: + return None + if type(uni) == str: + return uni + return str(uni) + + # The simple unicode(string) causes an error and need to use + # unicode(string, 'utf-8') instead. + def unicode(self, string): + if string == None: + return None + return string + + # If the parent process exited, the std io/out/error will be lost. + @staticmethod + def printerr(sentence): + try: + print(sentence, file=sys.stderr) + except IOError: + pass + diff --git a/setup/python3/setup.ui b/setup/python3/setup.ui new file mode 100644 index 0000000..d9ec626 --- /dev/null +++ b/setup/python3/setup.ui @@ -0,0 +1,2813 @@ +<?xml version="1.0"?> +<interface> + <object class="GtkAdjustment" id="adjustment1"> + <property name="upper">10</property> + <property name="lower">0</property> + <property name="page_increment">0</property> + <property name="step_increment">1</property> + <property name="page_size">0</property> + <property name="value">10</property> + </object> + <object class="GtkListStore" id="model1"> + <columns> + <column type="gchararray"/> + </columns> + <data> + <row> + <col id="0" translatable="yes">Hiragana</col> + </row> + <row> + <col id="0" translatable="yes">Katakana</col> + </row> + <row> + <col id="0" translatable="yes">Halfwidth Katakana</col> + </row> + <row> + <col id="0" translatable="yes">Latin</col> + </row> + <row> + <col id="0" translatable="yes">Wide Latin</col> + </row> + </data> + </object> + <object class="GtkListStore" id="model51"> + <columns> + <column type="gchararray"/> + </columns> + <data> + <row> + <col id="0" translatable="yes">NICOLA-J</col> + </row> + <row> + <col id="0" translatable="yes">NICOLA-A</col> + </row> + <row> + <col id="0" translatable="yes">NICOLA-F</col> + </row> + </data> + </object> + <object class="GtkListStore" id="model11"> + <columns> + <column type="gchararray"/> + </columns> + <data> + <row> + <col id="0" translatable="yes">None</col> + </row> + <row> + <col id="0" translatable="yes">FMV KB231 key extension</col> + </row> + <row> + <col id="0" translatable="yes">FMV KB611 key extension</col> + </row> + </data> + </object> + <object class="GtkListStore" id="model2"> + <columns> + <column type="gchararray"/> + </columns> + <data> + <row> + <col id="0" translatable="yes">Romaji</col> + </row> + <row> + <col id="0" translatable="yes">Kana</col> + </row> + <row> + <col id="0" translatable="yes">Thumb shift</col> + </row> + </data> + </object> + <object class="GtkListStore" id="model3"> + <columns> + <column type="gchararray"/> + </columns> + <data> + <row> + <col id="0" translatable="yes">Multiple segment</col> + </row> + <row> + <col id="0" translatable="yes">Single segment</col> + </row> + <row> + <col id="0" translatable="yes">Immediate conversion (multiple segment)</col> + </row> + <row> + <col id="0" translatable="yes">Immediate conversion (single segment)</col> + </row> + </data> + </object> + <object class="GtkListStore" id="model4"> + <columns> + <column type="gchararray"/> + </columns> + <data> + <row> + <col id="0" translatable="yes">Keep numpad codes</col> + </row> + <row> + <col id="0" translatable="yes">Convert characters</col> + </row> + </data> + </object> + <object class="GtkListStore" id="model5"> + <columns> + <column type="gchararray"/> + </columns> + <data> + <row> + <col id="0">「」/</col> + </row> + <row> + <col id="0">「」・</col> + </row> + <row> + <col id="0">[]/</col> + </row> + <row> + <col id="0">[]・</col> + </row> + </data> + </object> + <object class="GtkListStore" id="model6"> + <columns> + <column type="gchararray"/> + </columns> + <data> + <row> + <col id="0">、。</col> + </row> + <row> + <col id="0">,.</col> + </row> + </data> + </object> + <object class="GtkListStore" id="model7"> + <columns> + <column type="gchararray"/> + </columns> + <data> + <row> + <col id="0" translatable="yes">Do nothing</col> + </row> + <row> + <col id="0" translatable="yes">Automatically convert</col> + </row> + </data> + </object> + <object class="GtkListStore" id="model8"> + <columns> + <column type="gchararray"/> + </columns> + <data> + <row> + <col id="0" translatable="yes">Clear</col> + </row> + <row> + <col id="0" translatable="yes">Commit</col> + </row> + <row> + <col id="0" translatable="yes">Hold</col> + </row> + </data> + </object> + <object class="GtkListStore" id="model9"> + <columns> + <column type="gchararray"/> + </columns> + <data> + <row> + <col id="0" translatable="yes">Default</col> + </row> + <row> + <col id="0" translatable="yes">ATOK</col> + </row> + <row> + <col id="0" translatable="yes">Wnn</col> + </row> + </data> + </object> + <!-- interface-requires gtk+ 2.16 --> + <!-- interface-naming-policy toplevel-contextual --> + <object class="GtkDialog" id="main"> + <property name="visible">False</property> + <property name="title" translatable="yes">Setup - IBus-Anthy</property> + <property name="type_hint">dialog</property> + <signal handler="on_main_delete" name="delete_event"/> + <child internal-child="vbox"> + <object class="GtkVBox" id="dialog-vbox1"> + <property name="visible">True</property> + <child> + <object class="GtkNotebook" id="notebook1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="border_width">6</property> + <child> + <object class="GtkVBox" id="vbox1"> + <property name="visible">True</property> + <property name="border_width">8</property> + <child> + <object class="GtkFrame" id="frame11"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignment11"> + <property name="visible">True</property> + <property name="top_padding">8</property> + <property name="bottom_padding">8</property> + <property name="left_padding">12</property> + <child> + <object class="GtkTable" id="table11"> + <property name="visible">True</property> + <property name="n_rows">3</property> + <property name="n_columns">2</property> + <property name="column_spacing">8</property> + <property name="row_spacing">4</property> + <child> + <object class="GtkLabel" id="label101"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">_Input Mode:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">input_mode</property> + </object> + <packing> + <property name="x_options">GTK_FILL</property> + <property name="y_options"/> + </packing> + </child> + <child> + <object class="GtkComboBox" id="input_mode"> + <property name="visible">True</property> + <signal handler="on_cb_changed" name="changed"/> + <property name="model">model1</property> + <child> + <object class="GtkCellRendererText" id="renderer1"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="y_options"/> + </packing> + </child> + <child> + <object class="GtkLabel" id="label102"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">_Typing Method:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">typing_method</property> + </object> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"/> + </packing> + </child> + <child> + <object class="GtkComboBox" id="typing_method"> + <property name="visible">True</property> + <signal handler="on_cb_changed" name="changed"/> + <property name="model">model2</property> + <child> + <object class="GtkCellRendererText" id="renderer2"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </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> + <property name="y_options"/> + </packing> + </child> + <child> + <object class="GtkLabel" id="label103"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Conversion _Mode:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">conversion_segment_mode</property> + </object> + <packing> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"/> + </packing> + </child> + <child> + <object class="GtkComboBox" id="conversion_segment_mode"> + <property name="visible">True</property> + <signal handler="on_cb_changed" name="changed"/> + <property name="model">model3</property> + <child> + <object class="GtkCellRendererText" id="renderer3"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </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> + <property name="y_options"/> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label151"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Initial Setting</b></property> + <property name="use_markup">True</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkFrame" id="frame12"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignment12"> + <property name="visible">True</property> + <property name="top_padding">8</property> + <property name="bottom_padding">8</property> + <property name="left_padding">12</property> + <child> + <object class="GtkVBox" id="vbox12"> + <property name="visible">True</property> + <property name="border_width">4</property> + <property name="spacing">4</property> + <child> + <object class="GtkScrolledWindow" id="scrolledwindow12"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="height_request">200</property> + <property name="hscrollbar_policy">automatic</property> + <property name="vscrollbar_policy">automatic</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTreeView" id="menu_visible:treeview"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </object> + </child> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label152"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Menu Visibility on Status Icon</b></property> + <property name="use_markup">True</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + <child type="tab"> + <object class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="label" translatable="yes">General</property> + <property name="mnemonic_widget">vbox1</property> + </object> + <packing> + <property name="tab_fill">False</property> + </packing> + </child> + <child> + <object class="GtkVBox" id="vbox2"> + <property name="visible">True</property> + <property name="border_width">8</property> + <child> + <object class="GtkFrame" id="frame21"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignment21"> + <property name="visible">True</property> + <property name="top_padding">8</property> + <property name="bottom_padding">8</property> + <property name="left_padding">12</property> + <child> + <object class="GtkTable" id="table21"> + <property name="visible">True</property> + <property name="n_rows">5</property> + <property name="n_columns">2</property> + <property name="column_spacing">8</property> + <property name="row_spacing">4</property> + <child> + <object class="GtkLabel" id="label104"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">_Period Style:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">period_style</property> + </object> + <packing> + <property name="x_options">GTK_FILL</property> + <property name="y_options"/> + </packing> + </child> + <child> + <object class="GtkLabel" id="label105"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Symbo_l Style:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">symbol_style</property> + </object> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"/> + </packing> + </child> + <child> + <object class="GtkLabel" id="label106"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Numpad _Key Type:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">ten_key_mode</property> + </object> + <packing> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"/> + </packing> + </child> + <child> + <object class="GtkComboBox" id="ten_key_mode"> + <property name="visible">True</property> + <signal handler="on_cb_changed" name="changed"/> + <property name="model">model4</property> + <child> + <object class="GtkCellRendererText" id="renderer4"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </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> + <property name="y_options"/> + </packing> + </child> + <child> + <object class="GtkComboBox" id="symbol_style"> + <property name="visible">True</property> + <signal handler="on_cb_changed" name="changed"/> + <property name="model">model5</property> + <child> + <object class="GtkCellRendererText" id="renderer5"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </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> + <property name="y_options"/> + </packing> + </child> + <child> + <object class="GtkComboBox" id="period_style"> + <property name="visible">True</property> + <signal handler="on_cb_changed" name="changed"/> + <property name="model">model6</property> + <child> + <object class="GtkCellRendererText" id="renderer6"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="y_options"/> + </packing> + </child> + <child> + <object class="GtkLabel" id="label107"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">_Behavior on Period:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">behavior_on_period</property> + </object> + <packing> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"/> + </packing> + </child> + <child> + <object class="GtkLabel" id="label108"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Behavior on _Focus Out:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">behavior_on_focus_out</property> + </object> + <packing> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"/> + </packing> + </child> + <child> + <object class="GtkComboBox" id="behavior_on_period"> + <property name="visible">True</property> + <signal handler="on_cb_changed" name="changed"/> + <property name="model">model7</property> + <child> + <object class="GtkCellRendererText" id="renderer7"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </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> + <property name="y_options"/> + </packing> + </child> + <child> + <object class="GtkComboBox" id="behavior_on_focus_out"> + <property name="visible">True</property> + <signal handler="on_cb_changed" name="changed"/> + <property name="model">model8</property> + <child> + <object class="GtkCellRendererText" id="renderer8"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </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> + <property name="y_options"/> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label201"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Behavior</b></property> + <property name="use_markup">True</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkFrame" id="frame22"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignment22"> + <property name="visible">True</property> + <property name="top_padding">8</property> + <property name="bottom_padding">8</property> + <property name="left_padding">12</property> + <child> + <object class="GtkTable" id="table22"> + <property name="visible">True</property> + <property name="n_rows">4</property> + <property name="column_spacing">8</property> + <property name="row_spacing">4</property> + <child> + <object class="GtkHBox" id="hbox4"> + <property name="visible">True</property> + <property name="spacing">8</property> + <child> + <object class="GtkLabel" id="label109"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Candidate _Window Page Size:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">page_size</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="page_size"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="adjustment">adjustment1</property> + <property name="climb_rate">0.97999999999999998</property> + <signal handler="on_sb_changed" name="value_changed"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="y_options"/> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="half_width_symbol"> + <property name="label" translatable="yes">Convert _symbols with the one column width</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> + <signal handler="on_ck_toggled" name="toggled"/> + <accelerator key="S" modifiers="GDK_MOD1_MASK" signal="grab_focus"/> + </object> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options"/> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="half_width_number"> + <property name="label" translatable="yes">Convert _numbers with the one column width</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> + <signal handler="on_ck_toggled" name="toggled"/> + <accelerator key="N" modifiers="GDK_MOD1_MASK" signal="grab_focus"/> + </object> + <packing> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="y_options"/> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="half_width_space"> + <property name="label" translatable="yes">Con_vert spaces with the one column width</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> + <signal handler="on_ck_toggled" name="toggled"/> + <accelerator key="v" modifiers="GDK_MOD1_MASK" signal="activate"/> + </object> + <packing> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="y_options"/> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="latin_with_shift"> + <property name="label" translatable="yes">Swi_tch “Hiragana” and “Latin” with Shift key and Hiragana–Katakana key in preedit</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> + <signal handler="on_ck_toggled" name="toggled"/> + <accelerator key="t" modifiers="GDK_MOD1_MASK" signal="activate"/> + </object> + <packing> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + <property name="y_options"/> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label211"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Other</b></property> + <property name="use_markup">True</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + <child type="tab"> + <object class="GtkLabel" id="label2"> + <property name="visible">True</property> + <property name="label" translatable="yes">Conversion</property> + <property name="mnemonic_widget">vbox2</property> + </object> + <packing> + <property name="position">1</property> + <property name="tab_fill">False</property> + </packing> + </child> + <child> + <object class="GtkVBox" id="vbox3"> + <property name="visible">True</property> + <property name="border_width">4</property> + <property name="spacing">4</property> + <child> + <object class="GtkHBox" id="hbox1"> + <property name="visible">True</property> + <property name="spacing">8</property> + <child> + <object class="GtkLabel" id="label21"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Shortcut Type:</property> + <property name="use_underline">True</property> + <property name="wrap_mode">word-char</property> + <property name="mnemonic_widget">shortcut_type</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="padding">1</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkComboBox" id="shortcut_type"> + <property name="visible">True</property> + <signal handler="on_shortcut_type_changed" name="changed"/> + <property name="model">model9</property> + <child> + <object class="GtkCellRendererText" id="renderer9"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow" id="scrolledwindow31"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">automatic</property> + <property name="vscrollbar_policy">automatic</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTreeView" id="shortcut"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <signal handler="on_shortcut_click_event" name="button_press_event"/> + <signal handler="on_shortcut_click_event" name="button_release_event"/> + <signal handler="on_shortcut_key_release_event" name="key_release_event"/> + </object> + </child> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkHButtonBox" id="hbuttonbox31"> + <property name="visible">True</property> + <property name="spacing">4</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="btn_default"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">False</property> + <signal handler="on_btn_default_clicked" name="clicked"/> + <child> + <object class="GtkAlignment" id="alignment31"> + <property name="visible">True</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <child> + <object class="GtkHBox" id="hbox5"> + <property name="visible">True</property> + <property name="spacing">2</property> + <child> + <object class="GtkImage" id="image1"> + <property name="visible">True</property> + <property name="stock">gtk-undo</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label27"> + <property name="visible">True</property> + <property name="label" translatable="yes">De_fault</property> + <property name="use_underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="btn_edit"> + <property name="label">gtk-edit</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">False</property> + <property name="use_stock">True</property> + <signal handler="on_btn_edit_clicked" name="clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">2</property> + </packing> + </child> + </object> + </child> + <child type="tab"> + <object class="GtkLabel" id="label3"> + <property name="visible">True</property> + <property name="label" translatable="yes">Key Binding</property> + <property name="mnemonic_widget">vbox3</property> + </object> + <packing> + <property name="position">2</property> + <property name="tab_fill">False</property> + </packing> + </child> + <child> + <object class="GtkBox" id="vbox4"> + <property name="visible">True</property> + <property name="border_width">8</property> + <property name="spacing">4</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkFrame" id="frame41"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignment41"> + <property name="visible">True</property> + <property name="top_padding">0</property> + <property name="bottom_padding">8</property> + <property name="left_padding">12</property> + <child> + <object class="GtkBox" id="vbox41"> + <property name="visible">True</property> + <property name="border_width">4</property> + <property name="spacing">4</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkTable" id="table41"> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">2</property> + <property name="column_spacing">8</property> + <property name="row_spacing">4</property> + <child> + <object class="GtkLabel" id="label402"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Romaji Key Table:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">romaji:button_custom_table</property> + </object> + <packing> + <property name="x_options">GTK_FILL</property> + <!-- The fill need to be True so that + GtkTable do not have extra space + in y axis. --> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <object class="GtkButton" id="romaji:button_custom_table"> + <property name="label">...</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <signal handler="on_btn_romaji_custom_table_clicked" name="clicked"/> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label401"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Romaji</b></property> + <property name="use_markup">True</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <!-- The fill need to be True so that + GtkTable do not have extra space + in y axis. --> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkFrame" id="frame42"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignment42"> + <property name="visible">True</property> + <property name="top_padding">0</property> + <property name="bottom_padding">8</property> + <property name="left_padding">12</property> + <child> + <object class="GtkBox" id="vbox42"> + <property name="visible">True</property> + <property name="border_width">4</property> + <property name="spacing">4</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkTable" id="table42"> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">2</property> + <property name="column_spacing">8</property> + <property name="row_spacing">4</property> + <child> + <object class="GtkLabel" id="label412"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Kana Key Table:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">kana:button_custom_table</property> + </object> + <packing> + <property name="x_options">GTK_FILL</property> + <!-- The fill need to be True so that + GtkTable do not have extra space + in y axis. --> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <object class="GtkButton" id="kana:button_custom_table"> + <property name="label">...</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <signal handler="on_btn_kana_custom_table_clicked" name="clicked"/> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label411"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Kana</b></property> + <property name="use_markup">True</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <!-- The fill need to be True so that + GtkTable do not have extra space + in y axis. --> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkFrame" id="frame43"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignment43"> + <property name="visible">True</property> + <property name="top_padding">0</property> + <property name="bottom_padding">8</property> + <property name="left_padding">12</property> + <child> + <object class="GtkBox" id="vbox43"> + <property name="visible">True</property> + <property name="border_width">4</property> + <property name="spacing">4</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkTable" id="table43"> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">2</property> + <property name="column_spacing">8</property> + <property name="row_spacing">4</property> + <child> + <object class="GtkLabel" id="label422"> + <property name="visible">True</property> + <property name="label" translatable="yes">Keyboad _layout:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">keymap:combobox_custom_table</property> + </object> + <packing> + <property name="x_options">GTK_FILL</property> + <!-- The fill need to be True so that + GtkTable do not have extra space + in y axis. --> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <object class="GtkComboBox" id="keymap:combobox_custom_table"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <child> + <object class="GtkCellRendererText" id="renderer330"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label421"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Keyboard layout</b></property> + <property name="use_markup">True</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <!-- The fill need to be True so that + GtkTable do not have extra space + in y axis. --> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + </child> + <child type="tab"> + <object class="GtkLabel" id="label4"> + <property name="visible">True</property> + <property name="label" translatable="yes">Typing Method</property> + <property name="mnemonic_widget">vbox4</property> + </object> + <packing> + <property name="position">3</property> + <property name="tab_fill">False</property> + </packing> + </child> + <child> + <object class="GtkBox" id="vbox5"> + <property name="visible">True</property> + <property name="border_width">8</property> + <property name="spacing">4</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkFrame" id="frame51"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignment5"> + <property name="visible">True</property> + <property name="top_padding">8</property> + <property name="bottom_padding">8</property> + <property name="left_padding">12</property> + <child> + <object class="GtkBox" id="vbox51"> + <property name="visible">True</property> + <property name="border_width">4</property> + <property name="spacing">4</property> + <property name="orientation">vertical</property> + <child> + + <object class="GtkTable" id="table51"> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">3</property> + <property name="column_spacing">8</property> + <property name="row_spacing">4</property> + <child> + <object class="GtkLabel" id="label28"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="use_underline">True</property> + <property name="label" translatable="yes">_Left Thumb Shift Key:</property> + <property name="mnemonic_widget">thumb:ls</property> + </object> + <packing> + <!-- The fill need to be True so that + GtkTable do not have extra space + in y axis. --> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="thumb:ls"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">False</property> + </object> + <packing> + <property name="y_options">GTK_FILL</property> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + </packing> + </child> + <child> + <object class="GtkButton" id="thumb:button_ls"> + <property name="label">...</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <signal handler="on_btn_thumb_key_clicked" name="clicked"/> + </object> + <packing> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label29"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="use_underline">True</property> + <property name="label" translatable="yes">Right _Thumb Shift Key:</property> + <property name="mnemonic_widget">thumb:rs</property> + </object> + <packing> + <property name="y_options">GTK_FILL</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="thumb:rs"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">False</property> + </object> + <packing> + <property name="y_options">GTK_FILL</property> + <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="GtkButton" id="thumb:button_rs"> + <property name="label">...</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <signal handler="on_btn_thumb_key_clicked" name="clicked"/> + </object> + <packing> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + <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> + </object> + <packing> + <property name="expand">False</property> + <!-- The fill need to be True so that + GtkTable do not have extra space + in y axis. --> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="thumb:keyboard_layout_mode"> + <property name="label" translatable="yes">Adjust _input method layout to system keyboard layout</property> + <property name="tooltip_text" translatable="yes">Adjust IM layout to XKB layout</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> + <signal handler="on_ck_toggled" name="toggled"/> + <accelerator key="I" modifiers="GDK_MOD1_MASK" signal="grab_focus"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="hbox51"> + <property name="visible">True</property> + <property name="spacing">8</property> + <child> + <object class="GtkLabel" id="label30"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="use_underline">True</property> + <property name="label" translatable="yes">Input _Method Layout:</property> + <property name="mnemonic_widget">thumb:keyboard_layout</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkComboBox" id="thumb:keyboard_layout"> + <property name="visible">True</property> + <signal handler="on_cb_changed" name="changed"/> + <property name="model">model51</property> + <child> + <object class="GtkCellRendererText" id="renderer10"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="hbox52"> + <property name="visible">True</property> + <property name="spacing">8</property> + <child> + <object class="GtkImage" id="image2"> + <property name="visible">True</property> + <property name="stock">gtk-dialog-info</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label31"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="wrap">True</property> + <property name="label" translatable="yes">Restart IBus when you change the keyboard layout</property> + <property name="tooltip_text" translatable="yes">Restart IBus when you change XKB</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">3</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="hbox11"> + <property name="visible">True</property> + <property name="spacing">8</property> + <child> + <object class="GtkLabel" id="label33"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="use_underline">True</property> + <property name="label" translatable="yes">_Additional Key Arrangement:</property> + <property name="mnemonic_widget">thumb:fmv_extension</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkComboBox" id="thumb:fmv_extension"> + <property name="visible">True</property> + <property name="tooltip_text" translatable="yes">'~', '『', '¢', '£' and so on can be output with Thumb Shift key</property> + <signal handler="on_cb_changed" name="changed"/> + <property name="model">model11</property> + <child> + <object class="GtkCellRendererText" id="renderer11"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">4</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="hbox53"> + <property name="visible">True</property> + <property name="spacing">8</property> + <child> + <object class="GtkImage" id="image4"> + <property name="visible">True</property> + <property name="stock">gtk-dialog-info</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label34"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="wrap">True</property> + <property name="label" translatable="yes">You do not have to reconfigure the system keyboard layout for "Additional Key Arrangement" since this option changes input method layout only in case input method is turned on.</property> + <property name="tooltip_text" translatable="yes">You do not have to reconfigure XKB since this option changes IM layout only with IM on.</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">5</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="thumb:handakuten"> + <property name="label" translatable="yes">_Enable semi-voiced sound mark with Shift key</property> + <property name="tooltip_text" translatable="yes">Seion + Shift can output Handakuon</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> + <signal handler="on_ck_toggled" name="toggled"/> + <accelerator key="E" modifiers="GDK_MOD1_MASK" signal="grab_focus"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">6</property> + </packing> + + </child> + <child> + <object class="GtkTable" id="table52"> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">2</property> + <property name="column_spacing">8</property> + <property name="row_spacing">4</property> + <child> + <object class="GtkLabel" id="label35"> + <property name="visible">True</property> + <property name="label" translatable="yes">Thumb _Shift Key Table:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">thumb:button_custom_table</property> + </object> + <packing> + <property name="x_options">GTK_FILL</property> + <!-- The fill need to be True so that + GtkTable do not have extra space + in y axis. --> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <object class="GtkButton" id="thumb:button_custom_table"> + <property name="label">...</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <signal handler="on_btn_thumb_custom_table_clicked" name="clicked"/> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <!-- The fill need to be True so that + GtkTable do not have extra space + in y axis. --> + <property name="fill">True</property> + <property name="position">7</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label36"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Thumb Shift Layout</b></property> + <property name="use_markup">True</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">0</property> + </packing> + </child> + </object> + </child> + <child type="tab"> + <object class="GtkLabel" id="label5"> + <property name="visible">True</property> + <property name="label" translatable="yes">Thumb Shift</property> + <property name="mnemonic_widget">vbox5</property> + </object> + <packing> + <property name="position">4</property> + <property name="tab_fill">False</property> + </packing> + </child> + <child> + <object class="GtkVBox" id="vbox6"> + <property name="visible">True</property> + <property name="border_width">8</property> + <property name="spacing">4</property> + <child> + <object class="GtkFrame" id="frame61"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignment61"> + <property name="visible">True</property> + <property name="top_padding">4</property> + <property name="left_padding">0</property> + <child> + <object class="GtkVBox" id="vbox61"> + <property name="visible">True</property> + <property name="border_width">4</property> + <property name="spacing">4</property> + <child> + <object class="GtkTable" id="table61"> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">3</property> + <property name="column_spacing">8</property> + <property name="row_spacing">4</property> + <child> + <object class="GtkLabel" id="label601"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Edit Dictionary Command:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">dict:entry_edit_dict_command</property> + </object> + <packing> + <property name="x_options">GTK_FILL</property> + <!-- The fill need to be True so that + GtkTable do not have extra space + in y axis. --> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="dict:entry_edit_dict_command"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <signal handler="on_entry_dict_command_changed" name="changed"/> + </object> + <packing> + <!-- The fill need to be True so that + GtkTable do not have extra space + in y axis. --> + <property name="y_options">GTK_FILL</property> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + </packing> + </child> + <child> + <object class="GtkButton" id="dict:btn_edit_dict_command"> + <property name="label">...</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <signal handler="on_btn_dict_command_clicked" name="clicked"/> + </object> + <packing> + <property name="x_options">GTK_FILL</property> + <!-- The fill need to be True so that + GtkTable do not have extra space + in y axis. --> + <property name="y_options">GTK_FILL</property> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label602"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Add Word Command:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">dict:entry_add_word_command</property> + </object> + <packing> + <property name="x_options">GTK_FILL</property> + <!-- The fill need to be True so that + GtkTable do not have extra space + in y axis. --> + <property name="y_options">GTK_FILL</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="dict:entry_add_word_command"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <signal handler="on_entry_dict_command_changed" name="changed"/> + </object> + <packing> + <!-- The fill need to be True so that + GtkTable do not have extra space + in y axis. --> + <property name="y_options">GTK_FILL</property> + <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="GtkButton" id="dict:btn_add_word_command"> + <property name="label">...</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <signal handler="on_btn_dict_command_clicked" name="clicked"/> + </object> + <packing> + <property name="x_options">GTK_FILL</property> + <!-- The fill need to be True so that + GtkTable do not have extra space + in y axis. --> + <property name="y_options">GTK_FILL</property> + <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> + </object> + <packing> + <property name="expand">False</property> + <!-- The fill need to be True so that + GtkTable do not have extra space + in y axis. --> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label60"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Default Dictionary Configuration</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="frame71"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignment71"> + <property name="visible">True</property> + <property name="top_padding">4</property> + <property name="left_padding">0</property> + <child> + <object class="GtkVBox" id="vbox71"> + <property name="visible">True</property> + <property name="border_width">4</property> + <property name="spacing">4</property> + <child> + <object class="GtkScrolledWindow" id="scrolledwindow71"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="height_request">220</property> + <property name="hscrollbar_policy">automatic</property> + <property name="vscrollbar_policy">automatic</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTreeView" id="dict:view"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </object> + </child> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkHButtonBox" id="hbuttonbox71"> + <property name="visible">True</property> + <property name="spacing">4</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="dict:btn_view"> + <property name="label" translatable="yes">_View</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <signal handler="on_btn_dict_view_clicked" name="clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="dict:btn_add"> + <property name="label">gtk-add</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">False</property> + <property name="use_stock">True</property> + <signal handler="on_btn_dict_add_clicked" name="clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="dict:btn_edit"> + <property name="label">gtk-edit</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">False</property> + <property name="use_stock">True</property> + <signal handler="on_btn_dict_add_clicked" name="clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkButton" id="dict:btn_delete"> + <property name="label">gtk-delete</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">False</property> + <property name="use_stock">True</property> + <signal handler="on_btn_dict_delete_clicked" name="clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">3</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkHButtonBox" id="hbuttonbox72"> + <property name="visible">True</property> + <property name="spacing">4</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="dict:btn_up"> + <property name="label">gtk-go-up</property> + <property name="tooltip_text" translatable="yes">You can change the order on language bar</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">False</property> + <property name="use_stock">True</property> + <signal handler="on_btn_dict_order_clicked" name="clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="dict:btn_down"> + <property name="label">gtk-go-down</property> + <property name="tooltip_text" translatable="yes">You can change the order on language bar</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">False</property> + <property name="use_stock">True</property> + <signal handler="on_btn_dict_order_clicked" name="clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">2</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label71"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Extended Dictionaries</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> + <child type="tab"> + <object class="GtkLabel" id="label6"> + <property name="visible">True</property> + <property name="label" translatable="yes">Dictionary</property> + <property name="mnemonic_widget">vbox6</property> + </object> + <packing> + <property name="position">5</property> + <property name="tab_fill">False</property> + </packing> + </child> + <child> + <object class="GtkVBox" id="about_vbox"> + <property name="visible">True</property> + <property name="orientation">vertical</property> + <property name="border_width">10</property> + <property name="spacing">6</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + </object> + </child> + <child type="tab"> + <object class="GtkLabel" id="label7"> + <property name="visible">True</property> + <property name="label" translatable="yes">About</property> + <property name="mnemonic_widget">about_vbox</property> + </object> + <packing> + <property name="position">6</property> + <property name="tab_fill">False</property> + </packing> + </child> + </object> + <packing> + <property name="position">2</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="btn_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="can_default">True</property> + <property name="receives_default">False</property> + <property name="use_stock">True</property> + <signal handler="on_btn_apply_clicked" name="clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="btn_cancel"> + <property name="label">gtk-cancel</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">False</property> + <property name="use_stock">True</property> + <signal handler="on_btn_cancel_clicked" name="clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="btn_ok"> + <property name="label">gtk-ok</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">False</property> + <property name="use_stock">True</property> + <signal handler="on_btn_ok_clicked" name="clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">2</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="-10">btn_apply</action-widget> + <action-widget response="-6">btn_cancel</action-widget> + <action-widget response="-5">btn_ok</action-widget> + </action-widgets> + </object> + <object class="GtkDialog" id="edit_shortcut"> + <property name="width_request">340</property> + <property name="height_request">300</property> + <property name="title" translatable="yes">Edit Shortcut</property> + <property name="modal">True</property> + <property name="type_hint">dialog</property> + <child internal-child="vbox"> + <object class="GtkVBox" id="dialog-vbox2"> + <property name="visible">True</property> + <child> + <object class="GtkVBox" id="vbox101"> + <property name="visible">True</property> + <property name="border_width">5</property> + <property name="spacing">6</property> + <child> + <object class="GtkScrolledWindow" id="scrolledwindow101"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="border_width">1</property> + <property name="hscrollbar_policy">automatic</property> + <property name="vscrollbar_policy">automatic</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTreeView" id="es:treeview"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="headers_visible">False</property> + </object> + </child> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="hbox101"> + <property name="visible">True</property> + <property name="spacing">8</property> + <child> + <object class="GtkLabel" id="label1001"> + <property name="visible">True</property> + <property name="label" translatable="yes">Key Code:</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="es:entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <signal handler="on_es_entry_changed" name="changed"/> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="es:button_run_input"> + <property name="label">...</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <signal handler="on_es_button_run_input_clicked" name="clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="hbox102"> + <property name="visible">True</property> + <property name="spacing">8</property> + <child> + <object class="GtkLabel" id="label1002"> + <property name="visible">True</property> + <property name="label" translatable="yes">Modifier:</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="hbox103"> + <property name="visible">True</property> + <child> + <object class="GtkCheckButton" id="es:checkbutton_alt"> + <property name="label" translatable="yes">A_lternate</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> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="es:checkbutton_ctrl"> + <property name="label" translatable="yes">Co_ntrol</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> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="es:checkbutton_shift"> + <property name="label" translatable="yes">_Shift</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> + </object> + <packing> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkHButtonBox" id="hbuttonbox101"> + <property name="visible">True</property> + <property name="spacing">6</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="es:button_add"> + <property name="label">gtk-add</property> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">False</property> + <property name="use_stock">True</property> + <signal handler="on_es_button_add_clicked" name="clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="es:button_refresh"> + <property name="label">gtk-refresh</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">False</property> + <property name="use_stock">True</property> + <signal handler="on_es_button_refresh_clicked" name="clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="es:button_del"> + <property name="label">gtk-delete</property> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">False</property> + <property name="use_stock">True</property> + <signal handler="on_es_button_del_clicked" name="clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">3</property> + </packing> + </child> + </object> + <packing> + <property name="position">2</property> + </packing> + </child> + <child internal-child="action_area"> + <object class="GtkHButtonBox" id="dialog-action_area2"> + <property name="visible">True</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="cancelbutton101"> + <property name="label">gtk-cancel</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">False</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> + <child> + <object class="GtkButton" id="okbutton101"> + <property name="label">gtk-ok</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">False</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</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="-6">cancelbutton101</action-widget> + <action-widget response="-5">okbutton101</action-widget> + </action-widgets> + </object> + <object class="GtkDialog" id="dialog_custom_key_table"> + <property name="width_request">400</property> + <property name="height_request">470</property> + <property name="title"/> + <property name="modal">True</property> + <property name="type_hint">dialog</property> + <child internal-child="vbox"> + <object class="GtkVBox" id="dialog-vbox3"> + <property name="visible">True</property> + <property name="border_width">5</property> + <property name="spacing">6</property> + <child> + <object class="GtkHBox" id="hbox_for_combobox_custom_key_table"> + <property name="visible">True</property> + <property name="border_width">5</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel" id="label_custom_key_table"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label"/> + <property name="use_underline">True</property> + <property name="mnemonic_widget">combobox_custom_key_table</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkComboBox" id="combobox_custom_key_table"> + <property name="visible">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="hbox301"> + <property name="visible">True</property> + <property name="border_width">5</property> + <property name="spacing">6</property> + <child> + <object class="GtkScrolledWindow" id="scrolledwindow301"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="border_width">1</property> + <property name="hscrollbar_policy">automatic</property> + <property name="vscrollbar_policy">automatic</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTreeView" id="treeview_custom_key_table"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </object> + </child> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkVButtonBox" id="vbutton301"> + <property name="visible">True</property> + <property name="layout_style">start</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel" id="label3001"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Input Characters</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">entry_input_custom_key</property> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="entry_input_custom_key"> + <property name="visible">True</property> + <property name="width-chars">3</property> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label_output_custom_key"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Output Characters</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">entry_output_custom_key</property> + </object> + <packing> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="entry_output_custom_key"> + <property name="visible">True</property> + <property name="width-chars">3</property> + </object> + <packing> + <property name="position">3</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label_left_thumb_shift_custom_key"> + <property name="visible">False</property> + <property name="label" translatable="yes">_Left Thumb Shift</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">entry_left_thumb_shift_custom_key</property> + </object> + <packing> + <property name="position">4</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="entry_left_thumb_shift_custom_key"> + <property name="visible">False</property> + <property name="width-chars">3</property> + </object> + <packing> + <property name="position">5</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label_right_thumb_shift_custom_key"> + <property name="visible">False</property> + <property name="label" translatable="yes">_Right Thumb Shift</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">entry_right_thumb_shift_custom_key</property> + </object> + <packing> + <property name="position">6</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="entry_right_thumb_shift_custom_key"> + <property name="visible">False</property> + <property name="width-chars">3</property> + </object> + <packing> + <property name="position">7</property> + </packing> + </child> + <child> + <object class="GtkButton" id="button_add_custom_key"> + <property name="visible">True</property> + <property name="label">gtk-add</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">False</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="position">8</property> + </packing> + </child> + <child> + <object class="GtkButton" id="button_remove_custom_key"> + <property name="visible">True</property> + <property name="label">gtk-remove</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">False</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="position">9</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child internal-child="action_area"> + <object class="GtkHButtonBox" id="dialog-action_area3"> + <property name="visible">True</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="closebutton301"> + <property name="visible">True</property> + <property name="label">gtk-close</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="use_stock">True</property> + <property name="receives_default">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">closebutton301</action-widget> + </action-widgets> + </object> + <object class="GtkMessageDialog" id="quit_check"> + <property name="border_width">5</property> + <property name="resizable">False</property> + <property name="modal">True</property> + <property name="window_position">center-on-parent</property> + <property name="type_hint">dialog</property> + <property name="skip_taskbar_hint">True</property> + <property name="message_type">question</property> + <property name="buttons">yes-no</property> + <property name="text">Confirmation</property> + <property name="secondary_text">You are about to close the setup dialog, is that OK?</property> + <child internal-child="vbox"> + <object class="GtkVBox" id="dialog-vbox6"> + <property name="visible">True</property> + <property name="spacing">2</property> + <child internal-child="action_area"> + <object class="GtkHButtonBox" id="dialog-action_area6"> + <property name="visible">True</property> + <property name="layout_style">end</property> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + </object> + </child> + </object> + <object class="GtkMessageDialog" id="quit_check_without_save"> + <property name="border_width">5</property> + <property name="resizable">False</property> + <property name="modal">True</property> + <property name="window_position">center-on-parent</property> + <property name="type_hint">dialog</property> + <property name="skip_taskbar_hint">True</property> + <property name="message_type">warning</property> + <property name="buttons">yes-no</property> + <property name="text">Notice!</property> + <property name="secondary_text">You are about to close the setup dialog without saving your changes, is that OK?</property> + <child internal-child="vbox"> + <object class="GtkVBox" id="dialog-vbox7"> + <property name="visible">True</property> + <property name="spacing">2</property> + <child internal-child="action_area"> + <object class="GtkHButtonBox" id="dialog-action_area7"> + <property name="visible">True</property> + <property name="layout_style">end</property> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + </object> + </child> + </object> + <object class="GtkMessageDialog" id="key_input_dialog"> + <property name="border_width">5</property> + <property name="resizable">False</property> + <property name="modal">True</property> + <property name="window_position">center-on-parent</property> + <property name="type_hint">dialog</property> + <property name="skip_taskbar_hint">True</property> + <property name="buttons">cancel</property> + <property name="text">Please press a key (or a key combination)</property> + <property name="secondary_text">The dialog will be closed when the key is released</property> + <signal handler="on_key_input_dialog_key_press_event" name="key_press_event"/> + <signal handler="on_key_input_dialog_key_release_event" name="key_release_event"/> + <child internal-child="vbox"> + <object class="GtkVBox" id="dialog-vbox8"> + <property name="visible">True</property> + <property name="spacing">2</property> + <child internal-child="action_area"> + <object class="GtkHButtonBox" id="dialog-action_area8"> + <property name="visible">True</property> + <property name="layout_style">end</property> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + </object> + </child> + </object> + <object class="GtkMessageDialog" id="invalid_keysym"> + <property name="border_width">5</property> + <property name="resizable">False</property> + <property name="modal">True</property> + <property name="window_position">center-on-parent</property> + <property name="type_hint">dialog</property> + <property name="skip_taskbar_hint">True</property> + <property name="message_type">warning</property> + <property name="buttons">ok</property> + <property name="text">Invalid keysym</property> + <property name="secondary_text">This keysym is not valid</property> + <child internal-child="vbox"> + <object class="GtkVBox" id="dialog-vbox9"> + <property name="visible">True</property> + <property name="spacing">2</property> + <child internal-child="action_area"> + <object class="GtkHButtonBox" id="dialog-action_area9"> + <property name="visible">True</property> + <property name="layout_style">end</property> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + </object> + </child> + </object> + <object class="GtkVBox" id="dict:add_extra_vbox"> + <property name="visible">True</property> + <property name="no_show_all">True</property> + <property name="spacing">10</property> + <child> + <object class="GtkTable" id="table1000"> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">2</property> + <property name="column_spacing">8</property> + <property name="row_spacing">4</property> + <child> + <object class="GtkLabel" id="label10001"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Short Label:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">dict:short_entry</property> + </object> + <packing> + <property name="x_options">GTK_FILL</property> + <property name="y_options"/> + </packing> + </child> + <child> + <object class="GtkEntry" id="dict:short_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="max-length">1</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label10002"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Description:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">dict:long_entry</property> + </object> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"/> + </packing> + </child> + <child> + <object class="GtkEntry" id="dict:long_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">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> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="dict:single"> + <property name="label" translatable="yes">_Use your dictionary alone with switching dictionaries</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> + <property name="active">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="dict:embed"> + <property name="label" translatable="yes">_Embed your dictionary in the system dictionary</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> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">2</property> + </packing> + </child> + <child> + <!-- Unfortunatelly reverse conversion is too slow. --> + <object class="GtkCheckButton" id="dict:reverse"> + <property name="label" translatable="yes">Enable the _reverse conversion</property> + <property name="visible">False</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> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">3</property> + </packing> + </child> + </object> + <object class="GtkAboutDialog" id="about_dialog"> + <property name="program-name">IBus-Anthy</property> + <property name="copyright">Copyright © 2007–2008 Peng Huang +Copyright © 2009 Hideaki ABE +Copyright © 2009–2013 Takao Fujiwara +Copyright © 2007–2013 Red Hat, Inc.</property> + <property name="comments" translatable="yes">The Anthy engine for the IBus input platform</property> + <property name="license">GPL</property> + <property name="website">http://code.google.com/p/ibus/</property> + <property name="authors">Takao Fujiwara <takao.fujiwara1@gmail.com></property> + <property name="translator-credits" translatable="yes">translator_credits</property> + <property name="logo-icon-name"/> + <property name="wrap-license">True</property> + </object> +</interface> |