[Sugar-devel] [PATCH] Only add one time every object in the clipboard v5 - SL #3371

godiard at sugarlabs.org godiard at sugarlabs.org
Tue Apr 24 07:17:56 EDT 2012


From: Gonzalo Odiard <godiard at gmail.com>

This patch change the behaviour of the clipboard tray,
every object is added only one time, if already exist,
the already added object is selected and a notification is displayed
(showing a flashing icon in the lower left corner).

A hash over the data in the object is used to determine if the object
is already present in the journal. When the object is a uri,
a md5sum is calculated over the file and the hash is done over the result.

We need check if the object is already in the clipboard
because a bad interaction between the clipboard in write and
the text to speech feature. See the ticket for more information.

Signed-off-by: Gonzalo Odiard <gonzalo at laptop.org>

----

v2: Select the already added object if needed, as sugested by Sascha.
v3: Show the notification when copy a already existing object, as sugested by Gary
v4: Check targets is not None
v5: Chages acording to Sascha review and management of uri from the journal
---
 src/jarabe/frame/clipboard.py            |   22 +++++++++++++++---
 src/jarabe/frame/clipboardicon.py        |   26 +++++++++++++++-------
 src/jarabe/frame/clipboardpanelwindow.py |   34 +++++++++++++++++++++++++++++-
 3 files changed, 69 insertions(+), 13 deletions(-)

diff --git a/src/jarabe/frame/clipboard.py b/src/jarabe/frame/clipboard.py
index be2b902..f3da89f 100644
--- a/src/jarabe/frame/clipboard.py
+++ b/src/jarabe/frame/clipboard.py
@@ -36,7 +36,9 @@ class Clipboard(gobject.GObject):
         'object-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
                         ([object])),
         'object-deleted': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
-                        ([int])),
+                        ([long])),
+        'object-selected': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+                        ([long])),
         'object-state-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
                         ([object])),
     }
@@ -51,9 +53,21 @@ class Clipboard(gobject.GObject):
         self._next_id += 1
         return self._next_id
 
-    def add_object(self, name):
-        logging.debug('Clipboard.add_object')
-        object_id = self._get_next_object_id()
+    def add_object(self, name, data_hash=None):
+        """ Add a object to the clipboard.
+        data_hash is a long used to check if the object is already
+        in the clipboard, generated with hash() over the data to be added.
+        Return the object_id or None if the object is not added.
+        """
+        logging.debug('Clipboard.add_object hash %s', data_hash)
+        if data_hash is None:
+            object_id = self._get_next_object_id()
+        else:
+            object_id = data_hash
+        if object_id in self._objects:
+            logging.debug('Duplicate entry, selecting previous entry instead')
+            self.emit('object-selected', object_id)
+            return None
         self._objects[object_id] = ClipboardObject(object_id, name)
         self.emit('object-added', self._objects[object_id])
         return object_id
diff --git a/src/jarabe/frame/clipboardicon.py b/src/jarabe/frame/clipboardicon.py
index aa72d8a..315cdaa 100644
--- a/src/jarabe/frame/clipboardicon.py
+++ b/src/jarabe/frame/clipboardicon.py
@@ -57,6 +57,7 @@ class ClipboardIcon(RadioToolButton):
         cb_service = clipboard.get_instance()
         cb_service.connect('object-state-changed',
                            self._object_state_changed_cb)
+        cb_service.connect('object-selected', self._object_selected_cb)
 
         child = self.get_child()
         child.connect('drag_data_get', self._drag_data_get_cb)
@@ -128,17 +129,26 @@ class ClipboardIcon(RadioToolButton):
         # Clipboard object became complete. Make it the active one.
         if self._current_percent < 100 and cb_object.get_percent() == 100:
             self.props.active = True
+            self.show_notification()
 
-            self._notif_icon = NotificationIcon()
-            self._notif_icon.props.icon_name = self._icon.props.icon_name
-            self._notif_icon.props.xo_color = \
-                    XoColor('%s,%s' % (self._icon.props.stroke_color,
-                                       self._icon.props.fill_color))
-            frame = jarabe.frame.get_view()
-            frame.add_notification(self._notif_icon,
-                                   gtk.CORNER_BOTTOM_LEFT)
         self._current_percent = cb_object.get_percent()
 
+    def _object_selected_cb(self, cb_service, object_id):
+        if object_id != self._cb_object.get_id():
+            return
+        self.props.active = True
+        self.show_notification()
+        logging.debug('ClipboardIcon: %r was selected', object_id)
+
+    def show_notification(self):
+        self._notif_icon = NotificationIcon()
+        self._notif_icon.props.icon_name = self._icon.props.icon_name
+        self._notif_icon.props.xo_color = \
+                XoColor('%s,%s' % (self._icon.props.stroke_color,
+                                   self._icon.props.fill_color))
+        frame = jarabe.frame.get_view()
+        frame.add_notification(self._notif_icon, gtk.CORNER_BOTTOM_LEFT)
+
     def _drag_begin_cb(self, widget, context):
         # TODO: We should get the pixbuf from the icon, with colors, etc.
         icon_theme = gtk.icon_theme_get_default()
diff --git a/src/jarabe/frame/clipboardpanelwindow.py b/src/jarabe/frame/clipboardpanelwindow.py
index b73572e..c91e578 100644
--- a/src/jarabe/frame/clipboardpanelwindow.py
+++ b/src/jarabe/frame/clipboardpanelwindow.py
@@ -16,6 +16,7 @@
 
 import logging
 from urlparse import urlparse
+import hashlib
 
 import gtk
 
@@ -59,23 +60,54 @@ class ClipboardPanelWindow(FrameWindow):
 
         targets = x_clipboard.wait_for_targets()
         cb_selections = []
+        if targets is None:
+            return
+
+        target_is_uri = False
         for target in targets:
+            logging.error('TARGET: %s', target)
             if target not in ('TIMESTAMP', 'TARGETS',
                               'MULTIPLE', 'SAVE_TARGETS'):
                 logging.debug('Asking for target %s.', target)
+                if target == 'text/uri-list':
+                    target_is_uri = True
+
                 selection = x_clipboard.wait_for_contents(target)
                 if not selection:
                     logging.warning('no data for selection target %s.', target)
                     continue
                 cb_selections.append(selection)
 
+        if target_is_uri:
+            uri = selection.data
+            filename = uri[len('file://'):].strip()
+            md5 = self.md5_for_file(filename)
+            logging.error('Target is a uri %s', uri)
+            data_hash = hash(md5)
+        else:
+            data_hash = hash(selection.data)
+
         if len(cb_selections) > 0:
-            key = cb_service.add_object(name="")
+            key = cb_service.add_object(name="", data_hash=data_hash)
+            if key is None:
+                return
             cb_service.set_object_percent(key, percent=0)
             for selection in cb_selections:
                 self._add_selection(key, selection)
             cb_service.set_object_percent(key, percent=100)
 
+    def md5_for_file(self, file_name):
+        block_size = 8192
+        md5 = hashlib.md5()
+        f = open(file_name, 'r')
+        while True:
+            data = f.read(block_size)
+            if not data:
+                break
+            md5.update(data)
+        f.close()
+        return md5.digest()
+
     def _add_selection(self, key, selection):
         if not selection.data:
             logging.warning('no data for selection target %s.', selection.type)
-- 
1.7.7.6



More information about the Sugar-devel mailing list