From 1e5581bf5d538d7a8d5a05fa001e5a109879c041 Mon Sep 17 00:00:00 2001 From: Sayamindu Dasgupta Date: Sun, 26 Jul 2009 22:33:51 +0000 Subject: Initial code with GUI working. Backend does not work yet. --- diff --git a/data/icons/module-keyboard.svg b/data/icons/module-keyboard.svg new file mode 100644 index 0000000..43bbc57 --- /dev/null +++ b/data/icons/module-keyboard.svg @@ -0,0 +1,134 @@ + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/extensions/cpsection/keyboard/__init__.py b/extensions/cpsection/keyboard/__init__.py new file mode 100644 index 0000000..2f159a1 --- /dev/null +++ b/extensions/cpsection/keyboard/__init__.py @@ -0,0 +1,22 @@ +# Copyright (C) 2008, OLPC +# +# 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 St, Fifth Floor, Boston, MA 02110-1301 USA + +from gettext import gettext as _ + +CLASS = 'Keyboard' +ICON = 'module-keyboard' +TITLE = _('Keyboard') + diff --git a/extensions/cpsection/keyboard/model.py b/extensions/cpsection/keyboard/model.py new file mode 100644 index 0000000..9828963 --- /dev/null +++ b/extensions/cpsection/keyboard/model.py @@ -0,0 +1,118 @@ +# Copyright (C) 2007, 2008 One Laptop Per Child +# +# 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 St, Fifth Floor, Boston, MA 02110-1301 USA +# + +import xklavier +import gobject +import gconf + + +GRP_NAME = 'grp' # The XKB name for group switch options + +LAYOUTS_KEY = '/desktop/sugar/peripherals/keyboard/layouts' +OPTIONS_KEY = '/desktop/sugar/peripherals/keyboard/options' +MODEL_KEY = '/desktop/sugar/peripherals/keyboard/model' + +class XKB(gobject.GObject): + def __init__(self, display): + gobject.GObject.__init__(self) + + self._engine = xklavier.Engine(display) + self._configreg = xklavier.ConfigRegistry(self._engine) + self._configreg.load(False) + self._configrec = xklavier.ConfigRec() + self._configrec.get_from_server(self._engine) + + self._gconf_client = gconf.client_get_default() + + def _populate_one(self, c_reg, item, store): + store.append([item.get_description(), item.get_name()]) + + def _populate_two(self, c_reg, item, subitem, store): + layout = item.get_name() + if subitem: + desc = '%s, %s' % (subitem.get_description(), item.get_description()) + variant = subitem.get_name() + else: + desc = 'Default layout, %s' % item.get_description() + variant = '' + + store.append([desc, ('%s(%s)' % (layout, variant))]) + + def get_models(self): + models = [] + self._configreg.foreach_model(self._populate_one, models) + models.sort() + return models + + def get_languages(self): + languages = [] + self._configreg.foreach_language(self._populate_one, languages) + languages.sort() + return languages + + def get_layouts_for_language(self, language): + layouts = [] + self._configreg.foreach_language_variant(language, self._populate_two, layouts) + layouts.sort() + return layouts + + def get_options_grp(self): + options = [] + self._configreg.foreach_option(GRP_NAME, self._populate_one, options) + options.sort() + return options + + def get_current_model(self): + model = self._gconf_client.get_string(MODEL_KEY) + if model: + return model + else: + return self._configrec.get_model() + + def get_current_layouts(self): + layouts = self._gconf_client.get_list(LAYOUTS_KEY, 'string') + if layouts: + return layouts + + layouts = self._configrec.get_layouts() + variants = self._configrec.get_variants() + + ret = [] + i = 0 + for layout in layouts: + if len(variants) <= i or variants[i] == '': + ret.append('%s(%s)' % (layout, '')) + else: + ret.append('%s(%s)' % (layout, variants[i])) + i += 1 + + return ret + + def get_current_option_grp(self): + options = self._gconf_client.get_list(OPTIONS_KEY, 'string') + + if not options: + options = self._configrec.get_options() + + for option in options: + if option.startswith(GRP_NAME): + return option + + return None + + def get_max_layouts(self): + return self._engine.get_max_num_groups() diff --git a/extensions/cpsection/keyboard/view.py b/extensions/cpsection/keyboard/view.py new file mode 100644 index 0000000..148cec7 --- /dev/null +++ b/extensions/cpsection/keyboard/view.py @@ -0,0 +1,319 @@ +# Copyright (C) 2008, OLPC +# +# 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 St, Fifth Floor, Boston, MA 02110-1301 USA + +import gtk +import gobject +import pango +from gettext import gettext as _ + +from sugar.graphics import style +from sugar.graphics.icon import Icon + +from jarabe.controlpanel.sectionview import SectionView +from jarabe.controlpanel.inlinealert import InlineAlert + +CLASS = 'Language' +ICON = 'module-keyboard' +TITLE = _('Keyboard') + +class LayoutCombo(gtk.HBox): + __gsignals__ = { + 'selection-changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, + (gobject.TYPE_STRING, gobject.TYPE_INT)) + } + def __init__(self, xkb, n): + gtk.HBox.__init__(self) + self._xkb = xkb + self._index = n + + self.set_border_width(style.DEFAULT_SPACING) + self.set_spacing(style.DEFAULT_SPACING) + + label = gtk.Label(' %s ' % str(n+1)) + label.set_use_markup(True) + label.modify_fg(gtk.STATE_NORMAL, + style.COLOR_SELECTION_GREY.get_gdk_color()) + label.set_alignment(0.5, 0.5) + self.pack_start(label, expand=False) + + self._klang_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING) + for description, name in self._xkb.get_languages(): + self._klang_store.append([name, description]) + + self._klang_combo = gtk.ComboBox(model = self._klang_store) + self._klang_combo_changed_id = \ + self._klang_combo.connect('changed', self._klang_combo_changed_cb) + cell = gtk.CellRendererText() + cell.props.ellipsize = pango.ELLIPSIZE_MIDDLE + self._klang_combo.pack_start(cell) + self._klang_combo.add_attribute(cell, 'text', 1) + self.pack_start(self._klang_combo, expand=True, fill = True) + + self._kvariant_store = None + self._kvariant_combo = gtk.ComboBox(model = None) + self._kvariant_combo_changed_id = \ + self._kvariant_combo.connect('changed', self._kvariant_combo_changed_cb) + cell = gtk.CellRendererText() + cell.props.ellipsize = pango.ELLIPSIZE_MIDDLE + self._kvariant_combo.pack_start(cell) + self._kvariant_combo.add_attribute(cell, 'text', 1) + self.pack_start(self._kvariant_combo, expand=True, fill = True) + + self._klang_combo.set_active(self._index) + + def select_layout(self, layout): + self._kvariant_combo.handler_block(self._kvariant_combo_changed_id) + for i in range(0, len(self._klang_store)): + self._klang_combo.set_active(i) + for j in range(0, len(self._kvariant_store)): + if self._kvariant_store[j][0] == layout: + self._kvariant_combo.set_active(j) + self._kvariant_combo.handler_unblock(self._kvariant_combo_changed_id) + return True + + self._kvariant_combo.handler_unblock(self._kvariant_combo_changed_id) + self._klang_combo.set_active(0) + return False + + def get_layout(self): + iter = self._kvariant_combo.get_active_iter() + model = self._kvariant_combo.get_model() + return model.get(iter, 0)[0] + + def _set_kvariant_store(self, lang): + self._kvariant_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING) + for description, name in self._xkb.get_layouts_for_language(lang): + self._kvariant_store.append([name, description]) + self._kvariant_combo.set_model(self._kvariant_store) + self._kvariant_combo.set_active(0) + + def _klang_combo_changed_cb(self, combobox): + it = combobox.get_active_iter() + model = combobox.get_model() + lang = model.get(it, 0)[0] + self._set_kvariant_store(lang) + + def _kvariant_combo_changed_cb(self, combobox): + it = combobox.get_active_iter() + model = combobox.get_model() + layout = model.get(it, 0)[0] + self.emit('selection-changed', layout, self._index) + + +class Keyboard(SectionView): + def __init__(self, model, alerts): + SectionView.__init__(self) + + self._model = model + + self._kmodel = None + self._selected_kmodel = None + self._klayout = [] + self._selected_klayout = [] + self._kgrpswitch_option = None + self._selected_kgrpswitch_option = None + + self.set_border_width(style.DEFAULT_SPACING * 2) + self.set_spacing(style.DEFAULT_SPACING) + + self._layout_table = gtk.Table(rows = 4, columns = 2, homogeneous = False) + + self._xkb = model.XKB(self.get_display()) + self._layout_combo_list = [] + self._layout_addremovebox_list = [] + + scrollwindow = gtk.ScrolledWindow() + scrollwindow.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) + self.pack_start(scrollwindow, expand=True) + scrollwindow.show() + + self._vbox = gtk.VBox() + scrollwindow.add_with_viewport(self._vbox) + + self._kmodel_sid = None + self._layout_sid = None + self._group_switch_option_sid = None + + self._setup_kmodel() + self._setup_layouts() + self._setup_group_switch_option() + + self._vbox.show() + + def _setup_kmodel(self): + separator_kmodel = gtk.HSeparator() + self._vbox.pack_start(separator_kmodel, expand=False) + separator_kmodel.show_all() + + label_kmodel = gtk.Label(_('Keyboard Model')) + label_kmodel.set_alignment(0, 0) + self._vbox.pack_start(label_kmodel, expand=False) + label_kmodel.show_all() + + box_kmodel = gtk.VBox() + box_kmodel.set_border_width(style.DEFAULT_SPACING * 2) + box_kmodel.set_spacing(style.DEFAULT_SPACING) + + self._kmodel_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING) + for description, name in self._xkb.get_models(): + self._kmodel_store.append([name, description]) + + self._kmodel_combo = gtk.ComboBox(model = self._kmodel_store) + cell = gtk.CellRendererText() + self._kmodel_combo.pack_start(cell) + self._kmodel_combo.add_attribute(cell, 'text', 1) + + self._kmodel = self._xkb.get_current_model() + for row in self._kmodel_store: + if self._kmodel in row[0]: + self._kmodel_combo.set_active_iter(row.iter) + break + + box_kmodel.pack_start(self._kmodel_combo, expand = False) + self._vbox.pack_start(box_kmodel, expand=False) + box_kmodel.show_all() + + def _setup_group_switch_option(self): + separator_grp_option = gtk.HSeparator() + self._vbox.pack_start(separator_grp_option, expand=False) + separator_grp_option.show_all() + + label_grp_option = gtk.Label(_('Key(s) to change layout')) + label_grp_option.set_alignment(0, 0) + self._vbox.pack_start(label_grp_option, expand=False) + label_grp_option.show_all() + + box_grp_option = gtk.VBox() + box_grp_option.set_border_width(style.DEFAULT_SPACING * 2) + box_grp_option.set_spacing(style.DEFAULT_SPACING) + + self._grp_option_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING) + for description, name in self._xkb.get_options_grp(): + self._grp_option_store.append([name, description]) + + self._grp_option_combo = gtk.ComboBox(model = self._grp_option_store) + cell = gtk.CellRendererText() + self._grp_option_combo.pack_start(cell) + self._grp_option_combo.add_attribute(cell, 'text', 1) + + current_grp_option = self._xkb.get_current_option_grp() + if not current_grp_option: + self._grp_option_combo.set_active(0) + else: + found = False + for row in self._grp_option_store: + if current_grp_option in row[0]: + self._kmodel_combo.set_active_iter(row.iter) + found = True + break + if not found: + self._grp_option_combo.set_active(0) + + box_grp_option.pack_start(self._grp_option_combo, expand = False) + self._vbox.pack_start(box_grp_option, expand=False) + box_grp_option.show_all() + + def _setup_layouts(self): + separator_klayout = gtk.HSeparator() + self._vbox.pack_start(separator_klayout, expand=False) + separator_klayout.show_all() + + label_klayout = gtk.Label(_('Keyboard Layout(s)')) + label_klayout.set_alignment(0, 0) + label_klayout.show_all() + self._vbox.pack_start(label_klayout, expand=False) + + self._klayouts = self._xkb.get_current_layouts() + self._selected_klayouts = None + for i in range(0, self._xkb.get_max_layouts()): + add_remove_box = self.__create_add_remove_box() + self._layout_addremovebox_list.append(add_remove_box) + self._layout_table.attach(add_remove_box, 1, 2, i, i+1) + + layout_combo = LayoutCombo(self._xkb, i) + layout_combo.connect('selection-changed', \ + self.__layout_combo_selection_changed_cb) + self._layout_combo_list.append(layout_combo) + self._layout_table.attach(layout_combo, 0, 1, i, i+1) + + if i < len(self._klayouts): + layout_combo.show_all() + layout_combo.select_layout(self._klayouts[i]) + + self._vbox.pack_start(self._layout_table, expand=False) + self._layout_table.set_size_request(self._vbox.size_request()[0], -1) + self._layout_table.show() + self._update_klayouts() + + def __determine_add_remove_box_visibility(self): + i = 1 + for box in self._layout_addremovebox_list: + if not i == len(self._selected_klayouts): + box.props.visible = False + else: + box.show_all() + if i == 1: + # First row - no need for showing remove + add, remove = box.get_children() + remove.props.visible = False + if i == self._xkb.get_max_layouts(): + # Last row - no need for showing add + add, remove = box.get_children() + add.props.visible = False + i += 1 + + def __create_add_remove_box(self): + '''Creates gtk.Hbox with add/remove buttons''' + add_icon = Icon(icon_name='list-add') + + add_button = gtk.Button() + add_button.set_image(add_icon) + add_button.connect('clicked', + self.__add_button_clicked_cb) + + remove_icon = Icon(icon_name='list-remove') + remove_button = gtk.Button() + remove_button.set_image(remove_icon) + remove_button.connect('clicked', + self.__remove_button_clicked_cb) + + add_remove_box = gtk.HButtonBox() + add_remove_box.set_layout(gtk.BUTTONBOX_START) + add_remove_box.set_spacing(10) + add_remove_box.pack_start(add_button) + add_remove_box.pack_start(remove_button) + + return add_remove_box + + def __layout_combo_selection_changed_cb(self, combo, layout, index): + self._update_klayouts() + + def __add_button_clicked_cb(self, button): + self._layout_combo_list[len(self._selected_klayouts)].show_all() + self._update_klayouts() + + def __remove_button_clicked_cb(self, button): + self._layout_combo_list[len(self._selected_klayouts) - 1].hide() + self._update_klayouts() + + def _update_klayouts(self): + self._selected_klayouts = [] + for combo in self._layout_combo_list: + if combo.props.visible: + self._selected_klayouts.append(combo.get_layout()) + + self.__determine_add_remove_box_visibility() + -- cgit v0.9.1