From fcb57779a275e8a3343b71f991c23cb98f5c1e7a Mon Sep 17 00:00:00 2001 From: Marco Pesenti Gritti Date: Wed, 11 Apr 2007 16:14:58 +0200 Subject: [PATCH] Start reworking the cliboard services to use the types registry. --- services/clipboard/Makefile.am | 8 +- services/clipboard/clipboardobject.py | 22 +-- services/clipboard/clipboardservice.py | 50 ++--- services/clipboard/typeregistry.py | 243 ------------------------- shell/view/clipboardicon.py | 57 ++---- shell/view/clipboardmenu.py | 45 ++++- shell/view/frame/clipboardbox.py | 11 +- sugar/clipboard/clipboardservice.py | 24 +-- 8 files changed, 91 insertions(+), 369 deletions(-) delete mode 100644 services/clipboard/typeregistry.py diff --git a/services/clipboard/Makefile.am b/services/clipboard/Makefile.am index a656ee2f..28282702 100644 --- a/services/clipboard/Makefile.am +++ b/services/clipboard/Makefile.am @@ -7,11 +7,9 @@ $(service_DATA): $(service_in_files) Makefile sugardir = $(pkgdatadir)/services/clipboard sugar_PYTHON = \ - __init__.py \ - clipboardobject.py \ - clipboardservice.py \ - typeregistry.py - + __init__.py \ + clipboardobject.py \ + clipboardservice.py bin_SCRIPTS = sugar-clipboard diff --git a/services/clipboard/clipboardobject.py b/services/clipboard/clipboardobject.py index 919acd00..385de080 100644 --- a/services/clipboard/clipboardobject.py +++ b/services/clipboard/clipboardobject.py @@ -1,7 +1,4 @@ -import typeregistry - class ClipboardObject: - def __init__(self, object_path, name): self._id = object_path self._name = name @@ -11,24 +8,8 @@ class ClipboardObject: def get_id(self): return self._id - def _get_type_info(self): - type_registry = typeregistry.get_instance() - return type_registry.get_type(self._formats) - def get_name(self): - if self._name: - return self._name - else: - return self._get_type_info().get_name() - - def get_icon(self): - return self._get_type_info().get_icon() - - def get_preview(self): - return self._get_type_info().get_preview() - - def get_activity(self): - return self._get_type_info().get_activity() + return self._name def get_percent(self): return self._percent @@ -43,7 +24,6 @@ class ClipboardObject: return self._formats class Format: - def __init__(self, type, data, on_disk): self._type = type self._data = data diff --git a/services/clipboard/clipboardservice.py b/services/clipboard/clipboardservice.py index 0ed423b5..2616ea77 100644 --- a/services/clipboard/clipboardservice.py +++ b/services/clipboard/clipboardservice.py @@ -27,9 +27,6 @@ import typeregistry NAME_KEY = 'NAME' PERCENT_KEY = 'PERCENT' -ICON_KEY = 'ICON' -PREVIEW_KEY = 'PREVIEW' -ACTIVITY_KEY = 'ACTIVITY' FORMATS_KEY = 'FORMATS' class ClipboardDBusServiceHelper(dbus.service.Object): @@ -51,6 +48,18 @@ class ClipboardDBusServiceHelper(dbus.service.Object): self._next_id += 1 return self._next_id + def _get_object_dict(self, object_path): + cb_object = self._objects[str(object_path)] + formats = cb_object.get_formats() + format_types = dbus.Array([], 's') + + for type, format in formats.iteritems(): + format_types.append(type) + + return { NAME_KEY: cb_object.get_name(), + PERCENT_KEY: cb_object.get_percent(), + FORMATS_KEY: format_types } + def _handle_file_completed(self, cb_object): """If the object is an on-disk file, and it's at 100%, and we care about it's file type, copy that file to $HOME and upate the clipboard object's @@ -63,10 +72,6 @@ class ClipboardDBusServiceHelper(dbus.service.Object): if not format.get_on_disk(): return - if not len(cb_object.get_activity()): - # no activity to handle this, don't autosave it - return - # copy to homedir src = format.get_data() if not os.path.exists(src): @@ -100,11 +105,7 @@ class ClipboardDBusServiceHelper(dbus.service.Object): else: logging.debug('Added in-memory format of type ' + format_type + '.') - self.object_state_changed(object_path, {NAME_KEY: cb_object.get_name(), - PERCENT_KEY: cb_object.get_percent(), - ICON_KEY: cb_object.get_icon(), - PREVIEW_KEY: cb_object.get_preview(), - ACTIVITY_KEY: cb_object.get_activity()}) + self.object_changed(object_path, self._get_object_dict(object_path)) @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE, in_signature="o", out_signature="") @@ -130,29 +131,12 @@ class ClipboardDBusServiceHelper(dbus.service.Object): if percent == 100: self._handle_file_completed(cb_object) - self.object_state_changed(object_path, {NAME_KEY: cb_object.get_name(), - PERCENT_KEY: percent, - ICON_KEY: cb_object.get_icon(), - PREVIEW_KEY: cb_object.get_preview(), - ACTIVITY_KEY: cb_object.get_activity()}) + self.object_state_changed(object_path, { PERCENT_KEY: percent }) @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE, in_signature="o", out_signature="a{sv}") def get_object(self, object_path): - cb_object = self._objects[str(object_path)] - formats = cb_object.get_formats() - format_types = dbus.Array([], 's') - - for type, format in formats.iteritems(): - format_types.append(type) - - result_dict = {NAME_KEY: cb_object.get_name(), - PERCENT_KEY: cb_object.get_percent(), - ICON_KEY: cb_object.get_icon(), - PREVIEW_KEY: cb_object.get_preview(), - ACTIVITY_KEY: cb_object.get_activity(), - FORMATS_KEY: format_types} - return dbus.Dictionary(result_dict) + return dbus.Dictionary(self._get_object_dict(object_path)) @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE, in_signature="os", out_signature="ay") @@ -166,6 +150,10 @@ class ClipboardDBusServiceHelper(dbus.service.Object): def object_added(self, object_path, name): pass + @dbus.service.signal(_CLIPBOARD_DBUS_INTERFACE, signature="oa{sv}") + def object_changed(self, object_path, values): + pass + @dbus.service.signal(_CLIPBOARD_DBUS_INTERFACE, signature="o") def object_deleted(self, object_path): pass diff --git a/services/clipboard/typeregistry.py b/services/clipboard/typeregistry.py deleted file mode 100644 index b794cee9..00000000 --- a/services/clipboard/typeregistry.py +++ /dev/null @@ -1,243 +0,0 @@ -import logging -from gettext import gettext as _ - -class FileType: - def __init__(self, formats): - self._formats = formats - - def get_name(self): - raise NotImplementedError - - def get_icon(self): - raise NotImplementedError - - def get_preview(self): - raise NotImplementedError - - def get_activity(self): - raise NotImplementedError - - def matches_mime_type(cls, mime_type): - raise NotImplementedError - matches_mime_type = classmethod(matches_mime_type) - -class TextFileType(FileType): - - _types = set(['text/plain', 'UTF8_STRING', 'STRING']) - - def get_name(self): - return _('Text snippet') - - def get_icon(self): - return 'theme:object-text' - - def get_preview(self): - for format, data in self._formats.iteritems(): - if format in TextFileType._types: - text = data.get_data() - if len(text) < 50: - return text - else: - return text[0:49] + "..." - - return '' - - def get_activity(self): - return 'org.laptop.AbiWordActivity' - - def matches_mime_type(cls, mime_type): - return mime_type in cls._types - matches_mime_type = classmethod(matches_mime_type) - -class ImageFileType(FileType): - - _types = set(['image/jpeg', 'image/gif', 'image/png', 'image/tiff']) - - def get_name(self): - return _('Image') - - def get_icon(self): - return 'theme:object-image' - - def get_preview(self): - return '' - - def get_activity(self): - return '' - - def matches_mime_type(cls, mime_type): - return mime_type in cls._types - matches_mime_type = classmethod(matches_mime_type) - -class UriFileType(FileType): - - _types = set(['_NETSCAPE_URL']) - - def get_name(self): - return _('Web Page') - - def get_icon(self): - return 'theme:object-link' - - def get_preview(self): - for format, data in self._formats.iteritems(): - if format in UriFileType._types: - string = data.get_data() - title = string.split("\n")[1] - return title - - return '' - - def get_activity(self): - return '' - - def matches_mime_type(cls, mime_type): - return mime_type in cls._types - matches_mime_type = classmethod(matches_mime_type) - -class PdfFileType(FileType): - - _types = set(['application/pdf', 'application/x-pdf']) - - def get_name(self): - return _('PDF file') - - def get_icon(self): - return 'theme:object-text' - - def get_preview(self): - return '' - - def get_activity(self): - return 'org.laptop.sugar.Xbook' - - def matches_mime_type(cls, mime_type): - return mime_type in cls._types - matches_mime_type = classmethod(matches_mime_type) - -class MsWordFileType(FileType): - - _types = set(['application/msword']) - - def get_name(self): - return _('MS Word file') - - def get_icon(self): - return 'theme:object-text' - - def get_preview(self): - return '' - - def get_activity(self): - return 'org.laptop.AbiWordActivity' - - def matches_mime_type(cls, mime_type): - return mime_type in cls._types - matches_mime_type = classmethod(matches_mime_type) - -class RtfFileType(TextFileType): - - _types = set(['application/rtf', 'text/rtf']) - - def get_name(self): - return _('RTF file') - - def matches_mime_type(cls, mime_type): - return mime_type in cls._types - matches_mime_type = classmethod(matches_mime_type) - -class AbiwordFileType(TextFileType): - - _types = set(['application/x-abiword']) - - def get_name(self): - return _('Abiword file') - - def matches_mime_type(cls, mime_type): - return mime_type in cls._types - matches_mime_type = classmethod(matches_mime_type) - -class SqueakProjectFileType(FileType): - - _types = set(['application/x-squeak-project']) - - def get_name(self): - return _('Squeak project') - - def get_icon(self): - return 'theme:object-squeak-project' - - def get_preview(self): - return '' - - def get_activity(self): - return 'org.vpri.EtoysActivity' - - def matches_mime_type(cls, mime_type): - return mime_type in cls._types - matches_mime_type = classmethod(matches_mime_type) - -class OOTextFileType(FileType): - - _types = set(['application/vnd.oasis.opendocument.text']) - - def get_name(self): - return _('OpenOffice text file') - - def get_icon(self): - return 'theme:object-text' - - def get_preview(self): - return '' - - def get_activity(self): - return 'org.laptop.AbiWordActivity' - - def matches_mime_type(cls, mime_type): - return mime_type in cls._types - matches_mime_type = classmethod(matches_mime_type) - -class UnknownFileType(FileType): - def get_name(self): - return _('Object') - - def get_icon(self): - return 'theme:stock-missing' - - def get_preview(self): - return '' - - def get_activity(self): - return '' - - def matches_mime_type(cls, mime_type): - return true - matches_mime_type = classmethod(matches_mime_type) - -class TypeRegistry: - def __init__(self): - self._types = [] - self._types.append(PdfFileType) - self._types.append(MsWordFileType) - self._types.append(RtfFileType) - self._types.append(OOTextFileType) - self._types.append(UriFileType) - self._types.append(ImageFileType) - self._types.append(AbiwordFileType) - self._types.append(TextFileType) - self._types.append(SqueakProjectFileType) - - def get_type(self, formats): - for file_type in self._types: - for format, data in formats.iteritems(): - if file_type.matches_mime_type(format): - return file_type(formats) - - return UnknownFileType(formats) - -_type_registry = None -def get_instance(): - global _type_registry - if not _type_registry: - _type_registry = TypeRegistry() - return _type_registry diff --git a/shell/view/clipboardicon.py b/shell/view/clipboardicon.py index ef0de29e..e6b4a3f0 100644 --- a/shell/view/clipboardicon.py +++ b/shell/view/clipboardicon.py @@ -44,7 +44,6 @@ class ClipboardIcon(CanvasIcon): self._name = name self._percent = 0 self._preview = None - self._activity = None self._selected = False self._hover = False self.props.box_width = units.grid_to_pixels(1) @@ -74,60 +73,26 @@ class ClipboardIcon(CanvasIcon): self.props.background_color = color.TOOLBAR_BACKGROUND.get_int() def get_popup(self): - self._menu = ClipboardMenu(self._name, self._percent, self._preview, - self._activity) + self._menu = ClipboardMenu(self._name, self._percent, self._preview) self._menu.connect('action', self._popup_action_cb) return self._menu def get_popup_context(self): return self._popup_context - def set_state(self, name, percent, icon_name, preview, activity): + def set_name(self, name): self._name = name - self._percent = percent - self._preview = preview - self._activity = activity - self.set_property("icon_name", icon_name) if self._menu: - self._menu.set_state(name, percent, preview, activity) + self._menu.set_title(name) + + def set_formats(self, formats): + self._preview = None + self.props.icon_name = 'theme:stock-missing' - if activity and percent < 100: - self.props.xo_color = XoColor("#000000,#424242") - else: - self.props.xo_color = XoColor("#000000,#FFFFFF") - - if activity and percent == 100: - # FIXME: restrict based on file type rather than activity once - # we have a better type registry - # restrict auto-open to a specific set of activities - allowed = ["org.laptop.AbiWordActivity", - "org.laptop.sugar.Xbook", - "org.vpri.EtoysActivity"] - if activity in allowed: - self._open_file() - - def _open_file(self): - if self._percent < 100 or not self._activity: - return - - # Get the file path - cb_service = clipboardservice.get_instance() - obj = cb_service.get_object(self._object_id) - formats = obj['FORMATS'] - if len(formats) > 0: - path = cb_service.get_object_data(self._object_id, formats[0]) - - # FIXME: would be better to check for format.onDisk - try: - path_exists = os.path.exists(path) - except TypeError: - path_exists = False - - if path_exists: - uri = 'file://' + path - activityfactory.create_with_uri(self._activity, uri) - else: - logging.debug("Clipboard item file path %s didn't exist" % path) + def set_state(self, percent): + self._percent = percent + if self._menu: + self._menu.set_state(percent) def _popup_action_cb(self, popup, menu_item): action = menu_item.props.action_id diff --git a/shell/view/clipboardmenu.py b/shell/view/clipboardmenu.py index 3e8239d6..96999728 100644 --- a/shell/view/clipboardmenu.py +++ b/shell/view/clipboardmenu.py @@ -33,9 +33,11 @@ class ClipboardMenu(Menu): ACTION_OPEN = 1 ACTION_STOP_DOWNLOAD = 2 - def __init__(self, name, percent, preview, activity): + def __init__(self, name, percent, preview): Menu.__init__(self, name) self.props.border = 0 + + self._activities = None if percent < 100: self._progress_bar = ClipboardProgressBar(percent) @@ -54,10 +56,10 @@ class ClipboardMenu(Menu): self._preview_text.props.font_desc = font.DEFAULT.get_pango_desc() self.append(self._preview_text) - self._update_icons(percent, activity) + self._update_icons(percent) - def _update_icons(self, percent, activity): - if percent == 100 and activity: + def _update_icons(self, percent): + if percent == 100 and self._activities: if not self._remove_item: self._remove_item = MenuItem(ClipboardMenu.ACTION_DELETE, _('Remove'), @@ -73,7 +75,7 @@ class ClipboardMenu(Menu): if self._stop_item: self.remove_item(self._stop_item) self._stop_item = None - elif percent == 100 and not activity: + elif percent == 100 and not self._activities: if not self._remove_item: self._remove_item = MenuItem(ClipboardMenu.ACTION_DELETE, _('Remove'), @@ -102,8 +104,33 @@ class ClipboardMenu(Menu): self.remove_item(self._open_item) self._open_item = None - def set_state(self, name, percent, preview, activity): - self.set_title(name) + def _open_file(self): + if self._percent < 100 or not self._activity: + return + + # Get the file path + cb_service = clipboardservice.get_instance() + obj = cb_service.get_object(self._object_id) + formats = obj['FORMATS'] + if len(formats) > 0: + path = cb_service.get_object_data(self._object_id, formats[0]) + + # FIXME: would be better to check for format.onDisk + try: + path_exists = os.path.exists(path) + except TypeError: + path_exists = False + + if path_exists: + uri = 'file://' + path + activityfactory.create_with_uri(self._activity, uri) + else: + logging.debug("Clipboard item file path %s didn't exist" % path) + + def set_activities(self, activities): + self._activities = activities + + def set_state(self, percent): if self._progress_bar: - self._progress_bar.set_property('percent', percent) - self._update_icons(percent, activity) + self._progress_bar.props.percent = percent + self._update_icons(percent) diff --git a/shell/view/frame/clipboardbox.py b/shell/view/frame/clipboardbox.py index 2dcad10e..1baca587 100644 --- a/shell/view/frame/clipboardbox.py +++ b/shell/view/frame/clipboardbox.py @@ -52,6 +52,7 @@ class ClipboardBox(hippo.CanvasBox): cb_service = clipboardservice.get_instance() cb_service.connect('object-added', self._object_added_cb) cb_service.connect('object-deleted', self._object_deleted_cb) + cb_service.connect('object-changed', self._object_changed_cb) cb_service.connect('object-state-changed', self._object_state_changed_cb) def owns_clipboard(self): @@ -136,10 +137,14 @@ class ClipboardBox(hippo.CanvasBox): del self._icons[object_id] logging.debug('ClipboardBox: ' + object_id + ' was deleted.') - def _object_state_changed_cb(self, cb_service, object_id, name, percent, - icon_name, preview, activity): + def _object_changed_cb(self, cb_service, object_id, name, formats): icon = self._icons[object_id] - icon.set_state(name, percent, icon_name, preview, activity) + icon.set_name(name) + icon.set_formats(formats) + + def _object_state_changed_cb(self, cb_service, object_id, percent): + icon = self._icons[object_id] + icon.set_state(percent) if icon.props.selected and percent == 100: self._put_in_clipboard(object_id) diff --git a/sugar/clipboard/clipboardservice.py b/sugar/clipboard/clipboardservice.py index c7d68e46..17f6998d 100644 --- a/sugar/clipboard/clipboardservice.py +++ b/sugar/clipboard/clipboardservice.py @@ -4,9 +4,6 @@ import gobject NAME_KEY = 'NAME' PERCENT_KEY = 'PERCENT' -ICON_KEY = 'ICON' -PREVIEW_KEY = 'PREVIEW' -ACTIVITY_KEY = 'ACTIVITY' FORMATS_KEY = 'FORMATS' DBUS_SERVICE = "org.laptop.Clipboard" @@ -14,14 +11,15 @@ DBUS_INTERFACE = "org.laptop.Clipboard" DBUS_PATH = "/org/laptop/Clipboard" class ClipboardService(gobject.GObject): - __gsignals__ = { - 'object-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, - ([str, str])), + 'object-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + ([str, str])), + 'object-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + ([str, str, gobject.TYPE_PYOBJECT])), 'object-deleted': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, - ([str])), + ([str])), 'object-state-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, - ([str, str, int, str, str, str])), + ([str, int])), } def __init__(self): @@ -54,6 +52,8 @@ class ClipboardService(gobject.GObject): self._object_deleted_cb) self._dbus_service.connect_to_signal('object_state_changed', self._object_state_changed_cb) + self._dbus_service.connect_to_signal('object_changed', + self._object_changed_cb) self._connected = True bus.remove_signal_receiver(self._nameOwnerChangedHandler) @@ -66,13 +66,15 @@ class ClipboardService(gobject.GObject): def _object_added_cb(self, object_id, name): self.emit('object-added', str(object_id), name) + def _object_changed_cb(self, object_id, values): + self.emit('object-changed', str(object_id), + values[NAME_KEY], values[FORMATS_KEY]) + def _object_deleted_cb(self, object_id): self.emit('object-deleted', str(object_id)) def _object_state_changed_cb(self, object_id, values): - self.emit('object-state-changed', str(object_id), values[NAME_KEY], - values[PERCENT_KEY], values[ICON_KEY], values[PREVIEW_KEY], - values[ACTIVITY_KEY]) + self.emit('object-state-changed', str(object_id), values[PERCENT_KEY]) def add_object(self, name): return str(self._dbus_service.add_object(name))