diff --git a/Makefile.am b/Makefile.am index 61d63563..fec54c5b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -44,11 +44,28 @@ pkgconfigdir = $(libdir)/pkgconfig # To register as an AppStream component to be visible in the software center # (See http://www.freedesktop.org/software/appstream/docs/ for more details): appdata_DATA = \ - ibus-table.appdata.xml \ - $(NULL) + ibus-table.appdata.xml \ + $(NULL) appdatadir = $(datadir)/metainfo +schemas_DATA = \ + org.freedesktop.ibus.engine.table.gschema.xml + $(NULL) + +schemasdir = $(datadir)/glib-2.0/schemas/ + +install-data-hook: + if test -z "$(DESTDIR)"; then \ + glib-compile-schemas $(schemasdir); \ + fi + +uninstall-hook: + SCHEMAS_FILES=`ls $(schemasdir)/*.gschema.xml` || true; \ + if test -z "$$SCHEMAS_FILES" && \ + test -f $(schemasdir)/gschemas.compiled; then \ + rm $(schemasdir)/gschemas.compiled; \ + fi AUX_DIST = \ config.guess \ @@ -70,6 +87,7 @@ EXTRA_DIST = \ config.rpath \ autogen.sh \ ibus-table.appdata.xml \ + $(schemas_DATA) \ @PACKAGE_NAME@.spec \ $(NULL) diff --git a/engine/it_util.py b/engine/it_util.py index 1b12d47c..e4f6cb5e 100644 --- a/engine/it_util.py +++ b/engine/it_util.py @@ -26,33 +26,35 @@ ''' import sys -import re -import string +from gi import require_version +require_version('GLib', '2.0') +from gi.repository import GLib -def config_section_normalize(section): - '''Replaces “_:” with “-” in the dconf section and converts to lower case - - :param section: The name of the dconf section - :type section: string - :rtype: string - - To make the comparison of the dconf sections work correctly. - - I avoid using .lower() here because it is locale dependent, when - using .lower() this would not achieve the desired effect of - comparing the dconf sections case insentively in some locales, it - would fail for example if Turkish locale (tr_TR.UTF-8) is set. - - Examples: - - >>> config_section_normalize('Foo_bAr:Baz') - 'foo-bar-baz' +def variant_to_value(variant): ''' - return re.sub(r'[_:]', r'-', section).translate( - bytes.maketrans( - bytes(string.ascii_uppercase.encode('ascii')), - bytes(string.ascii_lowercase.encode('ascii')))) - + Convert a GLib variant to a value + ''' + # pylint: disable=unidiomatic-typecheck + 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': + # 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) + if type(GLib.Variant.new_strv([]).dup_strv()) == tuple: + return variant.dup_strv()[0] + else: + return variant.dup_strv() + else: + print('error: unknown variant type: %s' %type_string) + return variant if __name__ == "__main__": import doctest diff --git a/engine/table.py b/engine/table.py index 2b07f68c..58be3b06 100644 --- a/engine/table.py +++ b/engine/table.py @@ -32,6 +32,9 @@ from gi import require_version require_version('IBus', '1.0') from gi.repository import IBus +require_version('Gio', '2.0') +from gi.repository import Gio +require_version('GLib', '2.0') from gi.repository import GLib #import tabsqlitedb import re @@ -82,28 +85,6 @@ def ascii_ispunct(character): else: return False -def variant_to_value(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': - # 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) - if type(GLib.Variant.new_strv([]).dup_strv()) == tuple: - return variant.dup_strv()[0] - else: - return variant.dup_strv() - else: - print('error: unknown variant type: %s' %type_string) - return variant - def argb(a, r, g, b): return (((a & 0xff)<<24) + ((r & 0xff) << 16) @@ -245,16 +226,14 @@ def __str__(self): class editor(object): '''Hold user inputs chars and preedit string''' - def __init__ (self, config, valid_input_chars, pinyin_valid_input_chars, + def __init__ (self, gsettings, valid_input_chars, pinyin_valid_input_chars, single_wildcard_char, multi_wildcard_char, auto_wildcard, full_width_letter, full_width_punct, max_key_length, database): self.db = database - self._config = config + self._gsettings = gsettings engine_name = os.path.basename( self.db.filename).replace('.db', '').replace(' ','_') - self._config_section = it_util.config_section_normalize( - "engine/Table/%s" % engine_name) self._max_key_length = int(max_key_length) self._max_key_length_pinyin = 7 self._valid_input_chars = valid_input_chars @@ -320,14 +299,12 @@ def __init__ (self, config, valid_input_chars, pinyin_valid_input_chars, self._select_keys = [ IBus.keyval_from_name(y) for y in [x.strip() for x in select_keys_csv.split(",")]] - self._page_size = variant_to_value(self._config.get_value( - self._config_section, - "lookuptablepagesize")) + self._page_size = it_util.variant_to_value(self._gsettings.get_user_value( + 'lookuptablepagesize')) if self._page_size == None or self._page_size > len(self._select_keys): self._page_size = len(self._select_keys) - self._orientation = variant_to_value(self._config.get_value( - self._config_section, - "LookupTableOrientation")) + self._orientation = it_util.variant_to_value(self._gsettings.get_user_value( + 'lookuptableorientation')) if self._orientation == None: self._orientation = self.db.get_orientation() self._lookup_table = self.get_new_lookup_table( @@ -337,11 +314,8 @@ def __init__ (self, config, valid_input_chars, pinyin_valid_input_chars, # self._py_mode: whether in pinyin mode self._py_mode = False # self._onechar: whether we only select single character - self._onechar = variant_to_value(self._config.get_value( - self._config_section, - "OneChar")) - if self._onechar == None: - self._onechar = False + self._onechar = it_util.variant_to_value(self._gsettings.get_value( + 'onechar')) # self._chinese_mode: the candidate filter mode, # 0 means to show simplified Chinese only # 1 means to show traditional Chinese only @@ -349,29 +323,28 @@ def __init__ (self, config, valid_input_chars, pinyin_valid_input_chars, # 3 means to show all characters but show traditional Chinese first # 4 means to show all characters # we use LC_CTYPE or LANG to determine which one to use if - # no default comes from the config. - self._chinese_mode = variant_to_value(self._config.get_value( - self._config_section, - "ChineseMode")) - if self._chinese_mode == None: - self._chinese_mode = self.get_default_chinese_mode() - elif debug_level > 1: + # no default comes from the user Gsettings. + self._chinese_mode = it_util.variant_to_value( + self._gsettings.get_user_value('chinesemode')) + if self._chinese_mode != None and debug_level > 1: sys.stderr.write( - "Chinese mode found in user config, mode=%s\n" + "Chinese mode found in Gsettings, mode=%s\n" % self._chinese_mode) + if self._chinese_mode == None: + self._chinese_mode = self.get_default_chinese_mode() # If auto select is true, then the first candidate phrase will # be selected automatically during typing. Auto select is true # by default for the stroke5 table for example. - self._auto_select = variant_to_value(self._config.get_value( - self._config_section, - "AutoSelect")) + self._auto_select = it_util.variant_to_value( + self._gsettings.get_user_value('autoselect')) if self._auto_select == None: if self.db.ime_properties.get('auto_select') != None: self._auto_select = self.db.ime_properties.get( 'auto_select').lower() == u'true' - else: - self._auto_select = False + if self._auto_select == None: + self._auto_select = it_util.variant_to_value( + self._gsettings.get_value('autoselect')) def get_new_lookup_table( self, page_size=10, @@ -408,6 +381,16 @@ def get_select_keys(self): def get_default_chinese_mode (self): ''' Use db value or LC_CTYPE in your box to determine the _chinese_mode + + 0 means to show simplified Chinese only + 1 means to show traditional Chinese only + 2 means to show all characters but show simplified Chinese first + 3 means to show all characters but show traditional Chinese first + 4 means to show all characters + + If nothing can be found return 4 to avoid any special + Chinese filtering or sorting. + ''' # use db value, if applicable __db_chinese_mode = self.db.get_chinese_mode() @@ -461,12 +444,12 @@ def get_default_chinese_mode (self): if debug_level > 1: sys.stderr.write( "get_default_chinese_mode(): last fallback, " - + "database is not Chinese, returning -1.\n") - return -1 + + "database is not Chinese, returning 4.\n") + return 4 except: import traceback traceback.print_exc() - return -1 + return 4 def clear_all_input_and_preedit(self): ''' @@ -1254,19 +1237,17 @@ def __init__(self, bus, obj_path, db, unit_test=False): self._setup_pid = 0 self._icon_dir = '%s%s%s%s' % (os.getenv('IBUS_TABLE_LOCATION'), os.path.sep, 'icons', os.path.sep) - # name for config section self._engine_name = os.path.basename( self.db.filename).replace('.db', '').replace(' ','_') - self._config_section = it_util.config_section_normalize( - "engine/Table/%s" % self._engine_name) if debug_level > 1: sys.stderr.write( - 'tabengine.__init__() self._config_section = %s\n' - % self._config_section) + 'tabengine.__init__() self._engine_name = %s\n' + % self._engine_name) - # config module - self._config = self._bus.get_config() - self._config.connect ("value-changed", self.config_value_changed_cb) + self._gsettings = Gio.Settings( + schema='org.freedesktop.ibus.engine.table', + path='/org/freedesktop/ibus/engine/table/%s/' %self._engine_name) + self._gsettings.connect('changed', self.on_gsettings_value_changed) # self._ime_py: Indicates whether this table supports pinyin mode self._ime_py = self.db.ime_properties.get('pinyin_mode') @@ -1302,37 +1283,37 @@ def __init__(self, bus, obj_path, db, unit_test=False): 'valid_input_chars') self._pinyin_valid_input_chars = u'abcdefghijklmnopqrstuvwxyz!@#$%' - self._single_wildcard_char = variant_to_value(self._config.get_value( - self._config_section, - "singlewildcardchar")) + self._single_wildcard_char = it_util.variant_to_value( + self._gsettings.get_user_value('singlewildcardchar')) if self._single_wildcard_char == None: self._single_wildcard_char = self.db.ime_properties.get( 'single_wildcard_char') if self._single_wildcard_char == None: - self._single_wildcard_char = u'' + self._single_wildcard_char = it_util.variant_to_value( + self._gsettings.get_value('singlewildcardchar')) if len(self._single_wildcard_char) > 1: self._single_wildcard_char = self._single_wildcard_char[0] - self._multi_wildcard_char = variant_to_value(self._config.get_value( - self._config_section, - "multiwildcardchar")) + self._multi_wildcard_char = it_util.variant_to_value( + self._gsettings.get_user_value('multiwildcardchar')) if self._multi_wildcard_char == None: self._multi_wildcard_char = self.db.ime_properties.get( 'multi_wildcard_char') if self._multi_wildcard_char == None: - self._multi_wildcard_char = u'' + self._multi_wildcard_char = it_util.variant_to_value( + self._gsettings.get_value('multiwildcardchar')) if len(self._multi_wildcard_char) > 1: self._multi_wildcard_char = self._multi_wildcard_char[0] - self._auto_wildcard = variant_to_value(self._config.get_value( - self._config_section, - "autowildcard")) + self._auto_wildcard = it_util.variant_to_value( + self._gsettings.get_user_value('autowildcard')) if self._auto_wildcard == None: - self._auto_wildcard = self.db.ime_properties.get('auto_wildcard') - if self._auto_wildcard and self._auto_wildcard.lower() == u'false': - self._auto_wildcard = False - else: - self._auto_wildcard = True + if self.db.ime_properties.get('auto_wildcard') != None: + self._auto_wildcard = self.db.ime_properties.get( + 'auto_wildcard').lower() == u'true' + if self._auto_wildcard == None: + self._auto_wildcard = it_util.variant_to_value( + self._gsettings.get_value('autowildcard')) self._max_key_length = int(self.db.ime_properties.get('max_key_length')) self._max_key_length_pinyin = 7 @@ -1394,24 +1375,24 @@ def __init__(self, bus, obj_path, db, unit_test=False): self._page_up_keys.remove(keyval) if keyval in self._page_down_keys: self._page_down_keys.remove(keyval) - # Finally, check the user setting, i.e. the config value + # Finally, check the user setting, i.e. the Gsettings value # “spacekeybehavior” and let the user have the last word # how to use the space key: - spacekeybehavior = variant_to_value(self._config.get_value( - self._config_section, - "spacekeybehavior")) - if spacekeybehavior == True: - # space is used as a page down key and not as a commit key: - if IBus.KEY_space not in self._page_down_keys: - self._page_down_keys.append(IBus.KEY_space) - if IBus.KEY_space in self._commit_keys: - self._commit_keys.remove(IBus.KEY_space) - if spacekeybehavior == False: - # space is used as a commit key and not used as a page down key: - if IBus.KEY_space in self._page_down_keys: - self._page_down_keys.remove(IBus.KEY_space) - if IBus.KEY_space not in self._commit_keys: - self._commit_keys.append(IBus.KEY_space) + spacekeybehavior = it_util.variant_to_value( + self._gsettings.get_user_value('spacekeybehavior')) + if spacekeybehavior != None: + if spacekeybehavior == True: + # space is used as a page down key and not as a commit key: + if IBus.KEY_space not in self._page_down_keys: + self._page_down_keys.append(IBus.KEY_space) + if IBus.KEY_space in self._commit_keys: + self._commit_keys.remove(IBus.KEY_space) + if spacekeybehavior == False: + # space is used as a commit key and not used as a page down key: + if IBus.KEY_space in self._page_down_keys: + self._page_down_keys.remove(IBus.KEY_space) + if IBus.KEY_space not in self._commit_keys: + self._commit_keys.append(IBus.KEY_space) if debug_level > 1: sys.stderr.write( "self._page_down_keys=%s\n" %repr(self._page_down_keys)) @@ -1423,11 +1404,8 @@ def __init__(self, bus, obj_path, db, unit_test=False): # (but some fullwidth ↔ halfwidth conversion may be done even # in this mode, depending on the settings) # 1 = Table input ON (aka “Table input mode”, “Chinese mode”) - self._input_mode = variant_to_value(self._config.get_value( - self._config_section, - "inputmode")) - if self._input_mode == None: - self._input_mode = 1 + self._input_mode = it_util.variant_to_value( + self._gsettings.get_value('inputmode')) # self._prev_key: hold the key event last time. self._prev_key = None @@ -1436,63 +1414,67 @@ def __init__(self, bus, obj_path, db, unit_test=False): self._single_quotation_state = False self._full_width_letter = [ - variant_to_value(self._config.get_value( - self._config_section, - "EnDefFullWidthLetter")), - variant_to_value(self._config.get_value( - self._config_section, - "TabDefFullWidthLetter")) + it_util.variant_to_value( + self._gsettings.get_value('endeffullwidthletter')), + it_util.variant_to_value( + self._gsettings.get_user_value('tabdeffullwidthletter')) ] - if self._full_width_letter[0] == None: - self._full_width_letter[0] = False if self._full_width_letter[1] == None: - self._full_width_letter[1] = self.db.ime_properties.get( - 'def_full_width_letter').lower() == u'true' + if self.db.ime_properties.get('def_full_width_letter'): + self._full_width_letter[1] = self.db.ime_properties.get( + 'def_full_width_letter').lower() == u'true' + if self._full_width_letter[1] == None: + self._full_width_letter[1] = it_util.variant_to_value( + self._gsettings.get_value('tabdeffullwidthletter')) + self._full_width_punct = [ - variant_to_value(self._config.get_value( - self._config_section, - "EnDefFullWidthPunct")), - variant_to_value(self._config.get_value( - self._config_section, - "TabDefFullWidthPunct")) + it_util.variant_to_value( + self._gsettings.get_value('endeffullwidthpunct')), + it_util.variant_to_value( + self._gsettings.get_user_value('tabdeffullwidthpunct')) ] - if self._full_width_punct[0] == None: - self._full_width_punct[0] = False if self._full_width_punct[1] == None: - self._full_width_punct[1] = self.db.ime_properties.get( - 'def_full_width_punct').lower() == u'true' + if self.db.ime_properties.get('def_full_width_punct'): + self._full_width_punct[1] = self.db.ime_properties.get( + 'def_full_width_punct').lower() == u'true' + if self._full_width_punct[1] == None: + self._full_width_punct[1] = it_util.variant_to_value( + self._gsettings.get_value('tabdeffullwidthpunct')) - self._auto_commit = variant_to_value(self._config.get_value( - self._config_section, - "AutoCommit")) + self._auto_commit = it_util.variant_to_value( + self._gsettings.get_user_value('autocommit')) + if self._auto_commit == None: + if self.db.ime_properties.get('auto_commit'): + self._auto_commit = self.db.ime_properties.get( + 'auto_commit').lower() == u'true' if self._auto_commit == None: - self._auto_commit = self.db.ime_properties.get( - 'auto_commit').lower() == u'true' + self._auto_commit = it_util.variant_to_value( + self._gsettings.get_value('autocommit')) # If auto select is true, then the first candidate phrase will # be selected automatically during typing. Auto select is true # by default for the stroke5 table for example. - self._auto_select = variant_to_value(self._config.get_value( - self._config_section, - "AutoSelect")) + self._auto_select = it_util.variant_to_value( + self._gsettings.get_user_value('autoselect')) if self._auto_select == None: if self.db.ime_properties.get('auto_select') != None: self._auto_select = self.db.ime_properties.get( 'auto_select').lower() == u'true' - else: - self._auto_select = False + if self._auto_select == None: + self._auto_select = it_util.variant_to_value( + self._gsettings.get_value('autoselect')) - self._always_show_lookup = variant_to_value(self._config.get_value( - self._config_section, - "AlwaysShowLookup")) + self._always_show_lookup = it_util.variant_to_value( + self._gsettings.get_user_value('alwaysshowlookup')) if self._always_show_lookup == None: if self.db.ime_properties.get('always_show_lookup') != None: self._always_show_lookup = self.db.ime_properties.get( 'always_show_lookup').lower() == u'true' - else: - self._always_show_lookup = True + if self._always_show_lookup == None: + self._always_show_lookup = it_util.variant_to_value( + self._gsettings.get_value('alwaysshowlookup')) - self._editor = editor(self._config, + self._editor = editor(self._gsettings, self._valid_input_chars, self._pinyin_valid_input_chars, self._single_wildcard_char, @@ -1741,7 +1723,7 @@ def set_input_mode(self, mode=1): if mode == self._input_mode: return self._input_mode = mode - # Not saved to config on purpose. In the setup tool one + # Not saved to Gsettings on purpose. In the setup tool one # can select whether “Table input” or “Direct input” should # be the default when the input method starts. But when # changing this input mode using the property menu, @@ -1766,7 +1748,7 @@ def get_input_mode(self): def set_pinyin_mode(self, mode=False): if mode == self._editor._py_mode: return - # The pinyin mode is never saved to config on purpose + # The pinyin mode is never saved to Gsettings on purpose self._editor.commit_to_preedit() self._editor._py_mode = mode self._init_or_update_property_menu( @@ -1782,97 +1764,91 @@ def set_pinyin_mode(self, mode=False): self._input_mode) self._update_ui() - def set_onechar_mode(self, mode=False, update_dconf=True): + def set_onechar_mode(self, mode=False, update_gsettings=True): if mode == self._editor._onechar: return self._editor._onechar = mode self._init_or_update_property_menu( self.onechar_mode_menu, mode) self.db.reset_phrases_cache() - if update_dconf: - self._config.set_value( - self._config_section, + if update_gsettings: + self._gsettings.set_value( "OneChar", GLib.Variant.new_boolean(mode)) def get_onechar_mode(self): return self._editor._onechar - def set_autocommit_mode(self, mode=False, update_dconf=True): + def set_autocommit_mode(self, mode=False, update_gsettings=True): if mode == self._auto_commit: return self._auto_commit = mode self._init_or_update_property_menu( self.autocommit_mode_menu, mode) - if update_dconf: - self._config.set_value( - self._config_section, + if update_gsettings: + self._gsettings.set_value( "AutoCommit", GLib.Variant.new_boolean(mode)) def get_autocommit_mode(self): return self._auto_commit - def set_autoselect_mode(self, mode=False, update_dconf=True): + def set_autoselect_mode(self, mode=False, update_gsettings=True): if mode == self._auto_select: return self._auto_select = mode self._editor._auto_select = mode - if update_dconf: - self._config.set_value( - self._config_section, + if update_gsettings: + self._gsettings.set_value( "AutoSelect", GLib.Variant.new_boolean(mode)) def get_autoselect_mode(self): return self._auto_select - def set_autowildcard_mode(self, mode=False, update_dconf=True): + def set_autowildcard_mode(self, mode=False, update_gsettings=True): if mode == self._auto_wildcard: return self._auto_wildcard = mode self._editor._auto_wildcard = mode self.db.reset_phrases_cache() - if update_dconf: - self._config.set_value( - self._config_section, + if update_gsettings: + self._gsettings.set_value( "AutoWildcard", GLib.Variant.new_boolean(mode)) def get_autowildcard_mode(self): return self._auto_wildcard - def set_single_wildcard_char(self, char=u'', update_dconf=True): + def set_single_wildcard_char(self, char=u'', update_gsettings=True): if char == self._single_wildcard_char: return self._single_wildcard_char = char self._editor._single_wildcard_char = char self.db.reset_phrases_cache() - if update_dconf: - self._config.set_value( - self._config_section, + if update_gsettings: + self._gsettings.set_value( "singlewildcardchar", GLib.Variant.new_string(char)) def get_single_wildcard_char(self): return self._single_wildcard_char - def set_multi_wildcard_char(self, char=u'', update_dconf=True): + def set_multi_wildcard_char(self, char=u'', update_gsettings=True): if char == self._multi_wildcard_char: return self._multi_wildcard_char = char self._editor._multi_wildcard_char = char self.db.reset_phrases_cache() - if update_dconf: - self._config.set_value( - self._config_section, + if update_gsettings: + self._gsettings.set_value( "multiwildcardchar", GLib.Variant.new_string(char)) def get_multi_wildcard_char(self): return self._multi_wildcard_char - def set_space_key_behavior_mode(self, mode=False, update_dconf=True): + def set_space_key_behavior_mode(self, mode=False, update_gsettings=True): '''Sets the behaviour of the space key :param mode: How the space key should behave @@ -1881,12 +1857,12 @@ def set_space_key_behavior_mode(self, mode=False, update_dconf=True): and not as a commit key. False: space is used as a commit key and not used as a page down key - :param update_dconf: Whether to write the change to dconf. - Set this to False if this method is - called because the dconf key changed - to avoid endless loops when the dconf - key is changed twice in a short time. - :type update_dconf: boolean + :param update_gsettings: Whether to write the change to Gsettings. + Set this to False if this method is + called because the dconf key changed + to avoid endless loops when the dconf + key is changed twice in a short time. + :type update_gsettings: boolean ''' if debug_level > 1: sys.stderr.write( @@ -1911,9 +1887,8 @@ def set_space_key_behavior_mode(self, mode=False, update_dconf=True): sys.stderr.write( 'set_space_key_behavior_mode(): self._commit_keys=%s\n' % repr(self._commit_keys)) - if update_dconf: - self._config.set_value( - self._config_section, + if update_gsettings: + self._gsettings.set_value( "spacekeybehavior", GLib.Variant.new_boolean(mode)) @@ -1926,20 +1901,19 @@ def get_space_key_behavior_mode(self): mode = False return mode - def set_always_show_lookup(self, mode=False, update_dconf=True): + def set_always_show_lookup(self, mode=False, update_gsettings=True): if mode == self._always_show_lookup: return self._always_show_lookup = mode - if update_dconf: - self._config.set_value( - self._config_section, + if update_gsettings: + self._gsettings.set_value( "AlwaysShowLookup", GLib.Variant.new_boolean(mode)) def get_always_show_lookup(self): return self._always_show_lookup - def set_lookup_table_orientation(self, orientation, update_dconf=True): + def set_lookup_table_orientation(self, orientation, update_gsettings=True): '''Sets the orientation of the lookup table :param orientation: The orientation of the lookup table @@ -1947,12 +1921,12 @@ def set_lookup_table_orientation(self, orientation, update_dconf=True): IBUS_ORIENTATION_HORIZONTAL = 0, IBUS_ORIENTATION_VERTICAL = 1, IBUS_ORIENTATION_SYSTEM = 2. - :param update_dconf: Whether to write the change to dconf. - Set this to False if this method is - called because the dconf key changed - to avoid endless loops when the dconf - key is changed twice in a short time. - :type update_dconf: boolean + :param update_gsettings: Whether to write the change to Gsettings. + Set this to False if this method is + called because the dconf key changed + to avoid endless loops when the dconf + key is changed twice in a short time. + :type update_gsettings: boolean ''' if debug_level > 1: sys.stderr.write( @@ -1963,9 +1937,8 @@ def set_lookup_table_orientation(self, orientation, update_dconf=True): if orientation >= 0 and orientation <= 2: self._editor._orientation = orientation self._editor._lookup_table.set_orientation(orientation) - if update_dconf: - self._config.set_value( - self._config_section, + if update_gsettings: + self._gsettings.set_value( 'lookuptableorientation', GLib.Variant.new_int32(orientation)) @@ -1976,17 +1949,17 @@ def get_lookup_table_orientation(self): ''' return self._editor._orientation - def set_page_size(self, page_size, update_dconf=True): + def set_page_size(self, page_size, update_gsettings=True): '''Sets the page size of the lookup table :param orientation: The orientation of the lookup table :type mode: integer >= 1 and <= number of select keys - :param update_dconf: Whether to write the change to dconf. - Set this to False if this method is - called because the dconf key changed - to avoid endless loops when the dconf - key is changed twice in a short time. - :type update_dconf: boolean + :param update_gsettings: Whether to write the change to Gsettings. + Set this to False if this method is + called because the dconf key changed + to avoid endless loops when the dconf + key is changed twice in a short time. + :type update_gsettings: boolean ''' if debug_level > 1: sys.stderr.write( @@ -2004,9 +1977,8 @@ def set_page_size(self, page_size, update_dconf=True): select_keys = self._editor._select_keys, orientation = self._editor._orientation) self.reset() - if update_dconf: - self._config.set_value( - self._config_section, + if update_gsettings: + self._gsettings.set_value( 'lookuptablepagesize', GLib.Variant.new_int32(value)) @@ -2017,7 +1989,7 @@ def get_page_size(self): ''' return self._editor._page_size - def set_letter_width(self, mode=False, input_mode=0, update_dconf=True): + def set_letter_width(self, mode=False, input_mode=0, update_gsettings=True): if mode == self._full_width_letter[input_mode]: return self._full_width_letter[input_mode] = mode @@ -2025,22 +1997,20 @@ def set_letter_width(self, mode=False, input_mode=0, update_dconf=True): if input_mode == self._input_mode: self._init_or_update_property_menu( self.letter_width_menu, mode) - if update_dconf: + if update_gsettings: if input_mode: - self._config.set_value( - self._config_section, + self._gsettings.set_value( "TabDefFullWidthLetter", GLib.Variant.new_boolean(mode)) else: - self._config.set_value( - self._config_section, + self._gsettings.set_value( "EnDefFullWidthLetter", GLib.Variant.new_boolean(mode)) def get_letter_width(self): return self._full_width_letter - def set_punctuation_width(self, mode=False, input_mode=0, update_dconf=True): + def set_punctuation_width(self, mode=False, input_mode=0, update_gsettings=True): if mode == self._full_width_punct[input_mode]: return self._full_width_punct[input_mode] = mode @@ -2048,32 +2018,29 @@ def set_punctuation_width(self, mode=False, input_mode=0, update_dconf=True): if input_mode == self._input_mode: self._init_or_update_property_menu( self.punctuation_width_menu, mode) - if update_dconf: + if update_gsettings: if input_mode: - self._config.set_value( - self._config_section, + self._gsettings.set_value( "TabDefFullWidthPunct", GLib.Variant.new_boolean(mode)) else: - self._config.set_value( - self._config_section, + self._gsettings.set_value( "EnDefFullWidthPunct", GLib.Variant.new_boolean(mode)) def get_punctuation_width(self): return self._full_width_punct - def set_chinese_mode(self, mode=0, update_dconf=True): + def set_chinese_mode(self, mode=0, update_gsettings=True): if mode == self._editor._chinese_mode: return self._editor._chinese_mode = mode self.db.reset_phrases_cache() self._init_or_update_property_menu( self.chinese_mode_menu, mode) - if update_dconf: - self._config.set_value( - self._config_section, - "ChineseMode", + if update_gsettings: + self._gsettings.set_value( + "chinesemode", GLib.Variant.new_int32(mode)) def get_chinese_mode(self): @@ -3086,78 +3053,60 @@ def do_page_down (self): return True return False - def config_section_normalize(self, section): - # This function replaces _: with - in the dconf - # section and converts to lower case to make - # the comparison of the dconf sections work correctly. - # I avoid using .lower() here because it is locale dependent, - # when using .lower() this would not achieve the desired - # effect of comparing the dconf sections case insentively - # in some locales, it would fail for example if Turkish - # locale (tr_TR.UTF-8) is set. - if sys.version_info >= (3, 0, 0): # Python3 - return re.sub(r'[_:]', r'-', section).translate( - ''.maketrans( - string.ascii_uppercase, - string.ascii_lowercase)) - else: # Python2 - return re.sub(r'[_:]', r'-', section).translate( - string.maketrans( - string.ascii_uppercase, - string.ascii_lowercase).decode('ISO-8859-1')) - - def config_value_changed_cb(self, config, section, name, value): - if (self.config_section_normalize(self._config_section) - != self.config_section_normalize(section)): - return - value = variant_to_value(value) - print('config value %(n)s for engine %(en)s changed to %(value)s' - % {'n': name, 'en': self._engine_name, 'value': value}) - if name == u'inputmode': + def on_gsettings_value_changed(self, settings, key): + ''' + Called when a value in the settings has been changed. + ''' + value = it_util.variant_to_value(self._gsettings.get_value(key)) + sys.stderr.write('Settings changed for engine “%s”: key=%s value=%s\n' + %(self._engine_name, key, value)) + if key == u'inputmode': self.set_input_mode(value) return - if name == u'autoselect': - self.set_autoselect_mode(value, update_dconf=False) + if key == u'autoselect': + self.set_autoselect_mode(value, update_gsettings=False) return - if name == u'autocommit': - self.set_autocommit_mode(value, update_dconf=False) + if key == u'autocommit': + self.set_autocommit_mode(value, update_gsettings=False) return - if name == u'chinesemode': - self.set_chinese_mode(value, update_dconf=False) + if key == u'chinesemode': + self.set_chinese_mode(value, update_gsettings=False) return - if name == u'endeffullwidthletter': - self.set_letter_width(value, input_mode=0, update_dconf=False) + if key == u'endeffullwidthletter': + self.set_letter_width(value, input_mode=0, update_gsettings=False) return - if name == u'endeffullwidthpunct': - self.set_punctuation_width(value, input_mode=0, update_dconf=False) + if key == u'endeffullwidthpunct': + self.set_punctuation_width(value, input_mode=0, update_gsettings=False) return - if name == u'lookuptableorientation': - self.set_lookup_table_orientation(value, update_dconf=False) + if key == u'lookuptableorientation': + self.set_lookup_table_orientation(value, update_gsettings=False) return - if name == u'lookuptablepagesize': - self.set_page_size(value, update_dconf=False) + if key == u'lookuptablepagesize': + self.set_page_size(value, update_gsettings=False) return - if name == u'onechar': - self.set_onechar_mode(value, update_dconf=False) + if key == u'onechar': + self.set_onechar_mode(value, update_gsettings=False) return - if name == u'tabdeffullwidthletter': - self.set_letter_width(value, input_mode=1, update_dconf=False) + if key == u'tabdeffullwidthletter': + self.set_letter_width(value, input_mode=1, update_gsettings=False) return - if name == u'tabdeffullwidthpunct': - self.set_punctuation_width(value, input_mode=1, update_dconf=False) + if key == u'tabdeffullwidthpunct': + self.set_punctuation_width(value, input_mode=1, update_gsettings=False) return - if name == u'alwaysshowlookup': - self.set_always_show_lookup(value, update_dconf=False) + if key == u'alwaysshowlookup': + self.set_always_show_lookup(value, update_gsettings=False) return - if name == u'spacekeybehavior': - self.set_space_key_behavior_mode(value, update_dconf=False) + if key == u'spacekeybehavior': + self.set_space_key_behavior_mode(value, update_gsettings=False) return - if name == u'singlewildcardchar': - self.set_single_wildcard_char(value, update_dconf=False) + if key == u'singlewildcardchar': + self.set_single_wildcard_char(value, update_gsettings=False) return - if name == u'multiwildcardchar': - self.set_multi_wildcard_char(value, update_dconf=False) + if key == u'multiwildcardchar': + self.set_multi_wildcard_char(value, update_gsettings=False) return - if name == u'autowildcard': - self.set_autowildcard_mode(value, update_dconf=False) + if key == u'autowildcard': + self.set_autowildcard_mode(value, update_gsettings=False) return + sys.stderr.write('Unknown key\n') + return diff --git a/engine/tabsqlitedb.py b/engine/tabsqlitedb.py index 8185993d..4e063d90 100644 --- a/engine/tabsqlitedb.py +++ b/engine/tabsqlitedb.py @@ -98,6 +98,9 @@ def get(self, key): else: return None + def __str__(self): + return 'ime_property_cache = %s' %repr(self.ime_property_cache) + class tabsqlitedb: '''Phrase database for tables @@ -525,13 +528,13 @@ def is_cjk(self): return True return False - def get_chinese_mode (self): + def get_chinese_mode(self): try: __dict = {'cm0':0, 'cm1':1, 'cm2':2, 'cm3':3, 'cm4':4} __filt = self.ime_properties.get('language_filter') return __dict[__filt] except: - return -1 + return 4 def get_select_keys (self): ret = self.ime_properties.get("select_keys") @@ -873,7 +876,7 @@ def big5_code(self, phrase): return big5 def best_candidates( - self, typed_tabkeys=u'', candidates=[], chinese_mode=-1): + self, typed_tabkeys=u'', candidates=[], chinese_mode=4): ''' “candidates” is an array containing something like: [(tabkeys, phrase, freq, user_freq), ...] @@ -928,7 +931,7 @@ def best_candidates( ))[:maximum_number_of_candidates] def select_words( - self, tabkeys=u'', onechar=False, chinese_mode=-1, + self, tabkeys=u'', onechar=False, chinese_mode=4, single_wildcard_char=u'', multi_wildcard_char=u'', auto_wildcard=False): ''' @@ -1027,7 +1030,7 @@ def select_words( return best def select_chinese_characters_by_pinyin( - self, tabkeys=u'', chinese_mode=-1, single_wildcard_char=u'', + self, tabkeys=u'', chinese_mode=4, single_wildcard_char=u'', multi_wildcard_char=u''): ''' Get Chinese characters matching the pinyin given by tabkeys diff --git a/org.freedesktop.ibus.engine.table.gschema.xml b/org.freedesktop.ibus.engine.table.gschema.xml new file mode 100644 index 00000000..ad201000 --- /dev/null +++ b/org.freedesktop.ibus.engine.table.gschema.xml @@ -0,0 +1,53 @@ + + + + + false + + + false + + + 1 + + + 4 + + + false + + + false + + + 1 + + + 6 + + + false + + + false + + + false + + + true + + + false + + + '' + + + '' + + + true + + + diff --git a/setup/main.py b/setup/main.py index e5405c43..4e0ac9ef 100644 --- a/setup/main.py +++ b/setup/main.py @@ -32,6 +32,8 @@ import re from gi import require_version +require_version('Gio', '2.0') +from gi.repository import Gio require_version('GLib', '2.0') from gi.repository import GLib @@ -51,12 +53,17 @@ sys.path = [sys.path[0]+'/../engine'] + sys.path import tabsqlitedb import ibus_table_location +import it_util _ = lambda a : gettext.dgettext("ibus-table", a) +# The contents this OPTION_DEFAULTS dict are first overwritten +# with the defaults from the Gsettings schema file and then again with +# the defaults from the tables. + OPTION_DEFAULTS = { "inputmode": 1, - "chinesemode": 0, + "chinesemode": 4, "tabdeffullwidthletter": False, "tabdeffullwidthpunct": False, "endeffullwidthletter": False, @@ -141,6 +148,12 @@ def __init__(self): _("Cannot determine the engine name. Please use the --engine-name option."), Gtk.MessageType.ERROR) sys.exit(1) + short_engine_name = re.sub( + r'^table:', '', self.__engine_name).replace(" ", "_") + self.__gsettings = Gio.Settings( + schema='org.freedesktop.ibus.engine.table', + path='/org/freedesktop/ibus/engine/table/%s/' %short_engine_name) + self.__gsettings.connect('changed', self.on_gsettings_value_changed) def check_table_available(self): """Check if the current engine_name is available. @@ -156,7 +169,19 @@ def check_table_available(self): Gtk.MessageType.ERROR) return ret + def get_default_options_from_gsettings(self): + ''' + Get the default options from the Gsettings schema file. + ''' + for key in OPTION_DEFAULTS: + OPTION_DEFAULTS[key] = it_util.variant_to_value( + self.__gsettings.get_value(key)) + def get_default_options_from_database(self): + ''' + If there are default options in the database, + they override the defaults from Gsettings. + ''' self.tabsqlitedb = tabsqlitedb.tabsqlitedb( filename = os.path.join( db_dir, @@ -267,13 +292,13 @@ def get_default_options_from_database(self): OPTION_DEFAULTS['multiwildcardchar'] = multi_wildcard_char def __restore_defaults(self): - for name in OPTION_DEFAULTS: - value = OPTION_DEFAULTS[name] - self.__set_value(name, value) + for key in OPTION_DEFAULTS: + value = OPTION_DEFAULTS[key] + self.__set_value(key, value) - def _build_combobox_renderer(self, name): + def _build_combobox_renderer(self, key): """setup cell renderer for combobox""" - __combobox = self.__builder.get_object("combobox%s" % name) + __combobox = self.__builder.get_object("combobox%s" % key) __cell = Gtk.CellRendererText() __combobox.pack_start(__cell, True) __combobox.add_attribute(__cell, 'text', 0) @@ -285,15 +310,11 @@ def load_builder(self): self.__builder.add_from_file("ibus-table-preferences.ui") self.__dialog = self.__builder.get_object("dialog") - for name in list(OPTION_DEFAULTS.keys()): - if name not in SCALE_WIDGETS and name not in ENTRY_WIDGETS: - self._build_combobox_renderer(name) + for key in list(OPTION_DEFAULTS.keys()): + if key not in SCALE_WIDGETS and key not in ENTRY_WIDGETS: + self._build_combobox_renderer(key) def do_init(self): - self.__config = self.__bus.get_config() - self.__config_section = ("engine/Table/%s" % - re.sub(r'^table:', '', self.__engine_name).replace(" ", "_")) - self.__init_general() self.__init_about() @@ -310,17 +331,20 @@ def __init_general(self): # found, the second argument of set_wmclass() is shown by # gnome-shell in the top bar. self.__dialog.set_wmclass('ibus-setup-table', 'IBus Table Setup') - self.__values = self.__config.get_values(self.__config_section).unpack() - self.__config.connect ("value-changed", self.__config_value_changed_cb) - - for name in list(OPTION_DEFAULTS.keys()): - #self.__config.unset(self.__config_section, name); continue - if name in SCALE_WIDGETS: - self._init_hscale(name) - elif name in ENTRY_WIDGETS: - self._init_entry(name) + + self.__user_values = {} + for key in OPTION_DEFAULTS: + if self.__gsettings.get_user_value(key) != None: + self.__user_values[key] = it_util.variant_to_value( + self.__gsettings.get_user_value(key)) + sys.stderr.write( + 'self.__user_values[%s]=%s\n' %(key, self.__user_values[key])) + if key in SCALE_WIDGETS: + self._init_hscale(key) + elif key in ENTRY_WIDGETS: + self._init_entry(key) else: - self._init_combobox(name) + self._init_combobox(key) self._init_button('restoredefaults') return @@ -357,14 +381,14 @@ def __init_about(self): w = self.__builder.get_object("TableNameImage") w.set_from_pixbuf(pixbuf) - def _init_combobox(self, name): - """Set combobox from the __config engine""" - __combobox = self.__builder.get_object("combobox%s" % name) + def _init_combobox(self, key): + """Set combobox from the Gsettings""" + __combobox = self.__builder.get_object("combobox%s" % key) val = 0 - if name in self.__values: - init_val = self.__values[name] + if key in self.__user_values: + init_val = self.__user_values[key] else: - init_val = OPTION_DEFAULTS[name] + init_val = OPTION_DEFAULTS[key] if isinstance(init_val, bool): val = 1 if init_val else 0 elif isinstance(init_val, int): @@ -376,115 +400,108 @@ def _init_combobox(self, name): val = i break __combobox.set_active(val) - __combobox.connect("changed", self.__changed_cb, name) - if ((name in ['chinesemode'] + __combobox.connect("changed", self.__changed_cb, key) + if ((key in ['chinesemode'] and not self.__is_chinese) or - (name in ['tabdeffullwidthletter', + (key in ['tabdeffullwidthletter', 'tabdeffullwidthpunct', 'endeffullwidthletter', 'endeffullwidthpunct'] and not self.__is_cjk) or - (name in ['onechar'] + (key in ['onechar'] and not self.__is_cjk) or - (name in ['autocommit'] + (key in ['autocommit'] and (not self.__user_can_define_phrase or not self.__rules))): __combobox.set_button_sensitivity(Gtk.SensitivityType.OFF) - def _init_entry(self, name): - """Set entry widget from the __config engine""" - __entry = self.__builder.get_object("entry%s" % name) - if name in self.__values: - val = self.__values[name] + def _init_entry(self, key): + """Set entry widget from the Gsettings engine""" + __entry = self.__builder.get_object("entry%s" % key) + if key in self.__user_values: + val = self.__user_values[key] else: - val = OPTION_DEFAULTS[name] + val = OPTION_DEFAULTS[key] __entry.set_text(val) - __entry.connect("notify::text", self.__entry_changed_cb, name) + __entry.connect("notify::text", self.__entry_changed_cb, key) - def _init_hscale(self, name): - """Set scale widget from the __config engine""" - __hscale = self.__builder.get_object("hscale%s" % name) - if name in self.__values: - val = self.__values[name] + def _init_hscale(self, key): + """Set scale widget from Gsettings""" + __hscale = self.__builder.get_object("hscale%s" % key) + if key in self.__user_values: + val = self.__user_values[key] else: - val = OPTION_DEFAULTS[name] + val = OPTION_DEFAULTS[key] __hscale.set_value(val) - __hscale.connect("value-changed", self.__value_changed_cb, name) + __hscale.connect("value-changed", self.__value_changed_cb, key) - def _init_button(self, name): + def _init_button(self, key): """Initialize the button to restore the default settings""" - __button = self.__builder.get_object("button%s" %name) - __button.connect("clicked", self.__button_clicked_cb, name) + __button = self.__builder.get_object("button%s" %key) + __button.connect("clicked", self.__button_clicked_cb, key) - def __button_clicked_cb(self, widget, name): + def __button_clicked_cb(self, widget, key): """Button clicked handler""" - if name == 'restoredefaults': + if key == 'restoredefaults': self.__restore_defaults() - def __changed_cb(self, widget, name): + def __changed_cb(self, widget, key): """Combobox changed handler""" val = widget.get_active() - vtype = type(OPTION_DEFAULTS[name]) + vtype = type(OPTION_DEFAULTS[key]) if vtype == bool: val = False if val == 0 else True - self.__set_value(name, val) + self.__set_value(key, val) - def __value_changed_cb(self, widget, name): + def __value_changed_cb(self, widget, key): """scale widget value changed handler""" val = widget.get_value() - vtype = type(OPTION_DEFAULTS[name]) + vtype = type(OPTION_DEFAULTS[key]) if vtype == int: val = int(val) - self.__set_value(name, val) + self.__set_value(key, val) - def __entry_changed_cb(self, widget, property_spec, name): + def __entry_changed_cb(self, widget, property_spec, key): """entry widget text changed handler""" val = widget.get_text() - vtype = type(OPTION_DEFAULTS[name]) + vtype = type(OPTION_DEFAULTS[key]) if vtype != type(u''): val = val.decode('UTF-8') - self.__set_value(name, val) - - def __config_value_changed_cb(self, config, section, name, val): - """__config engine value changed handler""" - val = val.unpack() - if name in SCALE_WIDGETS: - __hscale = self.__builder.get_object("hscale%s" % name) - __hscale.set_value(val) - elif name in ENTRY_WIDGETS: - __entry = self.__builder.get_object("entry%s" % name) - __entry.set_text(val) + self.__set_value(key, val) + + def on_gsettings_value_changed(self, settings, key): + """ + Called when a value in the settings has been changed. + """ + value = it_util.variant_to_value(self.__gsettings.get_value(key)) + sys.stderr.write('Settings changed: key=%s value=%s\n' %(key, value)) + if key in SCALE_WIDGETS: + __hscale = self.__builder.get_object("hscale%s" % key) + __hscale.set_value(value) + elif key in ENTRY_WIDGETS: + __entry = self.__builder.get_object("entry%s" % key) + __entry.set_text(value) else: - __combobox = self.__builder.get_object("combobox%s" % name) - if isinstance(val, bool): - val = 1 if val else 0 - elif isinstance(val, str): - val = val.get_string() + __combobox = self.__builder.get_object("combobox%s" % key) + if isinstance(value, bool): + value = 1 if value else 0 + elif isinstance(value, str): model = __combobox.get_model() for i, row in enumerate(model): - if row[0] == val: - val = i + if row[0] == value: + value = i break - __combobox.set_active(val) - self.__values[name] = val + __combobox.set_active(value) + self.__user_values[key] = value - def __toggled_cb(self, widget, name): + def __toggled_cb(self, widget, key): """toggle button toggled signal handler""" - self.__set_value(name, widget.get_active ()) - - def __get_value(self, name, defval): - """Get the __config value if available""" - if name in self.__values: - var = self.__values[name] - if isinstance(defval, type(var)): - return var - self.__set_value(name, defval) - return defval - - def __set_value(self, name, val): - """Set the config value to __config""" + self.__set_value(key, widget.get_active ()) + + def __set_value(self, key, val): + """Set the _gsettings value""" var = None if isinstance(val, bool): var = GLib.Variant.new_boolean(val) @@ -496,8 +513,8 @@ def __set_value(self, name, val): sys.stderr.write("val(%s) is not in support type." %repr(val)) return - self.__values[name] = val - self.__config.set_value(self.__config_section, name, var) + self.__user_values[key] = val + self.__gsettings.set_value(key, var) def __run_message_dialog(self, message, message_type=Gtk.MessageType.INFO): dlg = Gtk.MessageDialog(parent=None, @@ -512,8 +529,9 @@ def run(self): ret = self.check_table_available() if not ret: return 0 - self.get_default_options_from_database() self.load_builder() + self.get_default_options_from_gsettings() + self.get_default_options_from_database() self.do_init() return self.__dialog.run() diff --git a/tests/test_it.py b/tests/test_it.py index d36ffdb9..b2f38968 100644 --- a/tests/test_it.py +++ b/tests/test_it.py @@ -125,7 +125,7 @@ def set_default_settings(): global ENGINE global TABSQLITEDB ENGINE.set_input_mode(mode=1) - chinese_mode = 0 + chinese_mode = 4 language_filter = TABSQLITEDB.ime_properties.get('language_filter') if language_filter in ['cm0', 'cm1', 'cm2', 'cm3', 'cm4']: chinese_mode = int(language_filter[-1]) @@ -136,7 +136,7 @@ def set_default_settings(): 'def_full_width_letter') if def_full_width_letter: letter_width_mode = (def_full_width_letter.lower() == u'true') - ENGINE.set_letter_width(mode=letter_width_mode, input_mode=0) + ENGINE.set_letter_width(mode=False, input_mode=0) ENGINE.set_letter_width(mode=letter_width_mode, input_mode=1) punctuation_width_mode = False @@ -144,7 +144,7 @@ def set_default_settings(): 'def_full_width_punct') if def_full_width_punct: punctuation_width_mode = (def_full_width_punct.lower() == u'true') - ENGINE.set_punctuation_width(mode=punctuation_width_mode, input_mode=0) + ENGINE.set_punctuation_width(mode=False, input_mode=0) ENGINE.set_punctuation_width(mode=punctuation_width_mode, input_mode=1) always_show_lookup_mode = True