From 6227b962153552299ec5825dd279d3de0835c670 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Wed, 14 Mar 2007 13:32:05 +0100 Subject: [PATCH] Support selection of the clipboard object to be pasted. --- services/clipboard/clipboardservice.py | 2 +- services/clipboard/typeregistry.py | 15 ++---- shell/view/clipboardicon.py | 48 +++++++++++++++--- shell/view/frame/clipboardbox.py | 62 +++++++++++++++++++++--- shell/view/frame/clipboardpanelwindow.py | 39 +++++++++------ 5 files changed, 124 insertions(+), 42 deletions(-) diff --git a/services/clipboard/clipboardservice.py b/services/clipboard/clipboardservice.py index 282dfd38..8fb0ff4f 100644 --- a/services/clipboard/clipboardservice.py +++ b/services/clipboard/clipboardservice.py @@ -100,7 +100,7 @@ class ClipboardDBusServiceHelper(dbus.service.Object): def get_object(self, object_path): cb_object = self._objects[str(object_path)] formats = cb_object.get_formats() - format_types = [] + format_types = dbus.Array([], 's') for type, format in formats.iteritems(): format_types.append(type) diff --git a/services/clipboard/typeregistry.py b/services/clipboard/typeregistry.py index 3f42ad5a..3e46895b 100644 --- a/services/clipboard/typeregistry.py +++ b/services/clipboard/typeregistry.py @@ -34,7 +34,7 @@ class TextFileType(FileType): def get_preview(self): for format, data in self._formats.iteritems(): if format in TextFileType._types: - text = str(data.get_data()) + text = data.get_data() if len(text) < 50: return text else: @@ -43,7 +43,7 @@ class TextFileType(FileType): return '' def get_activity(self): - return '' + return 'org.laptop.AbiWordActivity' def matches_mime_type(cls, mime_type): return mime_type in cls._types @@ -135,21 +135,12 @@ class MsWordFileType(FileType): return mime_type in cls._types matches_mime_type = classmethod(matches_mime_type) -class RtfFileType(FileType): +class RtfFileType(TextFileType): _types = set(['application/rtf', 'text/rtf']) def get_name(self): return _('RTF 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 diff --git a/shell/view/clipboardicon.py b/shell/view/clipboardicon.py index 7167bcec..37329904 100644 --- a/shell/view/clipboardicon.py +++ b/shell/view/clipboardicon.py @@ -1,5 +1,5 @@ # Copyright (C) 2007, Red Hat, Inc. -# Copyright (C) 2007, Tomeu Vizoso +# Copyright (C) 2007, One Laptop Per Child # # 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 @@ -18,6 +18,8 @@ import logging import os +import gobject + from sugar.graphics.canvasicon import CanvasIcon from view.clipboardmenu import ClipboardMenu from sugar.graphics.xocolor import XoColor @@ -28,6 +30,12 @@ from sugar.clipboard import clipboardservice from sugar import util class ClipboardIcon(CanvasIcon): + __gtype_name__ = 'SugarClipboardIcon' + + __gproperties__ = { + 'selected' : (bool, None, None, False, + gobject.PARAM_READWRITE) + } def __init__(self, popup_context, object_id, name): CanvasIcon.__init__(self) @@ -37,12 +45,34 @@ class ClipboardIcon(CanvasIcon): self._percent = 0 self._preview = None self._activity = None + self._selected = False + self._hover = False self.props.box_width = units.grid_to_pixels(1) self.props.box_height = units.grid_to_pixels(1) self.props.scale = units.STANDARD_ICON_SCALE - self.connect('activated', self._icon_activated_cb) self._menu = None - + + def do_set_property(self, pspec, value): + if pspec.name == 'selected': + self._set_selected(value) + self.emit_paint_needed(0, 0, -1, -1) + else: + CanvasIcon.do_set_property(self, pspec, value) + + def do_get_property(self, pspec): + if pspec.name == 'selected': + return self._selected + else: + return CanvasIcon.do_get_property(self, pspec) + + def _set_selected(self, selected): + self._selected = selected + if selected: + if not self._hover: + self.props.background_color = color.DESKTOP_BACKGROUND.get_int() + else: + self.props.background_color = color.TOOLBAR_BACKGROUND.get_int() + def get_popup(self): self._menu = ClipboardMenu(self._name, self._percent, self._preview, self._activity) @@ -70,7 +100,7 @@ class ClipboardIcon(CanvasIcon): if self._percent < 100 or not self._activity: return - logging.debug("_icon_activated_cb: " + self._object_id) + logging.debug("_open_file: " + self._object_id) # Get the file path cb_service = clipboardservice.get_instance() @@ -82,9 +112,6 @@ class ClipboardIcon(CanvasIcon): activityfactory.create_with_uri(self._activity, path) else: logging.debug("Clipboard item file path %s didn't exist" % path) - - def _icon_activated_cb(self, icon): - self._open_file() def _popup_action_cb(self, popup, menu_item): action = menu_item.props.action_id @@ -102,6 +129,11 @@ class ClipboardIcon(CanvasIcon): def prelight(self, enter): if enter: + self._hover = True self.props.background_color = color.BLACK.get_int() else: - self.props.background_color = color.TOOLBAR_BACKGROUND.get_int() + self._hover = False + if self._selected: + self.props.background_color = color.DESKTOP_BACKGROUND.get_int() + else: + self.props.background_color = color.TOOLBAR_BACKGROUND.get_int() diff --git a/shell/view/frame/clipboardbox.py b/shell/view/frame/clipboardbox.py index 031854aa..422d8380 100644 --- a/shell/view/frame/clipboardbox.py +++ b/shell/view/frame/clipboardbox.py @@ -42,16 +42,21 @@ class ClipboardBox(hippo.CanvasBox): self._popup_context = popup_context self._icons = {} self._context_map = _ContextMap() + self._selected_icon = None + self._owns_clipboard = False self._pressed_button = None self._press_start_x = None self._press_start_y = None - + 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-state-changed', self._object_state_changed_cb) + def owns_clipboard(self): + return self._owns_clipboard + def _get_icon_at_coords(self, x, y): for object_id, icon in self._icons.iteritems(): [icon_x, icon_y] = self.get_position(icon) @@ -77,14 +82,57 @@ class ClipboardBox(hippo.CanvasBox): def _object_added_cb(self, cb_service, object_id, name): icon = ClipboardIcon(self._popup_context, object_id, name) - self.append(icon) + icon.connect('activated', self._icon_activated_cb) + self._set_icon_selected(icon) + + self.prepend(icon) self._icons[object_id] = icon logging.debug('ClipboardBox: ' + object_id + ' was added.') + def _set_icon_selected(self, icon): + logging.debug('_set_icon_selected') + icon.props.selected = True + if self._selected_icon: + self._selected_icon.props.selected = False + self._selected_icon = icon + + def _put_in_clipboard(self, object_id): + logging.debug('ClipboardBox._put_in_clipboard') + targets = self._get_object_targets(object_id) + if targets: + clipboard = gtk.Clipboard() + if not clipboard.set_with_data(targets, + self._clipboard_data_get_cb, + self._clipboard_clear_cb): + logging.error('GtkClipboard.set_with_data failed!') + else: + self._owns_clipboard = True + + def _clipboard_data_get_cb(self, clipboard, selection, info, data): + object_id = self._selected_icon.get_object_id() + cb_service = clipboardservice.get_instance() + data = cb_service.get_object_data(object_id, selection.target) + + selection.set(selection.target, 8, data) + + def _clipboard_clear_cb(self, clipboard, data): + logging.debug('ClipboardBox._clipboard_clear_cb') + self._owns_clipboard = False + + def _icon_activated_cb(self, icon): + logging.debug('ClipboardBox._icon_activated_cb') + if not icon.props.selected: + self._set_icon_selected(icon) + def _object_deleted_cb(self, cb_service, object_id): icon = self._icons[object_id] + position = self.get_children().index(icon) self.remove(icon) + + if icon.props.selected: + self._set_icon_selected(self.get_children()[position]) + del self._icons[object_id] logging.debug('ClipboardBox: ' + object_id + ' was deleted.') @@ -92,11 +140,13 @@ class ClipboardBox(hippo.CanvasBox): icon_name, preview, activity): icon = self._icons[object_id] icon.set_state(name, percent, icon_name, preview, activity) + if icon.props.selected and percent == 100: + self._put_in_clipboard(object_id) def drag_motion_cb(self, widget, context, x, y, time): logging.debug('ClipboardBox._drag_motion_cb') context.drag_status(gtk.gdk.ACTION_COPY, time) - return True + return False; def drag_drop_cb(self, widget, context, x, y, time): logging.debug('ClipboardBox._drag_drop_cb') @@ -169,7 +219,7 @@ class ClipboardBox(hippo.CanvasBox): int(self._press_start_y), int(x), int(y)): - targets = self._get_targets_for_dnd( + targets = self._get_object_targets( self._last_clicked_icon.get_object_id()) context = widget.drag_begin(targets, @@ -183,7 +233,7 @@ class ClipboardBox(hippo.CanvasBox): logging.debug("drag_end_cb") self._pressed_button = None - def _get_targets_for_dnd(self, object_id): + def _get_object_targets(self, object_id): cb_service = clipboardservice.get_instance() attrs = cb_service.get_object(object_id) @@ -192,7 +242,5 @@ class ClipboardBox(hippo.CanvasBox): targets = [] for format_type in format_types: targets.append((format_type, 0, 0)) - - logging.debug(str(targets)) return targets diff --git a/shell/view/frame/clipboardpanelwindow.py b/shell/view/frame/clipboardpanelwindow.py index 6ee7ab85..0f916459 100644 --- a/shell/view/frame/clipboardpanelwindow.py +++ b/shell/view/frame/clipboardpanelwindow.py @@ -14,35 +14,43 @@ class ClipboardPanelWindow(PanelWindow): self._frame = frame # Listening for new clipboard objects - clipboard = gtk.Clipboard() - clipboard.connect("owner-change", self._owner_change_cb) + # NOTE: we need to keep a reference to gtk.Clipboard in order to keep + # listening to it. + self._clipboard = gtk.Clipboard() + self._clipboard.connect("owner-change", self._owner_change_cb) root = self.get_root() - box = ClipboardBox(frame.get_popup_context()) - root.append(box) + self._clipboard_box = ClipboardBox(frame.get_popup_context()) + root.append(self._clipboard_box) # Receiving dnd drops self.drag_dest_set(0, [], 0) - self.connect("drag_motion", box.drag_motion_cb) - self.connect("drag_drop", box.drag_drop_cb) - self.connect("drag_data_received", box.drag_data_received_cb) + self.connect("drag_motion", self._clipboard_box.drag_motion_cb) + self.connect("drag_drop", self._clipboard_box.drag_drop_cb) + self.connect("drag_data_received", + self._clipboard_box.drag_data_received_cb) # Offering dnd drags self.drag_source_set(0, [], 0) self.add_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.POINTER_MOTION_HINT_MASK) - self.connect("motion_notify_event", box.motion_notify_event_cb) + self.connect("motion_notify_event", + self._clipboard_box.motion_notify_event_cb) # FIXME I'm not sure we should expose the canvas in the Window API - self._canvas.connect("button_press_event", box.button_press_event_cb) + self._canvas.connect("button_press_event", + self._clipboard_box.button_press_event_cb) - self.connect("drag_end", box.drag_end_cb) - self.connect("drag_data_get", box.drag_data_get_cb) + self.connect("drag_end", self._clipboard_box.drag_end_cb) + self.connect("drag_data_get", self._clipboard_box.drag_data_get_cb) def _owner_change_cb(self, clipboard, event): + if self._clipboard_box.owns_clipboard(): + return + logging.debug("owner_change_cb") - + cb_service = clipboardservice.get_instance() key = cb_service.add_object(name="") cb_service.set_object_percent(key, percent = 100) @@ -53,8 +61,11 @@ class ClipboardPanelWindow(PanelWindow): selection = clipboard.wait_for_contents(target) if selection: self._add_selection(key, selection) - - self._frame.show_and_hide(0) + + cb_service.set_object_percent(key, percent=100) + + # TODO: Notify somehow the object added. + #self._frame.show_and_hide(0) def _add_selection(self, key, selection): if selection.data: