Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/src/jarabe/model
diff options
context:
space:
mode:
Diffstat (limited to 'src/jarabe/model')
-rw-r--r--src/jarabe/model/Makefile.am1
-rw-r--r--src/jarabe/model/accessibility.py160
-rw-r--r--src/jarabe/model/bundleregistry.py156
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: