Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSayamindu Dasgupta <sayamindu@gmail.com>2009-07-26 22:33:51 (GMT)
committer Sayamindu Dasgupta <sayamindu@gmail.com>2009-07-26 22:33:51 (GMT)
commit1e5581bf5d538d7a8d5a05fa001e5a109879c041 (patch)
tree1b2778798226e6fa81f345bd0fde8816403bf681
parent014a004eb2a708bd368f494e98a6c3705495cf76 (diff)
Initial code with GUI working.
Backend does not work yet.
-rw-r--r--data/icons/module-keyboard.svg134
-rw-r--r--extensions/cpsection/keyboard/__init__.py22
-rw-r--r--extensions/cpsection/keyboard/model.py118
-rw-r--r--extensions/cpsection/keyboard/view.py319
4 files changed, 593 insertions, 0 deletions
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 @@
+<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+ <!ENTITY stroke_color "#666666">
+ <!ENTITY fill_color "#ffffff">
+]><svg enable-background="new 0 0 55 55" height="55px" id="Layer_1" version="1.1" viewBox="0 0 55 55" width="55px" x="0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0px"><g display="block" id="module-keyboard">
+ <rect display="inline" fill="&fill_color;" height="23.326" width="54" x="0.5" y="15.837"/>
+ <g display="inline">
+ <path d="M52.61,28.081c0,0.55-0.45,1-1,1h-5.443c-0.55,0-1-0.45-1-1v-5.444c0-0.55,0.45-1,1-1h5.443c0.55,0,1,0.45,1,1V28.081z"/>
+ </g>
+ <g display="inline">
+ <path d="M52.61,19.941c0,0.55-0.45,1-1,1h-5.412c-0.55,0-1-0.45-1-1v-1.368c0-0.55,0.45-1,1-1h5.412c0.55,0,1,0.45,1,1V19.941z"/>
+ </g>
+ <g display="inline">
+ <path d="M52.61,32.267c0,0.55-0.45,1-1,1h-5.412c-0.55,0-1-0.45-1-1v-1.367c0-0.55,0.45-1,1-1h5.412c0.55,0,1,0.45,1,1V32.267z"/>
+ </g>
+ <g display="inline">
+ <path d="M39.11,36.403c0,0.55-0.45,1-1,1H13.176c-0.55,0-1-0.45-1-1v-1.366c0-0.55,0.45-1,1-1H38.11c0.55,0,1,0.45,1,1V36.403z"/>
+ </g>
+ <g display="inline">
+ <g>
+ <path d="M5.889,19.977c0,0.55-0.45,1-1,1H3.549c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1h1.339c0.55,0,1,0.45,1,1V19.977z"/>
+ </g>
+ <g>
+ <path d="M10.65,19.977c0,0.55-0.45,1-1,1H8.311c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1H9.65c0.55,0,1,0.45,1,1V19.977z"/>
+ </g>
+ <g>
+ <path d="M15.411,19.977c0,0.55-0.45,1-1,1h-1.339c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1h1.339c0.55,0,1,0.45,1,1V19.977z"/>
+ </g>
+ <g>
+ <path d="M20.173,19.978c0,0.55-0.45,1-1,1h-1.34c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.34c0.55,0,1,0.45,1,1V19.978z"/>
+ </g>
+ <g>
+ <path d="M24.934,19.977c0,0.55-0.45,1-1,1h-1.34c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1h1.34c0.55,0,1,0.45,1,1V19.977z"/>
+ </g>
+ <g>
+ <path d="M29.695,19.978c0,0.55-0.45,1-1,1h-1.34c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.34c0.55,0,1,0.45,1,1V19.978z"/>
+ </g>
+ <g>
+ <path d="M34.457,19.977c0,0.55-0.45,1-1,1h-1.341c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1h1.341c0.55,0,1,0.45,1,1V19.977z"/>
+ </g>
+ <g>
+ <path d="M39.218,19.977c0,0.55-0.45,1-1,1h-1.341c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1h1.341c0.55,0,1,0.45,1,1V19.977z"/>
+ </g>
+ <g>
+ <path d="M43.979,19.977c0,0.55-0.45,1-1,1h-1.341c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1h1.341c0.55,0,1,0.45,1,1V19.977z"/>
+ </g>
+ </g>
+ <g display="inline">
+ <g>
+ <path d="M5.889,24.038c0,0.55-0.45,1-1,1H3.549c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1h1.339c0.55,0,1,0.45,1,1V24.038z"/>
+ </g>
+ <g>
+ <path d="M10.65,24.038c0,0.55-0.45,1-1,1H8.311c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1H9.65c0.55,0,1,0.45,1,1V24.038z"/>
+ </g>
+ <g>
+ <path d="M15.411,24.038c0,0.55-0.45,1-1,1h-1.339c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1h1.339c0.55,0,1,0.45,1,1V24.038z"/>
+ </g>
+ <g>
+ <path d="M20.173,24.038c0,0.55-0.45,1-1,1h-1.34c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.34c0.55,0,1,0.45,1,1V24.038z"/>
+ </g>
+ <g>
+ <path d="M24.934,24.038c0,0.55-0.45,1-1,1h-1.34c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1h1.34c0.55,0,1,0.45,1,1V24.038z"/>
+ </g>
+ <g>
+ <path d="M29.695,24.038c0,0.55-0.45,1-1,1h-1.34c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.34c0.55,0,1,0.45,1,1V24.038z"/>
+ </g>
+ <g>
+ <path d="M34.457,24.038c0,0.55-0.45,1-1,1h-1.341c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1h1.341c0.55,0,1,0.45,1,1V24.038z"/>
+ </g>
+ <g>
+ <path d="M39.218,24.038c0,0.55-0.45,1-1,1h-1.341c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1h1.341c0.55,0,1,0.45,1,1V24.038z"/>
+ </g>
+ <g>
+ <path d="M43.979,24.038c0,0.55-0.45,1-1,1h-1.341c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1h1.341c0.55,0,1,0.45,1,1V24.038z"/>
+ </g>
+ </g>
+ <g display="inline">
+ <g>
+ <path d="M5.889,28.099c0,0.55-0.45,1-1,1.001H3.549c-0.55,0.001-1-0.449-1-0.999V26.76c0-0.55,0.45-1,1-1h1.339 c0.55,0,1,0.45,1,1V28.099z"/>
+ </g>
+ <g>
+ <path d="M10.65,28.099c0,0.55-0.45,1-1,1.001H8.311c-0.55,0.001-1-0.449-1-0.999V26.76c0-0.55,0.45-1,1-1H9.65c0.55,0,1,0.45,1,1 V28.099z"/>
+ </g>
+ <g>
+ <path d="M15.411,28.099c0,0.55-0.45,1-1,1L13.072,29.1c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.339c0.55,0,1,0.45,1,1 V28.099z"/>
+ </g>
+ <g>
+ <path d="M20.173,28.099c0,0.55-0.45,1-1,1l-1.34,0.001c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.34c0.55,0,1,0.45,1,1 V28.099z"/>
+ </g>
+ <g>
+ <path d="M24.934,28.099c0,0.55-0.45,1-1,1l-1.34,0.001c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.34c0.55,0,1,0.45,1,1 V28.099z"/>
+ </g>
+ <g>
+ <path d="M29.695,28.099c0,0.55-0.45,1-1,1l-1.34,0.001c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.34c0.55,0,1,0.45,1,1 V28.099z"/>
+ </g>
+ <g>
+ <path d="M34.457,28.099c0,0.55-0.45,1-1,1L32.116,29.1c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.341c0.55,0,1,0.45,1,1 V28.099z"/>
+ </g>
+ <g>
+ <path d="M39.218,28.099c0,0.55-0.45,1-1,1h-1.341c-0.55,0-1-0.45-1-1V26.76c0-0.55,0.45-1,1-1h1.341c0.55,0,1,0.45,1,1V28.099z"/>
+ </g>
+ <g>
+ <path d="M43.979,28.099c0,0.55-0.45,1-1,1h-1.341c-0.55,0-1-0.45-1-1V26.76c0-0.55,0.45-1,1-1h1.341c0.55,0,1,0.45,1,1V28.099z"/>
+ </g>
+ </g>
+ <g display="inline">
+ <g>
+ <path d="M5.889,32.161c0,0.55-0.45,1-1,1H3.549c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.339c0.55,0,1,0.45,1,1V32.161z"/>
+ </g>
+ <g>
+ <path d="M10.65,32.161c0,0.55-0.45,1-1,1H8.311c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1H9.65c0.55,0,1,0.45,1,1V32.161z"/>
+ </g>
+ <g>
+ <path d="M15.411,32.161c0,0.55-0.45,1-1,1h-1.339c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.339c0.55,0,1,0.45,1,1V32.161z"/>
+ </g>
+ <g>
+ <path d="M20.173,32.161c0,0.55-0.45,1-1,1h-1.34c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.34c0.55,0,1,0.45,1,1V32.161z"/>
+ </g>
+ <g>
+ <path d="M24.934,32.161c0,0.55-0.45,1-1,1h-1.34c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.34c0.55,0,1,0.45,1,1V32.161z"/>
+ </g>
+ <g>
+ <path d="M29.695,32.161c0,0.55-0.45,1-1,1h-1.34c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.34c0.55,0,1,0.45,1,1V32.161z"/>
+ </g>
+ <g>
+ <path d="M34.457,32.161c0,0.55-0.45,1-1,1h-1.341c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.341c0.55,0,1,0.45,1,1V32.161z"/>
+ </g>
+ <g>
+ <path d="M39.218,32.161c0,0.55-0.45,1-1,1h-1.341c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.341c0.55,0,1,0.45,1,1V32.161z"/>
+ </g>
+ <g>
+ <path d="M43.979,32.161c0,0.55-0.45,1-1,1h-1.341c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.341c0.55,0,1,0.45,1,1V32.161z"/>
+ </g>
+ </g>
+</g></svg> \ 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(' <b>%s</b> ' % 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()
+