From c54fb84b28cca54c7d0cb0355b7a21f3cbabfc4d Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Wed, 15 Aug 2007 12:19:29 +0200 Subject: [PATCH 1/2] #2543: Offer multiple activities for opening clipboard objects. --- NEWS | 2 + services/shell/clipboardobject.py | 5 +-- services/shell/clipboardservice.py | 8 ++-- shell/view/clipboardmenu.py | 60 +++++++++++++++++++++++++---- sugar/clipboard/clipboardservice.py | 10 ++--- sugar/datastore/datastore.py | 3 ++ 6 files changed, 68 insertions(+), 20 deletions(-) diff --git a/NEWS b/NEWS index 0068c953..52999cb6 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,5 @@ +* #2543: Offer multiple activities for opening clipboard objects. + Snapshot d93122bf5e * #2751 Add keybindings for max/min brightness/volume diff --git a/services/shell/clipboardobject.py b/services/shell/clipboardobject.py index bc51f472..65f3bc56 100644 --- a/services/shell/clipboardobject.py +++ b/services/shell/clipboardobject.py @@ -65,16 +65,15 @@ class ClipboardObject: #return self._get_type_info().get_preview() return '' - def get_activity(self): + def get_activities(self): mime = self.get_mime_type() if not mime: return '' registry = bundleregistry.get_registry() activities = registry.get_activities_for_type(self.get_mime_type()) - # TODO: should we return several activities? if activities: - return activities[0].get_service_name() + return [activity.get_service_name() for activity in activities] else: return '' diff --git a/services/shell/clipboardservice.py b/services/shell/clipboardservice.py index 19958a7c..90e1b8ee 100644 --- a/services/shell/clipboardservice.py +++ b/services/shell/clipboardservice.py @@ -33,7 +33,7 @@ NAME_KEY = 'NAME' PERCENT_KEY = 'PERCENT' ICON_KEY = 'ICON' PREVIEW_KEY = 'PREVIEW' -ACTIVITY_KEY = 'ACTIVITY' +ACTIVITIES_KEY = 'ACTIVITIES' FORMATS_KEY = 'FORMATS' TYPE_KEY = 'TYPE' @@ -87,7 +87,7 @@ class ClipboardService(dbus.service.Object): PERCENT_KEY: cb_object.get_percent(), ICON_KEY: cb_object.get_icon(), PREVIEW_KEY: cb_object.get_preview(), - ACTIVITY_KEY: cb_object.get_activity()}) + ACTIVITIES_KEY: cb_object.get_activities()}) @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE, in_signature="o", out_signature="") @@ -121,7 +121,7 @@ class ClipboardService(dbus.service.Object): PERCENT_KEY: percent, ICON_KEY: cb_object.get_icon(), PREVIEW_KEY: cb_object.get_preview(), - ACTIVITY_KEY: cb_object.get_activity()}) + ACTIVITIES_KEY: cb_object.get_activities()}) @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE, in_signature="o", out_signature="a{sv}") @@ -142,7 +142,7 @@ class ClipboardService(dbus.service.Object): PERCENT_KEY: cb_object.get_percent(), ICON_KEY: cb_object.get_icon(), PREVIEW_KEY: cb_object.get_preview(), - ACTIVITY_KEY: cb_object.get_activity(), + ACTIVITIES_KEY: cb_object.get_activities(), FORMATS_KEY: format_types} return dbus.Dictionary(result_dict) diff --git a/shell/view/clipboardmenu.py b/shell/view/clipboardmenu.py index 28ea0bb6..3acf90ee 100644 --- a/shell/view/clipboardmenu.py +++ b/shell/view/clipboardmenu.py @@ -30,16 +30,17 @@ from sugar.clipboard import clipboardservice from sugar.datastore import datastore from sugar.objects import mime from sugar import profile +from sugar import activity class ClipboardMenu(Palette): - def __init__(self, object_id, name, percent, preview, activity, installable): + def __init__(self, object_id, name, percent, preview, activities, installable): Palette.__init__(self, name) self.props.position = Palette.RIGHT self._object_id = object_id self._percent = percent - self._activity = activity + self._activities = activities self.set_group_id('frame') @@ -68,7 +69,8 @@ class ClipboardMenu(Palette): self._remove_item.show() self._open_item = MenuItem(_('Open'), 'stock-keep') - self._open_item.connect('activate', self._open_item_activate_cb) + self._open_item_activate_sid = self._open_item.connect('activate', + self._open_item_activate_cb) self.menu.append(self._open_item) self._open_item.show() @@ -83,14 +85,49 @@ class ClipboardMenu(Palette): self._journal_item.show() self._update_items_visibility(installable) + self._update_open_submenu() + + def _update_open_submenu(self): + submenu = self._open_item.get_submenu() + if submenu: + for item in submenu.get_children(): + submenu.remove(item) + + if self._activities is None or len(self._activities) <= 1: + if self._open_item_activate_sid is None: + self._open_item_activate_sid = self._open_item.connect( + 'activate', + self._open_item_activate_cb) + return + else: + if self._open_item_activate_sid is not None: + self._open_item.disconnect(self._open_item_activate_sid) + self._open_item_activate_sid = None + + if not submenu: + submenu = gtk.Menu() + self._open_item.set_submenu(submenu) + submenu.show() + + for service_name in self._activities: + registry = activity.get_registry() + activity_info = registry.get_activity(service_name) + + if not activity_info: + logging.warning('Activity %s is unknown.' % service_name) + + item = gtk.MenuItem(activity_info.name) + item.connect('activate', self._open_submenu_item_activate_cb, service_name) + submenu.append(item) + item.show() def _update_items_visibility(self, installable): - if self._percent == 100 and (self._activity or installable): + if self._percent == 100 and (self._activities or installable): self._remove_item.props.sensitive = True self._open_item.props.sensitive = True #self._stop_item.props.sensitive = False self._journal_item.props.sensitive = True - elif self._percent == 100 and (not self._activity and not installable): + elif self._percent == 100 and (not self._activities and not installable): self._remove_item.props.sensitive = True self._open_item.props.sensitive = False #self._stop_item.props.sensitive = False @@ -112,19 +149,26 @@ class ClipboardMenu(Palette): self._progress_bar.props.fraction = self._percent / 100.0 self._progress_bar.props.text = '%.2f %%' % self._percent - def set_state(self, name, percent, preview, activity, installable): + def set_state(self, name, percent, preview, activities, installable): self.set_primary_text(name) self._percent = percent - self._activity = activity + self._activities = activities if self._progress_bar: self._update_progress_bar() self._update_items_visibility(installable) + self._update_open_submenu() def _open_item_activate_cb(self, menu_item): if self._percent < 100: return jobject = self._copy_to_journal() - jobject.resume() + jobject.resume(self._activities[0]) + + def _open_submenu_item_activate_cb(self, menu_item, service_name): + if self._percent < 100: + return + jobject = self._copy_to_journal() + jobject.resume(service_name) def _remove_item_activate_cb(self, menu_item): cb_service = clipboardservice.get_instance() diff --git a/sugar/clipboard/clipboardservice.py b/sugar/clipboard/clipboardservice.py index dbdf41d1..0e357fef 100644 --- a/sugar/clipboard/clipboardservice.py +++ b/sugar/clipboard/clipboardservice.py @@ -23,7 +23,7 @@ NAME_KEY = 'NAME' PERCENT_KEY = 'PERCENT' ICON_KEY = 'ICON' PREVIEW_KEY = 'PREVIEW' -ACTIVITY_KEY = 'ACTIVITY' +ACTIVITIES_KEY = 'ACTIVITIES' FORMATS_KEY = 'FORMATS' TYPE_KEY = 'TYPE' @@ -51,7 +51,7 @@ class ClipboardService(gobject.GObject): 'object-deleted': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([str])), 'object-state-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, - ([str, str, int, str, str, str])), + ([str, str, int, str, str, object])), } def __init__(self): @@ -118,13 +118,13 @@ class ClipboardService(gobject.GObject): percent icon preview - activity + activities From the ClipboardObject instance which is being described. """ self.emit('object-state-changed', str(object_id), values[NAME_KEY], values[PERCENT_KEY], values[ICON_KEY], values[PREVIEW_KEY], - values[ACTIVITY_KEY]) + values[ACTIVITIES_KEY]) def add_object(self, name): """Add a new object to the path @@ -193,7 +193,7 @@ class ClipboardService(gobject.GObject): PERCENT_KEY: number, ICON_KEY: str, PREVIEW_KEY: XXX what is it?, - ACTIVITY_KEY: source activity id, + ACTIVITIES_KEY: activities that can open this object, FORMATS_KEY: list of XXX what is it? """ return self._dbus_service.get_object(dbus.ObjectPath(object_id),) diff --git a/sugar/datastore/datastore.py b/sugar/datastore/datastore.py index 5ba994db..0dbe35bd 100644 --- a/sugar/datastore/datastore.py +++ b/sugar/datastore/datastore.py @@ -120,6 +120,9 @@ class DSObject(object): def resume(self, service_name=None): if self.is_bundle(): + if service_name is not None: + raise ValueError('Object is a bundle, cannot be resumed as an activity.') + bundle = Bundle(self.file_path) if not bundle.is_installed(): bundle.install() From 26c5ad6ad05d5d1eba9bfefb092ad2245caa5a94 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Wed, 15 Aug 2007 09:19:40 -0400 Subject: [PATCH 2/2] Rewrite dbus_helpers to not make a dbus connection on import. #2773 --- sugar/datastore/dbus_helpers.py | 38 ++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/sugar/datastore/dbus_helpers.py b/sugar/datastore/dbus_helpers.py index f0cfa3bf..442a35d0 100644 --- a/sugar/datastore/dbus_helpers.py +++ b/sugar/datastore/dbus_helpers.py @@ -28,55 +28,63 @@ DS_DBUS_SERVICE = "org.laptop.sugar.DataStore" DS_DBUS_INTERFACE = "org.laptop.sugar.DataStore" DS_DBUS_PATH = "/org/laptop/sugar/DataStore" -_bus = dbus.SessionBus() -_data_store = dbus.Interface(_bus.get_object(DS_DBUS_SERVICE, DS_DBUS_PATH), - DS_DBUS_INTERFACE) +_data_store = None + +def _get_data_store(): + global _data_store + + if not _data_store: + _bus = dbus.SessionBus() + _data_store = dbus.Interface(_bus.get_object(DS_DBUS_SERVICE, + DS_DBUS_PATH), + DS_DBUS_INTERFACE) + return _data_store def create(properties, filename): - object_id = _data_store.create(dbus.Dictionary(properties), filename) + object_id = _get_data_store().create(dbus.Dictionary(properties), filename) logging.debug('dbus_helpers.create: ' + object_id) return object_id def update(uid, properties, filename, reply_handler=None, error_handler=None, timeout=-1): logging.debug('dbus_helpers.update: %s, %s, %s' % (uid, filename, properties)) if reply_handler and error_handler: - _data_store.update(uid, dbus.Dictionary(properties), filename, + _get_data_store().update(uid, dbus.Dictionary(properties), filename, reply_handler=reply_handler, error_handler=error_handler, timeout=timeout) else: - _data_store.update(uid, dbus.Dictionary(properties), filename) + _get_data_store().update(uid, dbus.Dictionary(properties), filename) def delete(uid): logging.debug('dbus_helpers.delete: %r' % uid) - _data_store.delete(uid) + _get_data_store().delete(uid) def get_properties(uid): logging.debug('dbus_helpers.get_properties: %s' % uid) - return _data_store.get_properties(uid) + return _get_data_store().get_properties(uid) def get_filename(uid): - filename = _data_store.get_filename(uid) + filename = _get_data_store().get_filename(uid) logging.debug('dbus_helpers.get_filename: %s, %s' % (uid, filename)) return filename def find(query, reply_handler, error_handler): logging.debug('dbus_helpers.find: %r' % query) if reply_handler and error_handler: - return _data_store.find(query, reply_handler=reply_handler, + return _get_data_store().find(query, reply_handler=reply_handler, error_handler=error_handler) else: - return _data_store.find(query) + return _get_data_store().find(query) def mount(uri, options): - return _data_store.mount(uri, options) + return _get_data_store().mount(uri, options) def unmount(mount_point_id): - _data_store.unmount(mount_point_id) + _get_data_store().unmount(mount_point_id) def mounts(): - return _data_store.mounts() + return _get_data_store().mounts() def get_unique_values(key): - return _data_store.get_uniquevaluesfor(key, dbus.Dictionary({}, signature='ss')) + return _get_data_store().get_uniquevaluesfor(key, dbus.Dictionary({}, signature='ss'))