# vim:set noet ts=4: # # ibus-anthy - The Anthy engine for IBus # # Copyright (c) 2007-2008 Peng Huang # Copyright (c) 2009 Hideaki ABE # Copyright (c) 2010-2017 Takao Fujiwara # Copyright (c) 2007-2017 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 import require_version as gi_require_version gi_require_version('Gio', '2.0') gi_require_version('GLib', '2.0') gi_require_version('IBus', '1.0') from gi.repository import Gio from gi.repository import GLib from gi.repository import GObject from gi.repository import IBus class DictItem(): def __init__(self, id='', short_label='', long_label='', icon='', is_system=False, preview_lines=-1, embed=False, single=True, reverse=False, encoding='utf-8'): self.id = id self.short_label = short_label self.long_label = long_label self.icon = icon self.is_system = is_system self.preview_lines = preview_lines self.embed = embed self.single = single self.reverse = reverse self.encoding = encoding def __str__(self): retval = ('id:', self.id, 'short-label:', self.short_label, 'long-label:', self.long_label, 'icon:', self.icon, 'is-system:', self.is_system, 'preview-lines:', self.preview_lines, 'embed:', self.embed, 'single:', self.single, 'reverse:', self.reverse, 'encoding:', self.encoding) return str(retval) @classmethod def serialize(cls, dict_item): builder = GLib.VariantBuilder(GLib.VariantType('r')) builder.add_value(GLib.Variant.new_string(dict_item.id)) builder.add_value(GLib.Variant.new_string(dict_item.short_label)) builder.add_value(GLib.Variant.new_string(dict_item.long_label)) builder.add_value(GLib.Variant.new_string(dict_item.icon)) builder.add_value(GLib.Variant.new_boolean(dict_item.is_system)) builder.add_value(GLib.Variant.new_int32(dict_item.preview_lines)) builder.add_value(GLib.Variant.new_boolean(dict_item.embed)) builder.add_value(GLib.Variant.new_boolean(dict_item.single)) builder.add_value(GLib.Variant.new_boolean(dict_item.reverse)) builder.add_value(GLib.Variant.new_string(dict_item.encoding)) return builder.end() class Prefs(GObject.GObject): __gsignals__ = { 'changed' : ( GObject.SignalFlags.RUN_FIRST, None, (str, str, GLib.Variant)), } def __init__(self): super(Prefs, self).__init__() self.__cache = {} self.__settings = {} self.__schema_prefix = 'org.freedesktop.ibus.engine.anthy.' self.__schema_sections = ['common', 'shortcut', 'romaji-typing-rule', 'kana-typing-rule', 'thumb-typing-rule', 'thumb', 'dict'] for section in self.__schema_sections: self.__settings[section] = Gio.Settings( schema=self.__schema_prefix + section) self.__settings[section].connect('changed', self.__settings_on_changed) def __settings_on_changed(self, settings, key): section = settings.props.schema[len(self.__schema_prefix):] variant_value = self.__settings[section].get_value(key) variant_key = self.__cache.get(section) if variant_key == None: variant_key = {} variant_key[key] = variant_value self.__cache[section] = variant_key self.emit('changed', section, key, variant_value) 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 == 'v': return variant.unpack() elif len(type_string) > 0 and type_string[0] == 'a': # 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 variant_from_value(self, value): variant = None if type(value) == str: variant = GLib.Variant.new_string(value) elif type(value) == int: variant = GLib.Variant.new_int32(value) elif type(value) == bool: variant = GLib.Variant.new_boolean(value) elif type(value) == list: variant = GLib.Variant.new_strv(value) if variant == None: self.printerr('Unknown value type: %s' % type(value)) return variant def get_variant(self, section, key): variant_key = self.__cache.get(section) if variant_key != None: variant_value = variant_key.get(key) if variant_value != None: return variant_value variant_value = self.__settings[section].get_value(key) if variant_key == None: variant_key = {} variant_key[key] = variant_value self.__cache[section] = variant_key return variant_value def get_default_variant(self, section, key): return self.__settings[section].get_default_value(key) def get_readable_value(self, section, key, variant): value = self.variant_to_value(variant) if section == 'dict' and key == 'list': dicts = {} for item in value: dict_item = DictItem(*item) dicts[dict_item.id] = dict_item value = dicts if section == 'dict' and key == 'template': value = DictItem(*value) return value def get_value(self, section, key): variant = self.get_variant(section, key) return self.get_readable_value(section, key, variant) def get_default_value(self, section, key): variant = self.get_default_variant(section, key) return self.get_readable_value(section, key, variant) def set_variant(self, section, key, variant): self.__settings[section].set_value(key, variant) self.__settings[section].apply() def set_value(self, section, key, value): variant = self.variant_from_value(value) if variant == None: return self.set_variant(section, key, variant) def set_list_item(self, section, key, item, values): variant = self.get_variant(section, key) if variant == None: printerrr('%s:%s does not exist' % (section, key)) return if section == 'shortcut': variant_dict = GLib.VariantDict(variant) array = [] for value in values: array.append(GLib.Variant.new_string(value)) varray = GLib.Variant.new_array(GLib.VariantType('s'), array) variant_dict.insert_value(item, varray) # GVariantDict uses GHashTable internally and # GVariantDict.end() does not support the order. self.set_variant(section, key, variant_dict.end()) return if section == 'romaji-typing-rule' or \ section == 'kana-typing-rule' or \ section == 'thumb-typing-rule': (method, keymap_key) = item variant_dict = GLib.VariantDict(variant) keymap = variant_dict.lookup_value(method, None) keymap_dict = GLib.VariantDict(keymap) if section == 'thumb-typing-rule': array = [] for value in values: array.append(GLib.Variant.new_string(value)) vvalue = GLib.Variant.new_array(GLib.VariantType('s'), array) else: vvalue = GLib.Variant.new_string(values) keymap_dict.insert_value(keymap_key, vvalue) keymap = keymap_dict.end() variant_dict.insert_value(method, keymap) self.set_variant(section, key, variant_dict.end()) return if section == 'dict' and key == 'files': variant_dict = GLib.VariantDict(variant) array = [] for value in values: array.append(GLib.Variant.new_string(value)) varray = GLib.Variant.new_array(GLib.VariantType('s'), array) variant_dict.insert_value(item, varray) self.set_variant(section, key, variant_dict.end()) return if section == 'dict' and key == 'list': array = [] has_item = False for v in variant: dict_item = DictItem(*v) if dict_item.id == values.id: array.append(GLib.Variant.new_variant( DictItem.serialize(values))) has_item = True else: array.append(GLib.Variant.new_variant( DictItem.serialize(dict_item))) if not has_item: array.append(GLib.Variant.new_variant(DictItem.serialize(values))) varray = GLib.Variant.new_array(GLib.VariantType('v'), array) self.set_variant(section, key, varray) return def delete_list_item(self, section, key, item): variant = self.get_variant(section, key) if variant == None: printerrr('%s:%s does not exist' % (section, key)) return if section == 'romaji-typing-rule' or \ section == 'kana-typing-rule' or \ section == 'thumb-typing-rule': (method, keymap_key) = item variant_dict = GLib.VariantDict(variant) keymap = variant_dict.lookup_value(method, None) keymap_dict = GLib.VariantDict(keymap) keymap_dict.remove(keymap_key) keymap = keymap_dict.end() variant_dict.insert_value(method, keymap) self.set_variant(section, key, variant_dict.end()) return if section == 'dict' and key == 'files': variant_dict = GLib.VariantDict(variant) variant_dict.remove(item) self.set_variant(section, key, variant_dict.end()) return if section == 'dict' and key == 'list': array = [] for v in variant: dict_item = DictItem(*v) if dict_item.id == item: continue else: array.append(GLib.Variant.new_variant( DictItem.serialize(dict_item))) varray = GLib.Variant.new_array(GLib.VariantType('v'), array) self.set_variant(section, key, varray) return def bind(self, section, key, object, property, flags): self.__settings[section].bind(key, object, property, flags) # 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