[Sugar-devel] [PATCH sugar] Group members of a shared activity around it OLPC #10675

Simon Schampijer simon at schampijer.de
Tue Jul 5 03:52:11 EDT 2011


Like in previous versions we use the shell model and listen if the
current-activity changes. We do then call 'SetCurrentActivity' and
let the other buddies know. If we started the activity and share it
later we listen on the 'ActivitiesChanged' signal and do call
'SetCurrentActivity' then so the other buddies can update their views
accordingly.

This patch also removes the dependency in the shell on the
neighborhood model which was a hack to determine the color of
a shared activity. The neighborhood view now updates the color
accordingly and that information is transferred to the shell.

The patch furthermore removes the tracking of the own buddy when
we receive 'ActivitiesUpdated' in the neighborhood model. With the
changes from above this triggered an error like described in
OLPC #10671. A few checks have been added to make sure that #10671
does not occure anymore.

Signed-off-by: Simon Schampijer <simon at laptop.org>
---
 src/jarabe/model/buddy.py        |   21 ----------
 src/jarabe/model/neighborhood.py |   80 ++++++++++++++++++++++++++++++--------
 src/jarabe/model/shell.py        |   40 ++++++++++--------
 3 files changed, 86 insertions(+), 55 deletions(-)

diff --git a/src/jarabe/model/buddy.py b/src/jarabe/model/buddy.py
index c580e68..8f17d7e 100644
--- a/src/jarabe/model/buddy.py
+++ b/src/jarabe/model/buddy.py
@@ -106,8 +106,6 @@ class OwnerBuddyModel(BaseBuddyModel):
 
         self.connect('notify::nick', self.__property_changed_cb)
         self.connect('notify::color', self.__property_changed_cb)
-        self.connect('notify::current-activity',
-                     self.__current_activity_changed_cb)
 
         bus = dbus.SessionBus()
         bus.add_signal_receiver(
@@ -134,25 +132,6 @@ class OwnerBuddyModel(BaseBuddyModel):
     def __property_changed_cb(self, buddy, pspec):
         self._sync_properties()
 
-    def __current_activity_changed_cb(self, buddy, pspec):
-        conn_watcher = connection_watcher.get_instance()
-        for connection in conn_watcher.get_connections():
-            if self.props.current_activity is not None:
-                activity_id = self.props.current_activity.activity_id
-                room_handle = self.props.current_activity.room_handle
-            else:
-                activity_id = ''
-                room_handle = 0
-
-            connection[CONNECTION_INTERFACE_BUDDY_INFO].SetCurrentActivity(
-                activity_id,
-                room_handle,
-                reply_handler=self.__set_current_activity_cb,
-                error_handler=self.__error_handler_cb)
-
-    def __set_current_activity_cb(self):
-        logging.debug('__set_current_activity_cb')
-
     def _sync_properties(self):
         conn_watcher = connection_watcher.get_instance()
         for connection in conn_watcher.get_connections():
diff --git a/src/jarabe/model/neighborhood.py b/src/jarabe/model/neighborhood.py
index 4bb9d92..7253b2d 100644
--- a/src/jarabe/model/neighborhood.py
+++ b/src/jarabe/model/neighborhood.py
@@ -47,6 +47,7 @@ from sugar.profile import get_profile
 
 from jarabe.model.buddy import BuddyModel, get_owner_instance
 from jarabe.model import bundleregistry
+from jarabe.model import shell
 
 
 ACCOUNT_MANAGER_SERVICE = 'org.freedesktop.Telepathy.AccountManager'
@@ -341,6 +342,9 @@ class _Account(gobject.GObject):
 
             connection.connect_to_signal('CurrentActivityChanged',
                                          self.__current_activity_changed_cb)
+            home_model = shell.get_model()
+            home_model.connect('active-activity-changed',
+                               self.__active_activity_changed_cb)
         else:
             logging.warning('Connection %s does not support OLPC buddy '
                             'properties', self._connection.object_path)
@@ -375,6 +379,29 @@ class _Account(gobject.GObject):
                 error_handler=partial(self.__error_handler_cb,
                                       'Connection.GetMembers'))
 
+    def __active_activity_changed_cb(self, model, home_activity):
+        room_handle = 0
+        home_activity_id = home_activity.get_activity_id()
+        for handle, activity_id in self._activity_handles.items():
+            if home_activity_id == activity_id:
+                room_handle = handle
+                break
+        if room_handle == 0:
+            home_activity_id = ''
+
+        connection = self._connection[CONNECTION_INTERFACE_BUDDY_INFO]
+        connection.SetCurrentActivity(
+            home_activity_id,
+            room_handle,
+            reply_handler=self.__set_current_activity_cb,
+            error_handler=self.__set_current_activity_error_cb)
+
+    def __set_current_activity_cb(self):
+        logging.warning('_Account.__set_current_activity_cb')
+
+    def __set_current_activity_error_cb(self, error):
+        logging.debug('_Account.__set_current_activity__error_cb %r', error)
+
     def __update_capabilities_cb(self):
         pass
 
@@ -416,16 +443,18 @@ class _Account(gobject.GObject):
                                   room_handle):
         logging.debug('_Account.__get_current_activity_cb %r %r %r',
                       contact_handle, activity_id, room_handle)
-        contact_id = self._buddy_handles[contact_handle]
-        self.emit('current-activity-updated', contact_id, activity_id)
+
+        if contact_handle in self._buddy_handles:
+            contact_id = self._buddy_handles[contact_handle]
+            if not activity_id and room_handle:
+                activity_id = self._activity_handles.get(room_handle, '')
+            self.emit('current-activity-updated', contact_id, activity_id)
 
     def __buddy_activities_changed_cb(self, buddy_handle, activities):
         self._update_buddy_activities(buddy_handle, activities)
 
     def _update_buddy_activities(self, buddy_handle, activities):
         logging.debug('_Account._update_buddy_activities')
-        if not buddy_handle in self._buddy_handles:
-            self._buddy_handles[buddy_handle] = None
 
         if not buddy_handle in self._activities_per_buddy:
             self._activities_per_buddy[buddy_handle] = set()
@@ -433,6 +462,19 @@ class _Account(gobject.GObject):
         for activity_id, room_handle in activities:
             if room_handle not in self._activity_handles:
                 self._activity_handles[room_handle] = activity_id
+
+                if buddy_handle == self._self_handle:
+                    home_model = shell.get_model()
+                    activity = home_model.get_active_activity()
+                    if activity.get_activity_id() == activity_id:
+                        connection = self._connection[
+                            CONNECTION_INTERFACE_BUDDY_INFO]
+                        connection.SetCurrentActivity(
+                            activity_id,
+                            room_handle,
+                            reply_handler=self.__set_current_activity_cb,
+                            error_handler=self.__set_current_activity_error_cb)
+
                 self.emit('activity-added', room_handle, activity_id)
 
                 connection = self._connection[
@@ -443,23 +485,25 @@ class _Account(gobject.GObject):
                      error_handler=partial(self.__error_handler_cb,
                                            'ActivityProperties.GetProperties'))
 
-                # Sometimes we'll get CurrentActivityChanged before we get to
-                # know about the activity so we miss the event. In that case,
-                # request again the current activity for this buddy.
-                connection = self._connection[CONNECTION_INTERFACE_BUDDY_INFO]
-                connection.GetCurrentActivity(
-                    buddy_handle,
-                    reply_handler=partial(self.__get_current_activity_cb,
-                                          buddy_handle),
-                    error_handler=partial(self.__error_handler_cb,
-                                          'BuddyInfo.GetCurrentActivity'))
+                if buddy_handle != self._self_handle:
+                    # Sometimes we'll get CurrentActivityChanged before we get
+                    # to know about the activity so we miss the event. In that
+                    # case, request again the current activity for this buddy.
+                    connection = self._connection[
+                        CONNECTION_INTERFACE_BUDDY_INFO]
+                    connection.GetCurrentActivity(
+                        buddy_handle,
+                        reply_handler=partial(self.__get_current_activity_cb,
+                                              buddy_handle),
+                        error_handler=partial(self.__error_handler_cb,
+                                              'BuddyInfo.GetCurrentActivity'))
 
             if not activity_id in self._buddies_per_activity:
                 self._buddies_per_activity[activity_id] = set()
             self._buddies_per_activity[activity_id].add(buddy_handle)
             if activity_id not in self._activities_per_buddy[buddy_handle]:
                 self._activities_per_buddy[buddy_handle].add(activity_id)
-                if self._buddy_handles[buddy_handle] is not None:
+                if buddy_handle != self._self_handle:
                     self.emit('buddy-joined-activity',
                               self._buddy_handles[buddy_handle],
                               activity_id)
@@ -483,7 +527,7 @@ class _Account(gobject.GObject):
         if activity_id in self._activities_per_buddy[buddy_handle]:
             self._activities_per_buddy[buddy_handle].remove(activity_id)
 
-        if self._buddy_handles[buddy_handle] is not None:
+        if buddy_handle != self._self_handle:
             self.emit('buddy-left-activity',
                       self._buddy_handles[buddy_handle],
                       activity_id)
@@ -642,6 +686,7 @@ class Neighborhood(gobject.GObject):
         self._activities = {}
         self._link_local_account = None
         self._server_account = None
+        self._shell_model = shell.get_model()
 
         client = gconf.client_get_default()
         client.add_dir('/desktop/sugar/collaboration',
@@ -930,6 +975,8 @@ class Neighborhood(gobject.GObject):
         activity.props.private = properties['private']
 
         if is_new:
+            self._shell_model.add_shared_activity(activity_id,
+                                                  activity.props.color)
             self.emit('activity-added', activity)
 
     def __activity_removed_cb(self, account, activity_id):
@@ -940,6 +987,7 @@ class Neighborhood(gobject.GObject):
             return
         activity = self._activities[activity_id]
         del self._activities[activity_id]
+        self._shell_model.remove_shared_activity(activity_id)
 
         if activity.props.bundle is not None:
             self.emit('activity-removed', activity)
diff --git a/src/jarabe/model/shell.py b/src/jarabe/model/shell.py
index 63f6173..a17c593 100644
--- a/src/jarabe/model/shell.py
+++ b/src/jarabe/model/shell.py
@@ -29,7 +29,6 @@ from sugar import dispatch
 from sugar.graphics.xocolor import XoColor
 
 from jarabe.model.bundleregistry import get_registry
-from jarabe.model import neighborhood
 
 _SERVICE_NAME = 'org.laptop.Activity'
 _SERVICE_PATH = '/org/laptop/Activity'
@@ -53,7 +52,7 @@ class Activity(gobject.GObject):
     LAUNCH_FAILED = 1
     LAUNCHED = 2
 
-    def __init__(self, activity_info, activity_id, window=None):
+    def __init__(self, activity_info, activity_id, color, window=None):
         """Initialise the HomeActivity
 
         activity_info -- sugar.activity.registry.ActivityInfo instance,
@@ -74,6 +73,13 @@ class Activity(gobject.GObject):
         self._launch_time = time.time()
         self._launch_status = Activity.LAUNCHING
 
+        if color is not None:
+            self._color = color
+        else:
+            client = gconf.client_get_default()
+            color = client.get_string('/desktop/sugar/user/color')
+            self._color = XoColor(color)
+
         if window is not None:
             self.add_window(window)
 
@@ -152,19 +158,7 @@ class Activity(gobject.GObject):
         have an entry (implying that this is not a Sugar-shared application)
         uses the local user's profile colour for the icon.
         """
-        # HACK to suppress warning in logs when activity isn't found
-        # (if it's locally launched and not shared yet)
-        activity = None
-        for act in neighborhood.get_model().get_activities():
-            if self._activity_id == act.activity_id:
-                activity = act
-                break
-
-        if activity != None:
-            return activity.props.color
-        else:
-            client = gconf.client_get_default()
-            return XoColor(client.get_string('/desktop/sugar/user/color'))
+        return self._color
 
     def get_activity_id(self):
         """Retrieve the "activity_id" passed in to our constructor
@@ -204,7 +198,7 @@ class Activity(gobject.GObject):
         activity to determine to which HomeActivity the newly
         launched window belongs.
         """
-	if self._windows:
+        if self._windows:
             return self._windows[0]
         return None
 
@@ -370,6 +364,7 @@ class ShellModel(gobject.GObject):
         self._zoom_level = self.ZOOM_HOME
         self._current_activity = None
         self._activities = []
+        self._shared_activities = {}
         self._active_activity = None
         self._tabbing_activity = None
         self._launchers = {}
@@ -470,6 +465,12 @@ class ShellModel(gobject.GObject):
         """Returns the activity that the user is currently working in"""
         return self._active_activity
 
+    def add_shared_activity(self, activity_id, color):
+        self._shared_activities[activity_id] = color
+
+    def remove_shared_activity(self, activity_id):
+        del self._shared_activities[activity_id]
+
     def get_tabbing_activity(self):
         """Returns the activity that is currently highlighted during tabbing"""
         return self._tabbing_activity
@@ -543,7 +544,9 @@ class ShellModel(gobject.GObject):
 
             if not home_activity:
                 logging.debug('first window registered for %s' % activity_id)
-                home_activity = Activity(activity_info, activity_id, window)
+                color = self._shared_activities.get(activity_id, None)
+                home_activity = Activity(activity_info, activity_id,
+                                         color, window)
                 self._add_activity(home_activity)
             else:
                 logging.debug('window registered for %s' % activity_id)
@@ -623,7 +626,8 @@ class ShellModel(gobject.GObject):
             raise ValueError("Activity service name '%s'" \
                              " was not found in the bundle registry."
                              % service_name)
-        home_activity = Activity(activity_info, activity_id)
+        color = self._shared_activities.get(activity_id, None)
+        home_activity = Activity(activity_info, activity_id, color)
         self._add_activity(home_activity)
 
         self._set_active_activity(home_activity)
-- 
1.7.4.4



More information about the Sugar-devel mailing list