1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 """UI interface to a buddy in the presence service
19
20 STABLE.
21 """
22
23 import gobject
24 import gtk
25 import dbus
26
27
28 -class Buddy(gobject.GObject):
29 """UI interface for a Buddy in the presence service
30
31 Each buddy interface tracks a set of activities and properties
32 that can be queried to provide UI controls for manipulating
33 the presence interface.
34
35 Properties Dictionary:
36 'key': public key,
37 'nick': nickname ,
38 'color': color (XXX what format),
39 'current-activity': (XXX dbus path?),
40 'owner': (XXX dbus path?),
41 'icon': (XXX pixel data for an icon?)
42 See __gproperties__
43 """
44
45 __gsignals__ = {
46 'icon-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
47 'joined-activity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
48 ([gobject.TYPE_PYOBJECT])),
49 'left-activity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
50 ([gobject.TYPE_PYOBJECT])),
51 'property-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
52 ([gobject.TYPE_PYOBJECT])),
53 }
54
55 __gproperties__ = {
56 'key': (str, None, None, None, gobject.PARAM_READABLE),
57 'icon': (str, None, None, None, gobject.PARAM_READABLE),
58 'nick': (str, None, None, None, gobject.PARAM_READABLE),
59 'color': (str, None, None, None, gobject.PARAM_READABLE),
60 'current-activity': (object, None, None, gobject.PARAM_READABLE),
61 'owner': (bool, None, None, False, gobject.PARAM_READABLE),
62 'ip4-address': (str, None, None, None, gobject.PARAM_READABLE),
63 'tags': (str, None, None, None, gobject.PARAM_READABLE),
64 }
65
66 _PRESENCE_SERVICE = "org.laptop.Sugar.Presence"
67 _BUDDY_DBUS_INTERFACE = "org.laptop.Sugar.Presence.Buddy"
68
69 - def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
70 """Initialise the reference to the buddy
71
72 bus -- dbus bus object
73 new_obj_cb -- callback to call when this buddy joins an activity
74 del_obj_cb -- callback to call when this buddy leaves an activity
75 object_path -- path to the buddy object
76 """
77 gobject.GObject.__init__(self)
78 self._object_path = object_path
79 self._ps_new_object = new_obj_cb
80 self._ps_del_object = del_obj_cb
81 self._properties = {}
82 self._activities = {}
83
84 bobj = bus.get_object(self._PRESENCE_SERVICE, object_path)
85 self._buddy = dbus.Interface(bobj, self._BUDDY_DBUS_INTERFACE)
86
87 self._icon_changed_signal = self._buddy.connect_to_signal(
88 'IconChanged', self._icon_changed_cb, byte_arrays=True)
89 self._joined_activity_signal = self._buddy.connect_to_signal(
90 'JoinedActivity', self._joined_activity_cb)
91 self._left_activity_signal = self._buddy.connect_to_signal(
92 'LeftActivity', self._left_activity_cb)
93 self._property_changed_signal = self._buddy.connect_to_signal(
94 'PropertyChanged', self._property_changed_cb)
95
96 self._properties = self._get_properties_helper()
97
98 activities = self._buddy.GetJoinedActivities()
99 for op in activities:
100 self._activities[op] = self._ps_new_object(op)
101 self._icon = None
102
104 self._icon_changed_signal.remove()
105 self._joined_activity_signal.remove()
106 self._left_activity_signal.remove()
107 self._property_changed_signal.remove()
108
110 """Retrieve the Buddy's property dictionary from the service object
111 """
112 props = self._buddy.GetProperties(byte_arrays=True)
113 if not props:
114 return {}
115 return props
116
118 """Retrieve a particular property from our property dictionary
119
120 pspec -- XXX some sort of GTK specifier object with attributes
121 including 'name', 'active' and 'icon-name'
122 """
123 if pspec.name == "key":
124 return self._properties["key"]
125 elif pspec.name == "nick":
126 return self._properties["nick"]
127 elif pspec.name == "color":
128 return self._properties["color"]
129 elif pspec.name == "tags":
130 return self._properties["tags"]
131 elif pspec.name == "current-activity":
132 if not self._properties.has_key("current-activity"):
133 return None
134 curact = self._properties["current-activity"]
135 if not len(curact):
136 return None
137 for activity in self._activities.values():
138 if activity.props.id == curact:
139 return activity
140 return None
141 elif pspec.name == "owner":
142 return self._properties["owner"]
143 elif pspec.name == "icon":
144 if not self._icon:
145 self._icon = str(self._buddy.GetIcon(byte_arrays=True))
146 return self._icon
147 elif pspec.name == "ip4-address":
148
149 if not self._properties.has_key("ip4-address"):
150 return None
151 return self._properties["ip4-address"]
152
154 """Retrieve our dbus object path"""
155 return self._object_path
156
158 """Emit GObject signal when icon has changed"""
159 self._icon = str(icon_data)
160 self.emit('icon-changed')
161 return False
162
166
168 """Emit activity joined signal with Activity object"""
169 self.emit('joined-activity', self._ps_new_object(object_path))
170 return False
171
180
182 """Emit activity left signal with Activity object
183
184 XXX this calls self._ps_new_object instead of self._ps_del_object,
185 which would seem to be the incorrect callback?
186 """
187 self.emit('left-activity', self._ps_new_object(object_path))
188 return False
189
198
200 """Emit property-changed signal with property dictionary
201
202 Generates a property-changed signal with the results of
203 _get_properties_helper()
204 """
205 self._properties = self._get_properties_helper()
206
207 self.emit('property-changed', prop_list)
208 return False
209
213
215 """Retrieve Buddy's icon as a GTK pixel buffer
216
217 XXX Why aren't the icons coming in as SVG?
218 """
219 if self.props.icon and len(self.props.icon):
220 pbl = gtk.gdk.PixbufLoader()
221 pbl.write(self.props.icon)
222 pbl.close()
223 return pbl.get_pixbuf()
224 else:
225 return None
226
228 """Retrieve the set of all activities which this buddy has joined
229
230 Uses the GetJoinedActivities method on the service
231 object to produce object paths, wraps each in an
232 Activity object.
233
234 returns list of presence Activity objects
235 """
236 try:
237 resp = self._buddy.GetJoinedActivities()
238 except dbus.exceptions.DBusException:
239 return []
240 acts = []
241 for item in resp:
242 acts.append(self._ps_new_object(item))
243 return acts
244