I extended the Invites to handle connections for 1-1 connections. This
should also handle incoming streaming media connections for VideoChat
(when that activity has the necessary bits in place).

It depends on Guillaume's patches in http://dev.laptop.org/ticket/6298
for presence-service, sugar, sugar-toolkit and chat-activity.

I will get this patch up in my git repo, as soon as I can figure out
why it won't allow me to push (non-fast forward).

It works in jhbuild with incoming XMPP chat giving an invite for Chat,
which launches Chat. The only thing not working yet is removing the
invite when you click on it.

Review please...

Morgan
commit a856fc40557fb1efc6e029088d49f74564d4675c
Author: Morgan Collett <[EMAIL PROTECTED]>
Date:   Fri May 23 16:47:58 2008 +0200

    #6298: Refactor invites to handle 1-1 XMPP connections

diff --git a/src/model/Invites.py b/src/model/Invites.py
index 9ffab44..2a4c9f2 100644
--- a/src/model/Invites.py
+++ b/src/model/Invites.py
@@ -18,10 +18,11 @@ import gobject
 from sugar.presence import presenceservice
 
 class Invite:
-    def __init__(self, issuer, bundle_id, activity_id):
-        self._issuer = issuer
+    def __init__(self, bundle_id, activity_id=None, 
+                 private_connection=None):
         self._activity_id = activity_id
         self._bundle_id = bundle_id
+        self._private_connection = private_connection
 
     def get_activity_id(self):
         return self._activity_id
@@ -29,6 +30,11 @@ class Invite:
     def get_bundle_id(self):
         return self._bundle_id
 
+    def get_private_connection(self):
+        """Connection info from private invitation"""
+        return self._private_connection
+
+
 class Invites(gobject.GObject):
     __gsignals__ = {
         'invite-added':   (gobject.SIGNAL_RUN_FIRST,
@@ -41,30 +47,52 @@ class Invites(gobject.GObject):
         gobject.GObject.__init__(self)
 
         self._dict = {}
+        self._private_invites = {}
 
         ps = presenceservice.get_instance()
         owner = ps.get_owner()
         owner.connect('joined-activity', self._owner_joined_cb)
+        # FIXME need equivalent for ^ for private invite
 
-    def add_invite(self, issuer, bundle_id, activity_id):
+    def add_invite(self, bundle_id, activity_id):
         if activity_id in self._dict:
             # there is no point to add more than one time
             # an invite for the same activity
             return
 
-        invite = Invite(issuer, bundle_id, activity_id)
+        invite = Invite(bundle_id, activity_id=activity_id)
         self._dict[activity_id] = invite
         self.emit('invite-added', invite)
 
+    def add_private_invite(self, private_connection, bundle_id):
+        if private_connection in self._dict:
+            # there is no point to add more than one invite for the
+            # same incoming connection
+            return
+
+        invite = Invite(bundle_id,
+                        private_connection=private_connection)
+        self._dict[private_connection] = invite
+        self.emit('invite-added', invite)
+
     def remove_invite(self, invite):
         self._dict.pop(invite.get_activity_id())
         self.emit('invite-removed', invite)
 
+    def remove_private_invite(self, invite):
+        self._dict.pop(invite.get_private_connection())
+        self.emit('invite-removed', invite)
+
     def remove_activity(self, activity_id):
         invite = self._dict.get(activity_id)
         if invite is not None:
             self.remove_invite(invite)
 
+    def remove_private_connection(self, private_connection):
+        invite = self._dict.get(private_connection)
+        if invite is not None:
+            self.remove_private_invite(invite)
+
     def _owner_joined_cb(self, owner, activity):
         self.remove_activity(activity.props.id)
 
diff --git a/src/model/Owner.py b/src/model/Owner.py
index 7affb83..1643c6f 100644
--- a/src/model/Owner.py
+++ b/src/model/Owner.py
@@ -17,6 +17,7 @@
 
 import gobject
 import os
+import json
 
 from telepathy.interfaces import CHANNEL_TYPE_TEXT
 
@@ -81,7 +82,7 @@ class ShellOwner(gobject.GObject):
         return self._nick
 
     def _activity_invitation_cb(self, pservice, activity, buddy, message):
-        self._invites.add_invite(buddy, activity.props.type,
+        self._invites.add_invite(activity.props.type,
                                  activity.props.id)
 
     def _private_invitation_cb(self, pservice, bus_name, connection,
@@ -91,14 +92,13 @@ class ShellOwner(gobject.GObject):
         This is a connection by a non-Sugar XMPP client, so
         launch Chat with the Telepathy connection and channel.
         """
-        import json
-        from sugar import activity
-        from sugar.activity import activityfactory
+        if channel_type == CHANNEL_TYPE_TEXT:
+            bundle_id = 'org.laptop.Chat'
+        else:
+            bundle_id = 'org.laptop.VideoChat'
         tp_channel = json.write([str(bus_name), str(connection),
                                  str(channel)])
-        registry = activity.get_registry()
-        if registry.get_activity('org.laptop.Chat') and channel_type == CHANNEL_TYPE_TEXT:
-            activityfactory.create_with_uri('org.laptop.Chat', tp_channel)
+        self._invites.add_private_invite(tp_channel, bundle_id)
 
     def _activity_disappeared_cb(self, pservice, activity):
         self._invites.remove_activity(activity.props.id)
diff --git a/src/view/Shell.py b/src/view/Shell.py
index f45923d..6dddda9 100644
--- a/src/view/Shell.py
+++ b/src/view/Shell.py
@@ -169,6 +169,14 @@ class Shell(gobject.GObject):
         self._activities_starting.add(activity_type)
         activityfactory.create(activity_type)
 
+    def start_activity_with_uri(self, activity_type, uri):
+        if activity_type in self._activities_starting:
+            logging.debug("This activity is still launching.")
+            return
+
+        self._activities_starting.add(activity_type)
+        activityfactory.create_with_uri(activity_type, uri)
+
     def take_activity_screenshot(self):
         if self._model.get_zoom_level() != shellmodel.ShellModel.ZOOM_ACTIVITY:
             return
diff --git a/src/view/frame/activitiestray.py b/src/view/frame/activitiestray.py
index 3958f20..50b6f69 100644
--- a/src/view/frame/activitiestray.py
+++ b/src/view/frame/activitiestray.py
@@ -26,7 +26,7 @@ from sugar.graphics.toolbutton import ToolButton
 from sugar.graphics.icon import Icon
 from sugar.graphics.palette import Palette, WidgetInvoker
 from sugar.graphics.menuitem import MenuItem
-from sugar import activity
+from sugar import activity, profile
 
 from model import shellmodel
 from view.palettes import JournalPalette, CurrentActivityPalette
@@ -88,21 +88,43 @@ class ActivityButton(RadioToolButton):
             home_activity.disconnect(self._notify_launching_hid)
 
 class InviteButton(ToolButton):
-    def __init__(self, activity_model):
+    """Invite to shared activity"""
+    def __init__(self, invite):
         ToolButton.__init__(self)
 
-        self._activity_model = activity_model
+        self._invite = invite
+        self._activity_model = activity_model = None
+        self._private_connection = None
+        if invite.get_activity_id():
+            # shared activity
+            mesh = shellmodel.get_instance().get_mesh()
+            activity_model = mesh.get_activity(invite.get_activity_id())
+            self._activity_model = activity_model
+            self._bundle_id = activity_model.get_bundle_id()
+        else:
+            # private invite to 1-1 connection
+            self._private_connection = invite.get_private_connection()
+            self._bundle_id = invite.get_bundle_id()
 
         self._icon = Icon()
-        self._icon.props.xo_color = activity_model.get_color()
-        if activity_model.get_icon_name():
-            self._icon.props.file = activity_model.get_icon_name()
+        if activity_model:
+            self._icon.props.xo_color = activity_model.get_color()
+            if activity_model.get_icon_name():
+                self._icon.props.file = activity_model.get_icon_name()
+            else:
+                self._icon.props.icon_name = 'image-missing'
         else:
-            self._icon.props.icon_name = 'image-missing'
+            self._icon.props.xo_color = profile.get_color()
+            registry = activity.get_registry()
+            activity_info = registry.get_activity(self._bundle_id)
+            if activity_info:
+                self._icon.props.file = activity_info.icon
+            else:
+                self._icon.props.icon_name = 'image-missing'
         self.set_icon_widget(self._icon)
         self._icon.show()
 
-        palette = InvitePalette(activity_model)
+        palette = InvitePalette(invite)
         palette.props.invoker = FrameWidgetInvoker(self)
         palette.set_group_id('frame')
         self.set_palette(palette)
@@ -111,16 +133,25 @@ class InviteButton(ToolButton):
         self.connect('destroy', self.__destroy_cb)
 
         self._notif_icon = NotificationIcon()
-        self._notif_icon.props.xo_color = activity_model.get_color()
-        if activity_model.get_icon_name():
-            icon_name = activity_model.get_icon_name()
-            self._notif_icon.props.icon_filename = icon_name
+        if activity_model:
+            self._notif_icon.props.xo_color = activity_model.get_color()
+            if activity_model.get_icon_name():
+                icon_name = activity_model.get_icon_name()
+                self._notif_icon.props.icon_filename = icon_name
+            else:
+                self._notif_icon.props.icon_name = 'image-missing'
         else:
-            self._notif_icon.props.icon_name = 'image-missing'
+            self._notif_icon.props.xo_color = profile.get_color()
+            registry = activity.get_registry()
+            activity_info = registry.get_activity(self._bundle_id)
+            if activity_info:
+                self._notif_icon.props.icon_filename = activity_info.icon
+            else:
+                self._notif_icon.props.icon_name = 'image-missing'
         self._notif_icon.connect('button-release-event',
                                  self.__button_release_event_cb)
 
-        palette = InvitePalette(activity_model)
+        palette = InvitePalette(invite)
         palette.props.invoker = WidgetInvoker(self._notif_icon)
         palette.set_group_id('frame')
         self._notif_icon.palette = palette
@@ -137,25 +168,42 @@ class InviteButton(ToolButton):
             self._notif_icon = None
 
         shell = view.Shell.get_instance()
-        shell.join_activity(self._activity_model.get_bundle_id(),
-                            self._activity_model.get_id())
+        if self._activity_model:
+            shell.join_activity(self._activity_model.get_bundle_id(),
+                                self._activity_model.get_id())
+        else:
+            shell.start_activity_with_uri(self._bundle_id, 
+                                          self._private_connection)
 
     def __destroy_cb(self, button):
         frame = view.frame.frame.get_instance()
         frame.remove_notification(self._notif_icon)
     
 class InvitePalette(Palette):
-    def __init__(self, activity_model):
-        self._activity_model = activity_model
+    def __init__(self, invite):
+        
+        self._invite = invite
+        self._activity_model = activity_model = None
+        self._private_connection = None
+        if invite.get_activity_id():
+            # shared activity
+            mesh = shellmodel.get_instance().get_mesh()
+            activity_model = mesh.get_activity(invite.get_activity_id())
+            self._activity_model = activity_model
+            self._bundle_id = activity_model.get_bundle_id()
+        else:
+            # private invite to 1-1 connection
+            self._private_connection = invite.get_private_connection()
+            self._bundle_id = invite.get_bundle_id()
 
         Palette.__init__(self, '')
 
         registry = activity.get_registry()
-        activity_info = registry.get_activity(activity_model.get_bundle_id())
+        activity_info = registry.get_activity(self._bundle_id)
         if activity_info:
             self.set_primary_text(activity_info.name)
         else:
-            self.set_primary_text(activity_model.get_bundle_id())
+            self.set_primary_text(self._bundle_id)
 
         menu_item = MenuItem(_('Join'), icon_name='dialog-ok')
         menu_item.connect('activate', self.__join_activate_cb)
@@ -169,15 +217,21 @@ class InvitePalette(Palette):
 
     def __join_activate_cb(self, menu_item):
         shell = view.Shell.get_instance()
-        shell.join_activity(self._activity_model.get_bundle_id(),
-                            self._activity_model.get_id())
+        if self._activity_model:
+            shell.join_activity(self._activity_model.get_bundle_id(),
+                                self._activity_model.get_id())
+        else:
+            shell.start_activity_with_uri(self._bundle_id,
+                                          self._private_connection)
 
     def __decline_activate_cb(self, menu_item):
         invites = shellmodel.get_instance().get_invites()
-        for invite in invites:
-            if invite.get_activity_id() == self._activity_model.get_id():
-                invites.remove_invite(invite)
-                return
+        if self._activity_model:
+            activity_id = self._activity_model.get_id()
+            invites.remove_activity(activity_id)
+        else:
+            invites.remove_private_connection(self._private_connection)
+
 
 class ActivitiesTray(HTray):
     def __init__(self):
@@ -237,15 +291,17 @@ class ActivitiesTray(HTray):
         self._remove_invite(invite)
 
     def _add_invite(self, invite):
-        mesh = shellmodel.get_instance().get_mesh()
-        activity_model = mesh.get_activity(invite.get_activity_id())
-        if activity_model:
-            item = InviteButton(activity_model)
-            item.connect('clicked', self.__invite_clicked_cb, invite)
-            self.add_item(item)
-            item.show()
-
-            self._invite_to_item[invite] = item
+        """Add an invite (SugarInvite or PrivateInvite)"""
+        if invite.get_activity_id():
+            mesh = shellmodel.get_instance().get_mesh()
+            activity_model = mesh.get_activity(invite.get_activity_id())
+            if not activity_model:
+                return
+        item = InviteButton(invite)
+        item.connect('clicked', self.__invite_clicked_cb, invite)
+        self.add_item(item)
+        item.show()
+        self._invite_to_item[invite] = item
 
     def _remove_invite(self, invite):
         self.remove_item(self._invite_to_item[invite])
_______________________________________________
Sugar mailing list
Sugar@lists.laptop.org
http://lists.laptop.org/listinfo/sugar

Reply via email to