diff options
Diffstat (limited to 'src/jarabe/model')
-rw-r--r-- | src/jarabe/model/Makefile.am | 1 | ||||
-rw-r--r-- | src/jarabe/model/accessibility.py | 160 | ||||
-rw-r--r-- | src/jarabe/model/bundleregistry.py | 156 |
3 files changed, 294 insertions, 23 deletions
diff --git a/src/jarabe/model/Makefile.am b/src/jarabe/model/Makefile.am index d40fb8d..8b37ee7 100644 --- a/src/jarabe/model/Makefile.am +++ b/src/jarabe/model/Makefile.am @@ -1,6 +1,7 @@ sugardir = $(pythondir)/jarabe/model sugar_PYTHON = \ adhoc.py \ + accessibility.py \ __init__.py \ buddy.py \ bundleregistry.py \ diff --git a/src/jarabe/model/accessibility.py b/src/jarabe/model/accessibility.py new file mode 100644 index 0000000..6910b2b --- /dev/null +++ b/src/jarabe/model/accessibility.py @@ -0,0 +1,160 @@ +# Copyright (C) 2010 Plan Ceibal +# +# Author: Esteban Arias <earias@plan.ceibal.edu.uy> +# Contact information: comunidad@plan.ceibal.edu.uy +# Plan Ceibal http://www.ceibal.edu.uy +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + +from gi.repository import Gtk +from gi.repository import GConf +import subprocess + +class Keyboard: + + def get_mouse_keys(self): + client = GConf.Client.get_default() + return client.get_bool("/desktop/sugar/accessibility/keyboard/mousekeys_enable") + + def set_mouse_keys(self, activar): + client = GConf.Client.get_default() + client.set_bool("/desktop/sugar/accessibility/keyboard/mousekeys_enable", activar) + self.run_config_keyboard() + + def get_sticky_keys(self): + client = GConf.Client.get_default() + return client.get_bool("/desktop/sugar/accessibility/keyboard/stickykeys_enable") + + def set_sticky_keys(self, activar): + client = GConf.Client.get_default() + client.set_bool("/desktop/sugar/accessibility/keyboard/stickykeys_enable", activar) + self.run_config_keyboard() + + def get_bounce_keys(self): + client = GConf.Client.get_default() + return client.get_bool("/desktop/sugar/accessibility/keyboard/bouncekeys_enable") + + def set_bounce_keys(self, activar): + client = GConf.Client.get_default() + client.set_bool("/desktop/sugar/accessibility/keyboard/bouncekeys_enable", activar) + self.run_config_keyboard() + + def run_config_keyboard(self): + cmd = ['ax'] + if self.get_sticky_keys(): + cmd.append('+stickykeys') + else: + cmd.append('-stickykeys') + if self.get_bounce_keys(): + cmd.append('+bouncekeys') + else: + cmd.append('-bouncekeys') + if self.get_mouse_keys(): + cmd += ['+mousekeys', 'mousemaxspeed', '3000', 'mousetimetomax', '1000', '-timeout', '-repeatkeys'] + else: + cmd += ['-mousekeys', 'mousemaxspeed', '3000', 'mousetimetomax', '1000', '+timeout', '+repeatkeys'] + subprocess.call(cmd) + +class Screen: + + DEFAULT_THEME = "sugar" + DEFAULT_FONT_SIZE = 7 + DEFAULT_FONT_FACE = "Sans Serif" + CONTRAST_THEME = "sugar-contrast" + CONTRAST_FONT_SIZE = 9.5 + CAPITAL_LETTERS_FONT_FACE = "Oracle" + + def get_contrast(self): + client = GConf.Client.get_default() + value = client.get_string("/desktop/sugar/interface/Gtk_theme") + return value==self.CONTRAST_THEME + + def set_contrast(self, activar): + client = GConf.Client.get_default() + if (activar): + client.set_string("/desktop/sugar/interface/Gtk_theme", self.CONTRAST_THEME) + client.set_float('/desktop/sugar/font/default_size', self.CONTRAST_FONT_SIZE) + else: + client.set_string("/desktop/sugar/interface/Gtk_theme", self.DEFAULT_THEME) + client.set_float('/desktop/sugar/font/default_size', self.DEFAULT_FONT_SIZE) + + def get_capital_letters(self): + client = GConf.Client.get_default() + value = client.get_string("/desktop/sugar/font/default_face") + return value==self.CAPITAL_LETTERS_FONT_FACE + + def set_capital_letters(self, activar): + client = GConf.Client.get_default() + if (activar): + client.set_string('/desktop/sugar/font/default_face', self.CAPITAL_LETTERS_FONT_FACE) + else: + client.set_string('/desktop/sugar/font/default_face', self.DEFAULT_FONT_FACE) + + +class Mouse: + + WHITE_CURSOR_THEME="FlatbedCursors.White.Huge" + DEFAULT_CURSOR_THEME="sugar" + DEFAULT_ACCEL_MOUSE=3 + + def get_white_mouse(self): + client = GConf.Client.get_default() + value = client.get_string("/desktop/sugar/peripherals/mouse/cursor_theme") + return value==self.WHITE_CURSOR_THEME + + def set_white_mouse(self, activar): + client = GConf.Client.get_default() + if (activar): + client.set_string("/desktop/sugar/peripherals/mouse/cursor_theme", self.WHITE_CURSOR_THEME) + else: + client.set_string("/desktop/sugar/peripherals/mouse/cursor_theme", self.DEFAULT_CURSOR_THEME) + + def _set_white_mouse_setting(self): + cursor_theme = self.DEFAULT_CURSOR_THEME + if (self.get_white_mouse()): + cursor_theme = self.WHITE_CURSOR_THEME + settings = Gtk.Settings.get_default() + settings.set_property("gtk-cursor-theme-name", "%s" % (cursor_theme)) + + def get_accel_mouse(self): + client = GConf.Client.get_default() + value = client.get_float("/desktop/sugar/peripherals/mouse/motion_acceleration") + return value + + def set_accel_mouse(self, value): + client = GConf.Client.get_default() + client.set_float("/desktop/sugar/peripherals/mouse/motion_acceleration", value) + self.run_config_mouse() + + def _set_accel_mouse_setting(self): + cmd = ['xset', 'm' , str(self.get_accel_mouse())] + subprocess.call(cmd) + + def run_config_mouse(self): + self._set_accel_mouse_setting() + self._set_white_mouse_setting() + +class AccessibilityManager: + def setup_accessibility(self): + client = GConf.Client.get_default() + is_accessibility = client.dir_exists("/desktop/sugar/accessibility") + mouse = Mouse() + if is_accessibility: + keyboard = Keyboard() + keyboard.run_config_keyboard() + mouse.run_config_mouse() + else: + mouse.set_accel_mouse(mouse.DEFAULT_ACCEL_MOUSE) + mouse.set_white_mouse(False) + mouse._set_accel_mouse_setting() diff --git a/src/jarabe/model/bundleregistry.py b/src/jarabe/model/bundleregistry.py index e441122..6fd4563 100644 --- a/src/jarabe/model/bundleregistry.py +++ b/src/jarabe/model/bundleregistry.py @@ -59,15 +59,18 @@ class BundleRegistry(GObject.GObject): self._bundles = [] # hold a reference to the monitors so they don't get disposed self._gio_monitors = [] + self._monitor = {} + self._handler_id = {} + self._allow_file_monitoring = True user_path = env.get_user_activities_path() for activity_dir in [user_path, config.activities_path]: self._scan_directory(activity_dir) directory = Gio.File.new_for_path(activity_dir) - monitor = directory.monitor_directory( \ - flags=Gio.FileMonitorFlags.NONE, cancellable=None) - monitor.connect('changed', self.__file_monitor_changed_cb) - self._gio_monitors.append(monitor) + self._monitor = directory.monitor_directory( \ + flags=Gio.FileMonitorFlags.NONE, cancellable=None) + self._handler_id = self._monitor.connect('changed', self.__file_monitor_changed_cb) + self._gio_monitors.append(self._monitor) self._last_defaults_mtime = -1 self._favorite_bundles = {} @@ -94,12 +97,31 @@ class BundleRegistry(GObject.GObject): def __file_monitor_changed_cb(self, monitor, one_file, other_file, event_type): - if not one_file.get_path().endswith('.activity'): - return - if event_type == Gio.FileMonitorEvent.CREATED: - self.add_bundle(one_file.get_path(), install_mime_type=True) - elif event_type == Gio.FileMonitorEvent.DELETED: - self.remove_bundle(one_file.get_path()) + if self._allow_file_monitoring: + if not one_file.get_path().endswith('.activity'): + return + if event_type == Gio.FileMonitorEvent.CREATED: + if self.get_bundle_by_path(one_file.get_path()) is None: + self.add_bundle(one_file.get_path(),install_mime_type=True) + elif event_type == Gio.FileMonitorEvent.DELETED: + self.remove_bundle(one_file.get_path()) + + # I tried 2 hours, trying to make the following mechanisms for + # event-blocking, work :: + # + # a. disconnect + # b. handler_disconnect + # c. handler_block/handler_unblock + # d. handler_block_by_func/handler_unblock_by_func + # + # I could not. + # + # In the end, I had to revert to using the oldy-goldy boolean flag. + def disable_directory_monitoring(self): + self._allow_file_monitoring = False + + def enable_directory_monitoring(self): + self._allow_file_monitoring = True def _load_mime_defaults(self): defaults = {} @@ -186,6 +208,12 @@ class BundleRegistry(GObject.GObject): return bundle return None + def get_bundle_by_path(self, bundle_path): + for bundle in self._bundles: + if bundle.get_path() == bundle_path: + return bundle + return None + def __iter__(self): return self._bundles.__iter__() @@ -213,7 +241,13 @@ class BundleRegistry(GObject.GObject): bundle_dirs.sort(lambda d1, d2: cmp(bundles[d1], bundles[d2])) for folder in bundle_dirs: try: - self._add_bundle(folder) + # sl#2818 + # + # Add meta-info, to indicate that this is a startup + # operation. + # + # See 'elif not startup' notes in 'self._add_bundle()' + self._add_bundle(folder, False, True) except: # pylint: disable=W0702 logging.exception('Error while processing installed activity' @@ -222,15 +256,13 @@ class BundleRegistry(GObject.GObject): def add_bundle(self, bundle_path, install_mime_type=False): bundle = self._add_bundle(bundle_path, install_mime_type) if bundle is not None: - self._set_bundle_favorite(bundle.get_bundle_id(), - bundle.get_activity_version(), - True) self.emit('bundle-added', bundle) return True else: return False - def _add_bundle(self, bundle_path, install_mime_type=False): + def _add_bundle(self, bundle_path, install_mime_type=False, + startup=False): logging.debug('STARTUP: Adding bundle %r', bundle_path) try: bundle = ActivityBundle(bundle_path) @@ -250,17 +282,90 @@ class BundleRegistry(GObject.GObject): return None else: logging.debug('Upgrade %s', bundle_id) + + # Query if the bundle is a favorite... + self._is_bundle_favorite = \ + self.is_bundle_favorite(installed.get_bundle_id(), + installed.get_activity_version()) + + # ...and then, remove the old bundle (we have the new + # one !!) self.remove_bundle(installed.get_path()) - self._bundles.append(bundle) + # Check, if this bundle-id is a favorite. + if self._is_bundle_favorite: + + # Mark the (new) bundle with this bundle-id, as + # favorite. + self.set_bundle_favorite(bundle.get_bundle_id(), + bundle.get_activity_version(), + True, + True) + + # This (new) bundle is new (!!), and is also a + # favorite. Add this to Favorites-View. + self.emit('bundle-added', bundle) + + elif not startup: + + # Ticket sl#2818 + + # Sub-case + # -------- + # The bundle is newly added; so set it as favorite as + # default, so that it is promptly available to the + # user. + # Note that, any newly added bundles during system + # startup, are not new-bundles-as-such. They were + # new, when they were first added, and their + # favorite-status set at that time. + # However, from code point of view, control reaches + # here, only if the bundle IS newly added by + # user-discretion. + self.set_bundle_favorite(bundle.get_bundle_id(), + bundle.get_activity_version(), + True, + True) + + # Emit 'bundle-added' (of course, this bundle is new !!), + # so that it is added in Favorites-View. + self.emit('bundle-added', bundle) + + + # In either case, + # a. Startup + # b. Upgrade of bundle + # c, Addition of new bundle, by user-discretion. + # add the bundle to bundles-list. + self.add_bundle_to_bundlelist(bundle) return bundle + def add_bundle_to_bundlelist(self, bundle): + for bundle_in_list in self._bundles: + if bundle_in_list.get_path() == \ + bundle.get_path(): + return False + + self._bundles.append(bundle) + return True + def remove_bundle(self, bundle_path): for bundle in self._bundles: if bundle.get_path() == bundle_path: + # This bundle is going. + # Remove it from bundles list... self._bundles.remove(bundle) + + # ... and remove it from Favorites-List... + self.set_bundle_favorite(bundle.get_bundle_id(), + bundle.get_activity_version(), + False, + True) + + # ...and remove its trace from Favorites-View. self.emit('bundle-removed', bundle) return True + return False def get_activities_for_type(self, mime_type): @@ -293,14 +398,22 @@ class BundleRegistry(GObject.GObject): if bundle.get_bundle_id() == bundle_id and \ bundle.get_activity_version() == version: return bundle - raise ValueError('No bundle %r with version %r exists.' % \ - (bundle_id, version)) + return None + + def set_bundle_favorite(self, bundle_id, version, favorite, + force=False): + # Return if file monitoring is not allowed, and the previous + # bundle is not a favorite. + if not force: + if not self._allow_file_monitoring: + if not self._is_bundle_favorite: + return - def set_bundle_favorite(self, bundle_id, version, favorite): changed = self._set_bundle_favorite(bundle_id, version, favorite) if changed: bundle = self._find_bundle(bundle_id, version) - self.emit('bundle-changed', bundle) + if bundle is not None: + self.emit('bundle-changed', bundle) def _set_bundle_favorite(self, bundle_id, version, favorite): key = self._get_favorite_key(bundle_id, version) @@ -426,9 +539,6 @@ class BundleRegistry(GObject.GObject): bundle.uninstall(install_path, force, delete_profile) - if not self.remove_bundle(install_path): - raise RegistrationException - def upgrade(self, bundle): act = self.get_bundle(bundle.get_bundle_id()) if act is None: |