[Sugar-devel] [PATCH] Properly store and load friends #2331

Tomeu Vizoso tomeu.vizoso at collabora.co.uk
Fri Sep 17 03:54:01 EDT 2010


Because FriendBuddyModel has a different life cycle than BuddyModel
(are tracked also when online), we need to store the key and nick
so we can represent them in the UI when the contact are not online
and also so we can relate to the contact when it becomes online.

* src/jarabe/model/buddy.py: Move out FriendBuddyModel and add a
  handle property to BuddyModel.

* src/jarabe/model/filetransfer.py: Ask neighborhood.py for the
  buddy associated to a handle.

* src/jarabe/model/friends.py: Add FriendBuddyModel.

* src/jarabe/model/neighborhood.py: Set the contact handle on the
  BuddyModel.
---
 src/jarabe/frame/activitiestray.py |    4 +-
 src/jarabe/model/buddy.py          |   23 +++---------
 src/jarabe/model/filetransfer.py   |   28 ++-------------
 src/jarabe/model/friends.py        |   68 ++++++++++++++++++++++++++++++++++-
 src/jarabe/model/neighborhood.py   |   24 ++++++++++---
 5 files changed, 97 insertions(+), 50 deletions(-)

diff --git a/src/jarabe/frame/activitiestray.py b/src/jarabe/frame/activitiestray.py
index 9a1a9da..6bd2a1b 100644
--- a/src/jarabe/frame/activitiestray.py
+++ b/src/jarabe/frame/activitiestray.py
@@ -371,7 +371,7 @@ class IncomingTransferButton(BaseTransferButton):
                 self.notif_icon.props.icon_name = icon_name
                 break
 
-        icon_color = XoColor(file_transfer.buddy.props.color)
+        icon_color = file_transfer.buddy.props.color
         self.props.icon_widget.props.xo_color = icon_color
         self.notif_icon.props.xo_color = icon_color
 
@@ -396,7 +396,7 @@ class IncomingTransferButton(BaseTransferButton):
             self._ds_object.metadata['buddies'] = ''
             self._ds_object.metadata['preview'] = ''
             self._ds_object.metadata['icon-color'] = \
-                    file_transfer.buddy.props.color
+                    file_transfer.buddy.props.color.to_string()
             self._ds_object.metadata['mime_type'] = file_transfer.mime_type
         elif file_transfer.props.state == filetransfer.FT_STATE_COMPLETED:
             logging.debug('__notify_state_cb COMPLETED')
diff --git a/src/jarabe/model/buddy.py b/src/jarabe/model/buddy.py
index 531d7ea..5f3176e 100644
--- a/src/jarabe/model/buddy.py
+++ b/src/jarabe/model/buddy.py
@@ -28,8 +28,6 @@ from sugar.profile import get_profile
 
 from jarabe.util.telepathy import connection_watcher
 
-_NOT_PRESENT_COLOR = "#d5d5d5,#FFFFFF"
-
 CONNECTION_INTERFACE_BUDDY_INFO = 'org.laptop.Telepathy.BuddyInfo'
 
 class BaseBuddyModel(gobject.GObject):
@@ -40,20 +38,10 @@ class BaseBuddyModel(gobject.GObject):
         self._nick = None
         self._color = None
         self._tags = None
-        self._present = False
         self._current_activity = None
 
         gobject.GObject.__init__(self, **kwargs)
 
-    def is_present(self):
-        return self._present
-
-    def set_present(self, present):
-        self._present = present
-
-    present = gobject.property(type=bool, default=False, getter=is_present,
-                               setter=set_present)
-
     def get_nick(self):
         return self._nick
 
@@ -103,7 +91,6 @@ class OwnerBuddyModel(BaseBuddyModel):
     __gtype_name__ = 'SugarOwnerBuddyModel'
     def __init__(self):
         BaseBuddyModel.__init__(self)
-        self.props.present = True
 
         client = gconf.client_get_default()
         self.props.nick = client.get_string('/desktop/sugar/user/nick')
@@ -207,6 +194,7 @@ class BuddyModel(BaseBuddyModel):
 
         self._account = None
         self._contact_id = None
+        self._handle = None
 
         BaseBuddyModel.__init__(self, **kwargs)
 
@@ -231,9 +219,10 @@ class BuddyModel(BaseBuddyModel):
     contact_id = gobject.property(type=object, getter=get_contact_id,
                                   setter=set_contact_id)
 
+    def get_handle(self):
+        return self._handle
 
-class FriendBuddyModel(BuddyModel):
-    __gtype_name__ = 'SugarFriendBuddyModel'
-    def __init__(self, nick, key):
-        BuddyModel.__init__(self, nick=nick, key=key)
+    def set_handle(self, handle):
+        self._handle = handle
 
+    handle = gobject.property(type=object, getter=get_handle, setter=set_handle)
diff --git a/src/jarabe/model/filetransfer.py b/src/jarabe/model/filetransfer.py
index e0809bb..0d21793 100644
--- a/src/jarabe/model/filetransfer.py
+++ b/src/jarabe/model/filetransfer.py
@@ -31,6 +31,7 @@ from sugar.presence import presenceservice
 from sugar import dispatch
 
 from jarabe.util.telepathy import connection_watcher
+from jarabe.model import neighborhood
 
 FT_STATE_NONE = 0
 FT_STATE_PENDING = 1
@@ -140,11 +141,7 @@ class BaseFileTransfer(gobject.GObject):
         self.mime_type = props['ContentType']
 
         handle = channel_properties.Get(CHANNEL, 'TargetHandle')
-        presence_service = presenceservice.get_instance()
-        self.buddy = presence_service.get_buddy_by_telepathy_handle(
-                self._connection.service_name,
-                self._connection.object_path,
-                handle)
+        self.buddy = neighborhood.get_model().get_buddy_by_handle(handle)
 
     def __transferred_bytes_changed_cb(self, transferred_bytes):
         logging.debug('__transferred_bytes_changed_cb %r', transferred_bytes)
@@ -240,20 +237,18 @@ class OutgoingFileTransfer(BaseFileTransfer):
         self._splicer = None
         self._output_stream = None
 
-        self.buddy = buddy.get_buddy()
+        self.buddy = buddy
         self.title = title
         self.file_size = os.stat(file_name).st_size
         self.description = description
         self.mime_type = mime_type
 
     def __connection_ready_cb(self, connection):
-        handle = self._get_buddy_handle()
-
         requests = connection[CONNECTION_INTERFACE_REQUESTS]
         object_path, properties_ = requests.CreateChannel({
             CHANNEL + '.ChannelType': CHANNEL_TYPE_FILE_TRANSFER,
             CHANNEL + '.TargetHandleType': CONNECTION_HANDLE_TYPE_CONTACT,
-            CHANNEL + '.TargetHandle': handle,
+            CHANNEL + '.TargetHandle': self.buddy.handle,
             CHANNEL_TYPE_FILE_TRANSFER + '.ContentType': self.mime_type,
             CHANNEL_TYPE_FILE_TRANSFER + '.Filename': self.title,
             CHANNEL_TYPE_FILE_TRANSFER + '.Size': self.file_size,
@@ -267,21 +262,6 @@ class OutgoingFileTransfer(BaseFileTransfer):
                 SOCKET_ADDRESS_TYPE_UNIX, SOCKET_ACCESS_CONTROL_LOCALHOST, '',
                 byte_arrays=True)
 
-    def _get_buddy_handle(self):
-        object_path = self.buddy.object_path()
-
-        bus = dbus.SessionBus()
-        remote_object = bus.get_object('org.laptop.Sugar.Presence', object_path)
-        ps_buddy = dbus.Interface(remote_object,
-                                  'org.laptop.Sugar.Presence.Buddy')
-
-        handles = ps_buddy.GetTelepathyHandles()
-        logging.debug('_get_buddy_handle %r', handles)
-
-        bus_name, object_path, handle = handles[0]
-
-        return handle
-
     def __notify_state_cb(self, file_transfer, pspec):
         logging.debug('__notify_state_cb %r', self.props.state)
         if self.props.state == FT_STATE_OPEN:
diff --git a/src/jarabe/model/friends.py b/src/jarabe/model/friends.py
index fb5323c..98bff96 100644
--- a/src/jarabe/model/friends.py
+++ b/src/jarabe/model/friends.py
@@ -21,8 +21,71 @@ from ConfigParser import ConfigParser
 import gobject
 import dbus
 
-from jarabe.model.buddy import BuddyModel
 from sugar import env
+from sugar.graphics.xocolor import XoColor
+
+from jarabe.model.buddy import BuddyModel
+from jarabe.model import neighborhood
+
+class FriendBuddyModel(BuddyModel):
+    __gtype_name__ = 'SugarFriendBuddyModel'
+
+    _NOT_PRESENT_COLOR = "#D5D5D5,#FFFFFF"
+
+    def __init__(self, nick, key):
+        self._online_buddy = None
+
+        BuddyModel.__init__(self, nick=nick, key=key)
+
+        neighborhood_model = neighborhood.get_model()
+        neighborhood_model.connect('buddy-added', self.__buddy_added_cb)
+        neighborhood_model.connect('buddy-removed', self.__buddy_removed_cb)
+
+        buddy = neighborhood_model.get_buddy_by_key(key)
+        if buddy is not None:
+            self._set_online_buddy(buddy)
+
+    def __buddy_added_cb(self, neighborhood, buddy):
+        if buddy.key != self.key:
+            return
+        self._set_online_buddy(buddy)
+
+    def _set_online_buddy(self, buddy):
+        self._online_buddy = buddy
+        self._online_buddy.connect('notify::color', self.__notify_color_cb)
+        self.notify('color')
+        self.notify('present')
+
+    def __buddy_removed_cb(self, neighborhood, buddy):
+        if buddy.key != self.key:
+            return
+        self._online_buddy = None
+        self.notify('color')
+        self.notify('present')
+
+    def __notify_color_cb(self, buddy, pspec):
+        self.notify('color')
+
+    def is_present(self):
+        return self._online_buddy is not None
+
+    present = gobject.property(type=bool, default=False, getter=is_present)
+
+    def get_color(self):
+        if self._online_buddy is not None:
+            return self._online_buddy.color
+        else:
+            return XoColor(FriendBuddyModel._NOT_PRESENT_COLOR)
+
+    color = gobject.property(type=object, getter=get_color)
+
+    def get_handle(self):
+        if self._online_buddy is not None:
+            return self._online_buddy.handle
+        else:
+            return None
+
+    handle = gobject.property(type=object, getter=get_handle)
 
 class Friends(gobject.GObject):
     __gsignals__ = {
@@ -49,6 +112,7 @@ class Friends(gobject.GObject):
 
     def make_friend(self, buddy):
         if not self.has_buddy(buddy):
+            buddy = FriendBuddyModel(key=buddy.key, nick=buddy.nick)
             self.add_friend(buddy)
             self.save()
 
@@ -70,7 +134,7 @@ class Friends(gobject.GObject):
                     # HACK: don't screw up on old friends files
                     if len(key) < 20:
                         continue
-                    buddy = BuddyModel(key=key, nick=cp.get(key, 'nick'))
+                    buddy = FriendBuddyModel(key=key, nick=cp.get(key, 'nick'))
                     self.add_friend(buddy)
         except Exception:
             logging.exception('Error parsing friends file')
diff --git a/src/jarabe/model/neighborhood.py b/src/jarabe/model/neighborhood.py
index a457ff7..eabdbc0 100644
--- a/src/jarabe/model/neighborhood.py
+++ b/src/jarabe/model/neighborhood.py
@@ -156,7 +156,8 @@ class _Account(gobject.GObject):
         'activity-removed':     (gobject.SIGNAL_RUN_FIRST,
                                  gobject.TYPE_NONE, ([object])),
         'buddy-added':          (gobject.SIGNAL_RUN_FIRST,
-                                 gobject.TYPE_NONE, ([object, object, object])),
+                                 gobject.TYPE_NONE,
+                                 ([object, object, object, object])),
         'buddy-updated':        (gobject.SIGNAL_RUN_FIRST,
                                  gobject.TYPE_NONE, ([object, object])),
         'buddy-removed':        (gobject.SIGNAL_RUN_FIRST,
@@ -517,7 +518,7 @@ class _Account(gobject.GObject):
     def __got_buddy_info_cb(self, handle, nick, properties):
         logging.debug('_Account.__got_buddy_info_cb %r', properties)
         self.emit('buddy-added', self._buddy_handles[handle], nick,
-                  properties.get('key', None))
+                  properties.get('key', None), handle)
         self.emit('buddy-updated', self._buddy_handles[handle], properties)
 
     def __get_contact_attributes_cb(self, attributes):
@@ -568,7 +569,7 @@ class _Account(gobject.GObject):
                                               'BuddyInfo.GetCurrentActivity'),
                         timeout=_QUERY_DBUS_TIMEOUT)
                 else:
-                    self.emit('buddy-added', contact_id, nick, None)
+                    self.emit('buddy-added', contact_id, nick, None, handle)
 
     def __got_activities_cb(self, buddy_handle, activities):
         logging.debug('_Account.__got_activities_cb %r %r', buddy_handle,
@@ -791,7 +792,7 @@ class Neighborhood(gobject.GObject):
         if needs_reconnect:
             account.Reconnect()
 
-    def __buddy_added_cb(self, account, contact_id, nick, key):
+    def __buddy_added_cb(self, account, contact_id, nick, key, handle):
         logging.debug('__buddy_added_cb %r', contact_id)
 
         if contact_id in self._buddies:
@@ -802,7 +803,8 @@ class Neighborhood(gobject.GObject):
                 nick=nick,
                 account=account.object_path,
                 contact_id=contact_id,
-                key=key)
+                key=key,
+                handle=handle)
         self._buddies[contact_id] = buddy
 
         self.emit('buddy-added', buddy)
@@ -927,6 +929,18 @@ class Neighborhood(gobject.GObject):
     def get_buddies(self):
         return self._buddies.values()
 
+    def get_buddy_by_key(self, key):
+        for buddy in self._buddies.values():
+            if buddy.key == key:
+                return buddy
+        return None
+
+    def get_buddy_by_handle(self, contact_handle):
+        for buddy in self._buddies.values():
+            if not buddy.is_owner() and buddy.handle == contact_handle:
+                return buddy
+        return None
+
     def get_activity(self, activity_id):
         return self._activities.get(activity_id, None)
 
-- 
1.7.2.3



More information about the Sugar-devel mailing list