From 940329703f5106a6ee13e58c7f2bbd2ebf808415 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 22 Sep 2006 16:35:03 -0400 Subject: [PATCH 1/6] Clean up buddy checking & retrieval; make constructor choice between name & real buddy explicit. --- shell/model/BuddyModel.py | 63 +++++++++++++++++++++++++-------------- shell/model/Friends.py | 4 +-- 2 files changed, 41 insertions(+), 26 deletions(-) diff --git a/shell/model/BuddyModel.py b/shell/model/BuddyModel.py index 9e6c6bd3..7584b6e6 100644 --- a/shell/model/BuddyModel.py +++ b/shell/model/BuddyModel.py @@ -2,25 +2,35 @@ from sugar.presence import PresenceService from sugar.canvas.IconColor import IconColor class BuddyModel: - def __init__(self, buddy=None): + def __init__(self, name=None, buddy=None): + if name and buddy: + raise RuntimeError("Must specify only _one_ of name or buddy.") + self._cur_activity = None + self._buddy_appeared_handler = None self._pservice = PresenceService.get_instance() self._buddy = buddy + + # If given just a name, try to get the buddy from the PS first + if not self._buddy: + self._name = name + # FIXME: use public key, not name + self._buddy = self._pservice.get_buddy_by_name(self._name) + + # If successful, copy properties from the PS buddy object if self._buddy: - self.set_name(self._buddy.get_name()) - self.set_color(self._buddy.get_color()) - self._buddy.connect('property-changed', - self.__buddy_property_changed_cb) + self.__update_buddy(buddy) else: - # if we don't have a buddy yet, connect to the PS - # and wait until the buddy pops up on the network - self._pservice.connect('buddy-appeared', self.__buddy_appeared_cb) + # Otherwise, connect to the PS's buddy-appeared signal and + # wait for the buddy to appear + self._buddy_appeared_handler = self._pservice.connect('buddy-appeared', + self.__buddy_appeared_cb) + self._name = name + # Set color to 'inactive'/'disconnected' + self.__set_color_from_string("#888888,#BBBBBB") - def set_name(self, name): - self._name = name - - def set_color(self, color_string): + def __set_color_from_string(self, color_string): self._color = IconColor(color_string) def get_name(self): @@ -30,21 +40,28 @@ class BuddyModel: return self._color def get_buddy(self): - # If we have a buddy already, just return - if self._buddy: - return self._buddy - - # Otherwise try to get the buddy from the PS - self._buddy = self._pservice.get_buddy_by_name(self._name) - if self._buddy: - self._buddy.connect('property-changed', - self.__buddy_property_changed_cb) return self._buddy + def __update_buddy(self, buddy): + if not buddy: + raise ValueError("Buddy cannot be None.") + self._buddy = buddy + self._name = self._buddy.get_name() + self.__set_color_from_string(self._buddy.get_color()) + self._buddy.connect('property-changed', self.__buddy_property_changed_cb) + def __buddy_appeared_cb(self, pservice, buddy): # FIXME: use public key rather than buddy name - if not self._buddy and buddy.get_name() == self._name: - self.get_buddy() + if self._buddy or buddy.get_name() != self._name: + return + + if self._buddy_appeared_handler: + # Once we have the buddy, we no longer need to + # monitor buddy-appeared events + self._pservice.disconnect(self._buddy_appeared_handler) + self._buddy_appeared_handler = None + + self.__update_buddy(buddy) def __buddy_property_changed_cb(self, buddy, keys): # all we care about right now is current activity diff --git a/shell/model/Friends.py b/shell/model/Friends.py index 4a2298c5..5048688b 100644 --- a/shell/model/Friends.py +++ b/shell/model/Friends.py @@ -50,9 +50,7 @@ class Friends(gobject.GObject): success = cp.read([self._path]) if success: for name in cp.sections(): - buddy = BuddyModel() - buddy.set_name(name) - buddy.set_color(cp.get(name, 'color')) + buddy = BuddyModel(name) self.add_friend(buddy) except Exception, exc: logging.error("Error parsing friends file: %s" % exc) From 6473444e099e004d5840e034a22151c77654b360 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 22 Sep 2006 17:21:34 -0400 Subject: [PATCH 2/6] Add a 'Disappeared' signal on the buddy object --- services/presence/Buddy.py | 6 ++++++ sugar/presence/Buddy.py | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/services/presence/Buddy.py b/services/presence/Buddy.py index bf369f7e..618902e9 100644 --- a/services/presence/Buddy.py +++ b/services/presence/Buddy.py @@ -33,6 +33,11 @@ class BuddyDBusHelper(dbus.service.Object): def ServiceDisappeared(self, object_path): pass + @dbus.service.signal(BUDDY_DBUS_INTERFACE, + signature="") + def Disappeared(self): + pass + @dbus.service.signal(BUDDY_DBUS_INTERFACE, signature="") def IconChanged(self): @@ -268,6 +273,7 @@ class Buddy(object): if service.get_type() == PRESENCE_SERVICE_TYPE: self._valid = False + self._dbus_helper.Disappeared() def remove_activity(self, activity): actid = activity.get_id() diff --git a/sugar/presence/Buddy.py b/sugar/presence/Buddy.py index ee7bfdef..a0d3fd15 100644 --- a/sugar/presence/Buddy.py +++ b/sugar/presence/Buddy.py @@ -7,6 +7,8 @@ class Buddy(gobject.GObject): __gsignals__ = { 'icon-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])), + 'disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + ([])), 'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])), 'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, @@ -33,6 +35,7 @@ class Buddy(gobject.GObject): self._buddy.connect_to_signal('IconChanged', self._icon_changed_cb) self._buddy.connect_to_signal('ServiceAppeared', self._service_appeared_cb) self._buddy.connect_to_signal('ServiceDisappeared', self._service_disappeared_cb) + self._buddy.connect_to_signal('Disappeared', self._disappeared_cb) self._buddy.connect_to_signal('JoinedActivity', self._joined_activity_cb) self._buddy.connect_to_signal('LeftActivity', self._left_activity_cb) self._buddy.connect_to_signal('PropertyChanged', self._property_changed_cb) @@ -54,6 +57,12 @@ class Buddy(gobject.GObject): def _icon_changed_cb(self): gobject.idle_add(self._emit_icon_changed_signal) + def _emit_disappeared_signal(self): + self.emit('disappeared') + + def _disappeared_cb(self): + gobject.idle_add(self._emit_disappeared_signal) + def _emit_service_appeared_signal(self, object_path): self.emit('service-appeared', self._ps_new_object(object_path)) return False From 2031eb650a7734029383bf49f01ad79870ccc16d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 22 Sep 2006 17:24:00 -0400 Subject: [PATCH 3/6] - don't hardcode inactive buddy color - shorten signal handler id variable names - add appeared/disappeared signals to BuddyModel - deal with buddy disappearance --- shell/model/BuddyModel.py | 49 +++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/shell/model/BuddyModel.py b/shell/model/BuddyModel.py index 7584b6e6..3d28c1b4 100644 --- a/shell/model/BuddyModel.py +++ b/shell/model/BuddyModel.py @@ -1,34 +1,47 @@ from sugar.presence import PresenceService from sugar.canvas.IconColor import IconColor +import gobject + +_NOT_PRESENT_COLOR = "#888888,#BBBBBB" + +class BuddyModel(gobject.GObject): + __gsignals__ = { + 'appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])), + 'disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])) + } -class BuddyModel: def __init__(self, name=None, buddy=None): if name and buddy: raise RuntimeError("Must specify only _one_ of name or buddy.") + gobject.GObject.__init__(self) + + self._ba_handler = None + self._pc_handler = None + self._dis_handler = None + self._cur_activity = None - self._buddy_appeared_handler = None self._pservice = PresenceService.get_instance() - self._buddy = buddy + self._buddy = None # If given just a name, try to get the buddy from the PS first - if not self._buddy: + if not buddy: self._name = name # FIXME: use public key, not name - self._buddy = self._pservice.get_buddy_by_name(self._name) + buddy = self._pservice.get_buddy_by_name(self._name) # If successful, copy properties from the PS buddy object - if self._buddy: + if buddy: self.__update_buddy(buddy) else: # Otherwise, connect to the PS's buddy-appeared signal and # wait for the buddy to appear - self._buddy_appeared_handler = self._pservice.connect('buddy-appeared', + self._ba_handler = self._pservice.connect('buddy-appeared', self.__buddy_appeared_cb) self._name = name # Set color to 'inactive'/'disconnected' - self.__set_color_from_string("#888888,#BBBBBB") + self.__set_color_from_string(_NOT_PRESENT_COLOR) def __set_color_from_string(self, color_string): self._color = IconColor(color_string) @@ -45,26 +58,38 @@ class BuddyModel: def __update_buddy(self, buddy): if not buddy: raise ValueError("Buddy cannot be None.") + self._buddy = buddy self._name = self._buddy.get_name() self.__set_color_from_string(self._buddy.get_color()) - self._buddy.connect('property-changed', self.__buddy_property_changed_cb) + + self._pc_handler = self._buddy.connect('property-changed', self.__buddy_property_changed_cb) + self._dis_handler = self._buddy.connect('disappeared', self.__buddy_disappeared_cb) def __buddy_appeared_cb(self, pservice, buddy): # FIXME: use public key rather than buddy name if self._buddy or buddy.get_name() != self._name: return - if self._buddy_appeared_handler: + if self._ba_handler: # Once we have the buddy, we no longer need to # monitor buddy-appeared events - self._pservice.disconnect(self._buddy_appeared_handler) - self._buddy_appeared_handler = None + self._pservice.disconnect(self._ba_handler) + self._ba_handler = None self.__update_buddy(buddy) + self.emit('appeared') def __buddy_property_changed_cb(self, buddy, keys): # all we care about right now is current activity curact = self._buddy.get_current_activity() self._cur_activity = self._pservice.get_activity(curact) + def __buddy_disappeared_cb(self, buddy): + if buddy != self._buddy: + return + self._buddy.disconnect(self._pc_handler) + self._buddy.disconnect(self._dis_handler) + self.__set_color_from_string(_NOT_PRESENT_COLOR) + self.emit('disappeared') + self._buddy = None From 188394f09f788b19303909738adfff8ec8c788c0 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 22 Sep 2006 17:24:56 -0400 Subject: [PATCH 4/6] - Track BuddyModel appeared/disappeared signals, and update our icon colors accordingly - s/friend/buddy since BuddyModel isn't just for friends --- shell/view/BuddyIcon.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/shell/view/BuddyIcon.py b/shell/view/BuddyIcon.py index 9ae709a5..21092268 100644 --- a/shell/view/BuddyIcon.py +++ b/shell/view/BuddyIcon.py @@ -2,18 +2,24 @@ from sugar.canvas.MenuIcon import MenuIcon from view.BuddyMenu import BuddyMenu class BuddyIcon(MenuIcon): - def __init__(self, shell, menu_shell, friend): + def __init__(self, shell, menu_shell, buddy): MenuIcon.__init__(self, menu_shell, icon_name='stock-buddy', - color=friend.get_color(), size=112) + color=buddy.get_color(), size=112) self._shell = shell - self._friend = friend + self._buddy = buddy + self._buddy.connect('appeared', self.__buddy_presence_change_cb) + self._buddy.connect('disappeared', self.__buddy_presence_change_cb) + + def __buddy_presence_change_cb(self, buddy): + # Update the icon's color when the buddy comes and goes + self.set_property('color', buddy.get_color()) def set_popup_distance(self, distance): self._popup_distance = distance def create_menu(self): - menu = BuddyMenu(self._shell, self._friend) + menu = BuddyMenu(self._shell, self._buddy) menu.connect('action', self._popup_action_cb) return menu @@ -22,14 +28,14 @@ class BuddyIcon(MenuIcon): friends = self._shell.get_model().get_friends() if action == BuddyMenu.ACTION_REMOVE_FRIEND: - friends.remove(self._friend) + friends.remove(self._buddy) - buddy = self._friend.get_buddy() - if buddy == None: + ps_buddy = self._buddy.get_buddy() + if ps_buddy == None: return if action == BuddyMenu.ACTION_INVITE: activity = self._shell.get_current_activity() - activity.invite(buddy) + activity.invite(ps_buddy) elif action == BuddyMenu.ACTION_MAKE_FRIEND: - friends.make_friend(buddy) + friends.make_friend(ps_buddy) From d12c57895ccc310f51fb5ccaa3e8bad2bfdcb788 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 22 Sep 2006 17:37:16 -0400 Subject: [PATCH 5/6] Add color-changed and current-activity-changed signals --- shell/model/BuddyModel.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/shell/model/BuddyModel.py b/shell/model/BuddyModel.py index 3d28c1b4..0606ca4f 100644 --- a/shell/model/BuddyModel.py +++ b/shell/model/BuddyModel.py @@ -7,7 +7,11 @@ _NOT_PRESENT_COLOR = "#888888,#BBBBBB" class BuddyModel(gobject.GObject): __gsignals__ = { 'appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])), - 'disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])) + 'disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])), + 'color-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + ([gobject.TYPE_PYOBJECT])), + 'current-activity-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + ([gobject.TYPE_PYOBJECT])) } def __init__(self, name=None, buddy=None): @@ -81,9 +85,17 @@ class BuddyModel(gobject.GObject): self.emit('appeared') def __buddy_property_changed_cb(self, buddy, keys): + if not self._buddy: + return + # all we care about right now is current activity - curact = self._buddy.get_current_activity() - self._cur_activity = self._pservice.get_activity(curact) + if 'curact' in keys: + curact = self._buddy.get_current_activity() + self._cur_activity = self._pservice.get_activity(curact) + self.emit('current-activity-changed', self._cur_activity) + if 'color' in keys: + self.__set_color_from_string(self._buddy.get_color()) + self.emit('color-changed', self.get_color()) def __buddy_disappeared_cb(self, buddy): if buddy != self._buddy: @@ -91,5 +103,7 @@ class BuddyModel(gobject.GObject): self._buddy.disconnect(self._pc_handler) self._buddy.disconnect(self._dis_handler) self.__set_color_from_string(_NOT_PRESENT_COLOR) + self._cur_activity = None + self.emit('current-activity-changed', self._cur_activity) self.emit('disappeared') self._buddy = None From e92548df5c0cd1db4b6fd31a80844ffd4e530448 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 22 Sep 2006 17:37:41 -0400 Subject: [PATCH 6/6] Use the new BuddyModel color-changed signal --- shell/view/BuddyIcon.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shell/view/BuddyIcon.py b/shell/view/BuddyIcon.py index 21092268..f6386e0d 100644 --- a/shell/view/BuddyIcon.py +++ b/shell/view/BuddyIcon.py @@ -10,8 +10,9 @@ class BuddyIcon(MenuIcon): self._buddy = buddy self._buddy.connect('appeared', self.__buddy_presence_change_cb) self._buddy.connect('disappeared', self.__buddy_presence_change_cb) + self._buddy.connect('color-changed', self.__buddy_presence_change_cb) - def __buddy_presence_change_cb(self, buddy): + def __buddy_presence_change_cb(self, buddy, color=None): # Update the icon's color when the buddy comes and goes self.set_property('color', buddy.get_color())