Added icon, title and preview for clipboard objects. Also allow for opening docs and rtfs from the web.

This commit is contained in:
Tomeu Vizoso 2007-01-05 21:13:46 +01:00
parent 74e407f9ff
commit f50d9f5f9a
11 changed files with 308 additions and 64 deletions

View File

@ -9,7 +9,8 @@ sugardir = $(pkgdatadir)/services/clipboard
sugar_PYTHON = \ sugar_PYTHON = \
__init__.py \ __init__.py \
clipboardobject.py \ clipboardobject.py \
clipboardservice.py clipboardservice.py \
typeregistry.py
bin_SCRIPTS = sugar-clipboard bin_SCRIPTS = sugar-clipboard

View File

@ -1,3 +1,5 @@
import typeregistry
class ClipboardObject: class ClipboardObject:
def __init__(self, id, name): def __init__(self, id, name):
@ -8,10 +10,23 @@ class ClipboardObject:
def get_id(self): def get_id(self):
return self._id return self._id
def _get_type_info(self):
type_registry = typeregistry.get_instance()
return type_registry.get_type(self._formats)
def get_name(self): def get_name(self):
return self._name 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_percent(self): def get_percent(self):
return self._percent return self._percent
@ -23,7 +38,7 @@ class ClipboardObject:
def get_formats(self): def get_formats(self):
return self._formats return self._formats
class Format: class Format:
def __init__(self, type, data, on_disk): def __init__(self, type, data, on_disk):

View File

@ -19,8 +19,15 @@ import gobject
import dbus import dbus
import dbus.service import dbus.service
from sugar import env from sugar import env
from sugar import util
from clipboardobject import ClipboardObject, Format from clipboardobject import ClipboardObject, Format
NAME_KEY = 'NAME'
PERCENT_KEY = 'PERCENT'
ICON_KEY = 'ICON'
PREVIEW_KEY = 'PREVIEW'
FORMATS_KEY = 'FORMATS'
class ClipboardDBusServiceHelper(dbus.service.Object): class ClipboardDBusServiceHelper(dbus.service.Object):
_CLIPBOARD_DBUS_INTERFACE = "org.laptop.Clipboard" _CLIPBOARD_DBUS_INTERFACE = "org.laptop.Clipboard"
@ -43,21 +50,20 @@ class ClipboardDBusServiceHelper(dbus.service.Object):
logging.debug('Added object ' + object_id + ' with name ' + name) logging.debug('Added object ' + object_id + ' with name ' + name)
@dbus.service.method(_CLIPBOARD_DBUS_INTERFACE, @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE,
in_signature="ssayb", out_signature="") in_signature="ssayb", out_signature="", byte_arrays=True)
def add_object_format(self, object_id, format_type, data, on_disk): def add_object_format(self, object_id, format_type, data, on_disk):
# FIXME: Take it out when using the 0.80 dbus bindings
s = ""
for i in data:
s += chr(i)
cb_object = self._objects[object_id] cb_object = self._objects[object_id]
cb_object.add_format(Format(format_type, s, on_disk)) cb_object.add_format(Format(format_type, data, on_disk))
if on_disk: if on_disk:
logging.debug('Added format of type ' + format_type + ' with path at ' + s) logging.debug('Added format of type ' + format_type + ' with path at ' + data)
else: else:
logging.debug('Added in-memory format of type ' + format_type + '.') logging.debug('Added in-memory format of type ' + format_type + '.')
self.object_state_changed(object_id, {NAME_KEY: cb_object.get_name(),
PERCENT_KEY: cb_object.get_percent(),
ICON_KEY: cb_object.get_icon(),
PREVIEW_KEY: cb_object.get_preview()})
@dbus.service.method(_CLIPBOARD_DBUS_INTERFACE, @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE,
in_signature="s", out_signature="") in_signature="s", out_signature="")
@ -68,30 +74,39 @@ class ClipboardDBusServiceHelper(dbus.service.Object):
@dbus.service.method(_CLIPBOARD_DBUS_INTERFACE, @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE,
in_signature="si", out_signature="") in_signature="si", out_signature="")
def set_object_state(self, object_id, percent): def set_object_percent(self, object_id, percent):
cb_object = self._objects[object_id] cb_object = self._objects[object_id]
cb_object.set_percent(percent) cb_object.set_percent(percent)
self.object_state_changed(object_id, percent) self.object_state_changed(object_id, {NAME_KEY: cb_object.get_name(),
logging.debug('Changed object with object_id ' + object_id + ' with percent ' + str(percent)) PERCENT_KEY: percent,
ICON_KEY: cb_object.get_icon(),
PREVIEW_KEY: cb_object.get_preview()})
logging.debug('Changed object with object_id ' + object_id +
' with percent ' + str(percent))
@dbus.service.method(_CLIPBOARD_DBUS_INTERFACE, @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE,
in_signature="s", out_signature="as") in_signature="s", out_signature="a{sv}")
def get_object_format_types(self, object_id): def get_object(self, object_id):
cb_object = self._objects[object_id] cb_object = self._objects[object_id]
formats = cb_object.get_formats() formats = cb_object.get_formats()
array = [] format_types = []
for type, format in formats.iteritems(): for type, format in formats.iteritems():
array.append(type) format_types.append(type)
return array 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(),
FORMATS_KEY: format_types}
return result_dict
@dbus.service.method(_CLIPBOARD_DBUS_INTERFACE, @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE,
in_signature="ss", out_signature="ay") in_signature="ss", out_signature="ay")
def get_object_data(self, object_id, format_type): def get_object_data(self, object_id, format_type):
cb_object = self._objects[object_id] cb_object = self._objects[object_id]
formats = cb_object.get_formats() formats = cb_object.get_formats()
return formats[format_type].get_data() return formats[format_type].get_data()
# dbus signals # dbus signals
@ -103,8 +118,8 @@ class ClipboardDBusServiceHelper(dbus.service.Object):
def object_deleted(self, object_id): def object_deleted(self, object_id):
pass pass
@dbus.service.signal(_CLIPBOARD_DBUS_INTERFACE, signature="si") @dbus.service.signal(_CLIPBOARD_DBUS_INTERFACE, signature="sa{sv}")
def object_state_changed(self, object_id, percent): def object_state_changed(self, object_id, values):
pass pass
class ClipboardService(object): class ClipboardService(object):
@ -115,5 +130,5 @@ class ClipboardService(object):
loop = gobject.MainLoop() loop = gobject.MainLoop()
try: try:
loop.run() loop.run()
except idboardInterrupt: except KeyboardInterrupt:
print 'Ctrl+C pressed, exiting...' print 'Ctrl+C pressed, exiting...'

View File

@ -0,0 +1,169 @@
import logging
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 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 'activity-xbook'
def get_preview(self):
for format, data in self._formats.iteritems():
if format in TextFileType._types:
return str(data.get_data())
return ''
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 'activity-sketch'
def get_preview(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 'URL'
def get_icon(self):
return 'activity-web'
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 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'])
def get_name(self):
return 'PDF file'
def get_icon(self):
return 'activity-xbook'
def get_preview(self):
return ''
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 'activity-abiword'
def get_preview(self):
return ''
def matches_mime_type(cls, mime_type):
return mime_type in cls._types
matches_mime_type = classmethod(matches_mime_type)
class RtfFileType(FileType):
_types = set(['application/rtf', 'text/rtf'])
def get_name(self):
return 'RTF file'
def get_icon(self):
return 'activity-abiword'
def get_preview(self):
return ''
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 'stock-missing'
def get_preview(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(UriFileType)
self._types.append(ImageFileType)
self._types.append(TextFileType)
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

View File

@ -1,3 +1,5 @@
import logging
from sugar.graphics.menuicon import MenuIcon from sugar.graphics.menuicon import MenuIcon
from view.clipboardmenu import ClipboardMenu from view.clipboardmenu import ClipboardMenu
from sugar.activity import ActivityFactory from sugar.activity import ActivityFactory
@ -6,31 +8,54 @@ from sugar.clipboard import clipboardservice
class ClipboardIcon(MenuIcon): class ClipboardIcon(MenuIcon):
def __init__(self, menu_shell, object_id, name): def __init__(self, menu_shell, object_id, name):
MenuIcon.__init__(self, menu_shell, icon_name='activity-xbook') MenuIcon.__init__(self, menu_shell)
self._object_id = object_id self._object_id = object_id
self._name = name self._name = name
self._percent = 0 self._percent = 0
self._preview = None
self.connect('activated', self._icon_activated_cb) self.connect('activated', self._icon_activated_cb)
self._menu = None self._menu = None
def create_menu(self): def create_menu(self):
self._menu = ClipboardMenu(self._name, self._percent) self._menu = ClipboardMenu(self._name, self._percent, self._preview)
self._menu.connect('action', self._popup_action_cb) self._menu.connect('action', self._popup_action_cb)
return self._menu return self._menu
def set_percent(self, percent): def set_state(self, name, percent, icon_name, preview):
self._name = name
self._percent = percent self._percent = percent
self._preview = preview
self.set_icon_name(icon_name)
if self._menu: if self._menu:
self._menu.set_percent(percent) self._menu.set_state(name, percent, preview)
def _get_activity_for_mime_type(self, mime_type):
# FIXME: We should use some kind of registry that could be extended by
# newly installed activities.
if mime_type == "application/pdf":
return "org.laptop.sugar.Xbook"
elif mime_type in ["application/msword", "text/rtf", "application/rtf"]:
return "org.laptop.AbiWordActivity"
else:
return None
def _icon_activated_cb(self, icon): def _icon_activated_cb(self, icon):
if self._percent == 100: if self._percent == 100:
cb_service = clipboardservice.get_instance() cb_service = clipboardservice.get_instance()
format_types = cb_service.get_object_format_types(self._object_id)
if len(format_types) > 0 and format_types[0] == "application/pdf": (name, percent, icon, preview, format_types) = \
activity = ActivityFactory.create("org.laptop.sugar.Xbook") cb_service.get_object(self._object_id)
activity.execute("open_document", [self._object_id])
if format_types:
logging.debug("_icon_activated_cb: " + self._object_id)
activity_id = self._get_activity_for_mime_type(format_types[0])
if activity_id:
activity = ActivityFactory.create(activity_id)
activity.start()
activity.execute("open_document", [self._object_id])
def _popup_action_cb(self, popup, action): def _popup_action_cb(self, popup, action):
self.popdown() self.popdown()

View File

@ -19,7 +19,7 @@ class ClipboardMenu(Menu):
ACTION_SHARE = 1 ACTION_SHARE = 1
ACTION_STOP_DOWNLOAD = 2 ACTION_STOP_DOWNLOAD = 2
def __init__(self, name, percent): def __init__(self, name, percent, preview):
Menu.__init__(self, name) Menu.__init__(self, name)
if percent < 100: if percent < 100:
@ -31,6 +31,8 @@ class ClipboardMenu(Menu):
self._remove_icon = None self._remove_icon = None
self._stop_icon = None self._stop_icon = None
self.add_item(preview)
self._update_icons(percent) self._update_icons(percent)
def _update_icons(self, percent): def _update_icons(self, percent):
@ -51,7 +53,8 @@ class ClipboardMenu(Menu):
self.remove_action(self._remove_icon) self.remove_action(self._remove_icon)
self._remove_icon = None self._remove_icon = None
def set_percent(self, percent): def set_state(self, name, percent, preview):
self.set_title(name)
if self._progress_bar: if self._progress_bar:
self._progress_bar.set_property('percent', percent) self._progress_bar.set_property('percent', percent)
self._update_icons(percent) self._update_icons(percent)

View File

@ -88,9 +88,10 @@ class ClipboardBox(hippo.CanvasBox):
del self._icons[object_id] del self._icons[object_id]
logging.debug('ClipboardBox: ' + object_id + ' was deleted.') logging.debug('ClipboardBox: ' + object_id + ' was deleted.')
def _object_state_changed_cb(self, cb_service, object_id, percent): def _object_state_changed_cb(self, cb_service, object_id, name, percent,
icon_name, preview):
icon = self._icons[object_id] icon = self._icons[object_id]
icon.set_percent(percent) icon.set_state(name, percent, icon_name, preview)
logging.debug('ClipboardBox: ' + object_id + ' state was changed.') logging.debug('ClipboardBox: ' + object_id + ' state was changed.')
def drag_motion_cb(self, widget, context, x, y, time): def drag_motion_cb(self, widget, context, x, y, time):
@ -104,13 +105,13 @@ class ClipboardBox(hippo.CanvasBox):
self._context_map.add_context(context, object_id, len(context.targets)) self._context_map.add_context(context, object_id, len(context.targets))
cb_service = clipboardservice.get_instance() cb_service = clipboardservice.get_instance()
cb_service.add_object(object_id, "name") cb_service.add_object(object_id, name="")
for target in context.targets: for target in context.targets:
if str(target) not in ('TIMESTAMP', 'TARGETS', 'MULTIPLE'): if str(target) not in ('TIMESTAMP', 'TARGETS', 'MULTIPLE'):
widget.drag_get_data(context, target, time) widget.drag_get_data(context, target, time)
cb_service.set_object_state(object_id, percent = 100) cb_service.set_object_percent(object_id, percent = 100)
return True return True
@ -186,9 +187,11 @@ class ClipboardBox(hippo.CanvasBox):
def _get_targets_for_dnd(self, object_id): def _get_targets_for_dnd(self, object_id):
cb_service = clipboardservice.get_instance() cb_service = clipboardservice.get_instance()
format_types = cb_service.get_object_format_types(object_id)
targets = [] (name, percent, icon, preview, format_types) = \
cb_service.get_object(object_id)
targets = []
for format_type in format_types: for format_type in format_types:
targets.append((format_type, 0, 0)) targets.append((format_type, 0, 0))

View File

@ -45,7 +45,7 @@ class ClipboardPanelWindow(PanelWindow):
cb_service = clipboardservice.get_instance() cb_service = clipboardservice.get_instance()
cb_service.add_object(key, "name") cb_service.add_object(key, "name")
cb_service.set_object_state(key, percent = 100) cb_service.set_object_percent(key, percent = 100)
targets = clipboard.wait_for_targets() targets = clipboard.wait_for_targets()
for target in targets: for target in targets:

View File

@ -2,7 +2,11 @@ import logging
import dbus import dbus
import gobject import gobject
from sugar import util NAME_KEY = 'NAME'
PERCENT_KEY = 'PERCENT'
ICON_KEY = 'ICON'
PREVIEW_KEY = 'PREVIEW'
FORMATS_KEY = 'FORMATS'
DBUS_SERVICE = "org.laptop.Clipboard" DBUS_SERVICE = "org.laptop.Clipboard"
DBUS_INTERFACE = "org.laptop.Clipboard" DBUS_INTERFACE = "org.laptop.Clipboard"
@ -16,7 +20,7 @@ class ClipboardService(gobject.GObject):
'object-deleted': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'object-deleted': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([str])), ([str])),
'object-state-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'object-state-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([str, int])), ([str, str, int, str, str])),
} }
def __init__(self): def __init__(self):
@ -58,8 +62,9 @@ class ClipboardService(gobject.GObject):
def _object_deleted_cb(self, object_id): def _object_deleted_cb(self, object_id):
self.emit('object-deleted', object_id) self.emit('object-deleted', object_id)
def _object_state_changed_cb(self, object_id, percent): def _object_state_changed_cb(self, object_id, values):
self.emit('object-state-changed', object_id, percent) self.emit('object-state-changed', object_id, values[NAME_KEY],
values[PERCENT_KEY], values[ICON_KEY], values[PREVIEW_KEY])
def add_object(self, object_id, name): def add_object(self, object_id, name):
self._dbus_service.add_object(object_id, name) self._dbus_service.add_object(object_id, name)
@ -67,27 +72,25 @@ class ClipboardService(gobject.GObject):
def add_object_format(self, object_id, formatType, data, on_disk): def add_object_format(self, object_id, formatType, data, on_disk):
self._dbus_service.add_object_format(object_id, self._dbus_service.add_object_format(object_id,
formatType, formatType,
dbus.types.ByteArray(data), data,
on_disk) on_disk)
def delete_object(self, object_id): def delete_object(self, object_id):
self._dbus_service.delete_object(object_id) self._dbus_service.delete_object(object_id)
def set_object_state(self, object_id, percent): def set_object_percent(self, object_id, percent):
self._dbus_service.set_object_state(object_id, percent) self._dbus_service.set_object_percent(object_id, percent)
def get_object_format_types(self, object_id): def get_object(self, object_id):
return self._dbus_service.get_object_format_types(object_id) result_dict = self._dbus_service.get_object(object_id,)
def get_object_data(self, object_id, formatType):
data = self._dbus_service.get_object_data(object_id, formatType)
# FIXME: Take it out when using the 0.80 dbus bindings return (result_dict[NAME_KEY], result_dict[PERCENT_KEY],
s = "" result_dict[ICON_KEY], result_dict[PREVIEW_KEY],
for i in data: result_dict[FORMATS_KEY])
s += chr(i)
def get_object_data(self, object_id, formatType):
return s return self._dbus_service.get_object_data(object_id, formatType,
byte_arrays=True)
_clipboard_service = None _clipboard_service = None
def get_instance(): def get_instance():

View File

@ -16,6 +16,7 @@
# Boston, MA 02111-1307, USA. # Boston, MA 02111-1307, USA.
import re import re
import logging
import gobject import gobject
import gtk import gtk
@ -156,3 +157,8 @@ class CanvasIcon(hippo.CanvasBox, hippo.CanvasItem):
def _button_press_event_cb(self, item, event): def _button_press_event_cb(self, item, event):
item.emit_activated() item.emit_activated()
def set_icon_name(self, icon_name):
self._icon_name = icon_name
self._buffer = None
self.emit_paint_needed(0, 0, -1, -1)

View File

@ -76,7 +76,7 @@ class Menu(gtk.Window):
orientation=hippo.ORIENTATION_HORIZONTAL) orientation=hippo.ORIENTATION_HORIZONTAL)
self._root.append(self._action_box) self._root.append(self._action_box)
def add_item(self, label, action_id): def add_item(self, label, action_id=None):
if not self._item_box: if not self._item_box:
self._create_item_box() self._create_item_box()
@ -84,8 +84,9 @@ class Menu(gtk.Window):
style.apply_stylesheet(text, 'menu.Item') style.apply_stylesheet(text, 'menu.Item')
# FIXME need a way to make hippo items activable in python # FIXME need a way to make hippo items activable in python
text.connect('button-press-event', self._item_clicked_cb, action_id) if action_id:
#text.connect('activated', self._action_clicked_cb, action_id) text.connect('button-press-event', self._item_clicked_cb, action_id)
#text.connect('activated', self._action_clicked_cb, action_id)
self._item_box.append(text) self._item_box.append(text)
@ -105,3 +106,6 @@ class Menu(gtk.Window):
def _action_clicked_cb(self, icon, action): def _action_clicked_cb(self, icon, action):
self.emit('action', action) self.emit('action', action)
def set_title(self, title):
self._title_item.set_text(title)