Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/sugar
diff options
context:
space:
mode:
authorMarco Pesenti Gritti <mpg@redhat.com>2007-10-15 21:48:17 (GMT)
committer Marco Pesenti Gritti <mpg@redhat.com>2007-10-15 21:48:17 (GMT)
commit1eb9932ab312ee0bd2f38585ae1caa0bc447dfd0 (patch)
treed87f2c0ed37881031ef8072baaf62df0204c1dee /sugar
parentc975b11606400043a49cae8a90bbd5ed044e9233 (diff)
parent0a27ed0c554e453ef2528341a32cda866a640dcc (diff)
Merge branch 'master' of git+ssh://dev.laptop.org/git/sugar
Diffstat (limited to 'sugar')
-rw-r--r--sugar/graphics/alert.py92
-rw-r--r--sugar/presence/activity.py48
2 files changed, 120 insertions, 20 deletions
diff --git a/sugar/graphics/alert.py b/sugar/graphics/alert.py
index 960cbef..ef93a5a 100644
--- a/sugar/graphics/alert.py
+++ b/sugar/graphics/alert.py
@@ -1,8 +1,27 @@
+# Copyright (C) 2007, One Laptop Per Child
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
from gettext import gettext as _
import gtk
import gobject
-
+import hippo
+import math
+
from sugar.graphics import style
from sugar.graphics.icon import Icon
@@ -28,7 +47,7 @@ class Alert(gtk.EventBox, gobject.GObject):
__gsignals__ = {
'response': (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([int]))
+ gobject.TYPE_NONE, ([object]))
}
__gproperties__ = {
@@ -69,7 +88,8 @@ class Alert(gtk.EventBox, gobject.GObject):
self._hbox.pack_start(self._msg_box)
self._buttons_box = gtk.HButtonBox()
- self._buttons_box.set_layout(gtk.BUTTONBOX_SPREAD)
+ self._buttons_box.set_layout(gtk.BUTTONBOX_END)
+ self._buttons_box.set_spacing(style.DEFAULT_SPACING)
self._hbox.pack_start(self._buttons_box)
self._buttons_box.show()
@@ -99,17 +119,20 @@ class Alert(gtk.EventBox, gobject.GObject):
elif pspec.name == 'msg':
return self._msg
- def add_button(self, response_id, label, icon, position=-1):
+ def add_button(self, response_id, label, icon=None, position=-1):
"""Add a button to the alert
response_id: will be emitted with the response signal
+ a response ID should one of the pre-defined
+ GTK Response Type Constants or a positive number
label: that will occure right to the buttom
icon: this can be a SugarIcon or a gtk.Image
position: the position of the button in the box (optional)
"""
button = gtk.Button()
self._buttons[response_id] = button
- button.set_image(icon)
+ if icon is not None:
+ button.set_image(icon)
button.set_label(label)
self._buttons_box.pack_start(button)
button.show()
@@ -142,11 +165,66 @@ class ConfirmationAlert(Alert):
Alert.__init__(self, **kwargs)
icon = Icon(icon_name='dialog-cancel')
- cancel_button = self.add_button(0, _('Cancel'), icon)
+ cancel_button = self.add_button(gtk.RESPONSE_CANCEL, _('Cancel'), icon)
icon.show()
icon = Icon(icon_name='dialog-ok')
- ok_button = self.add_button(1, _('Ok'), icon)
+ ok_button = self.add_button(gtk.RESPONSE_OK, _('Ok'), icon)
icon.show()
+class _TimeoutIcon(hippo.CanvasText, hippo.CanvasItem):
+ __gtype_name__ = 'AlertTimeoutIcon'
+
+ def __init__(self, **kwargs):
+ hippo.CanvasText.__init__(self, **kwargs)
+
+ self.props.orientation = hippo.ORIENTATION_HORIZONTAL
+ self.props.border_left = style.DEFAULT_SPACING
+ self.props.border_right = style.DEFAULT_SPACING
+
+ def do_paint_background(self, cr, damaged_box):
+ [width, height] = self.get_allocation()
+
+ x = width * 0.5
+ y = height * 0.5
+ radius = min(width * 0.5, height * 0.5)
+
+ hippo.cairo_set_source_rgba32(cr, self.props.background_color)
+ cr.arc(x, y, radius, 0, 2*math.pi)
+ cr.fill_preserve()
+
+
+class TimeoutAlert(Alert):
+ """This is a ready-made two button (Cancel,Continue) alert
+
+ It times out with a positive reponse after the given amount of seconds.
+ """
+
+ def __init__(self, timeout=5, **kwargs):
+ Alert.__init__(self, **kwargs)
+
+ self._timeout = timeout
+
+ icon = Icon(icon_name='dialog-cancel')
+ cancel_button = self.add_button(gtk.RESPONSE_CANCEL, _('Cancel'), icon)
+ icon.show()
+
+ self._timeout_text = _TimeoutIcon(
+ text=self._timeout,
+ color=style.COLOR_BUTTON_GREY.get_int(),
+ background_color=style.COLOR_WHITE.get_int())
+ canvas = hippo.Canvas()
+ canvas.set_root(self._timeout_text)
+ canvas.show()
+ self.add_button(gtk.RESPONSE_OK, _('Continue'), canvas)
+
+ gobject.timeout_add(1000, self.__timeout)
+
+ def __timeout(self):
+ self._timeout -= 1
+ self._timeout_text.props.text = self._timeout
+ if self._timeout == 0:
+ self._response(gtk.RESPONSE_OK)
+ return False
+ return True
diff --git a/sugar/presence/activity.py b/sugar/presence/activity.py
index c4c0a47..c37b63a 100644
--- a/sugar/presence/activity.py
+++ b/sugar/presence/activity.py
@@ -26,9 +26,8 @@ _logger = logging.getLogger('sugar.presence.activity')
class Activity(gobject.GObject):
"""UI interface for an Activity in the presence service
- Activities in the presence service represent other user's
- shared activities and your own activities (XXX shared or
- otherwise?)
+ Activities in the presence service represent your and other user's
+ shared activities.
Properties:
id
@@ -69,8 +68,10 @@ class Activity(gobject.GObject):
self._ps_del_object = del_obj_cb
bobj = bus.get_object(self._PRESENCE_SERVICE, object_path)
self._activity = dbus.Interface(bobj, self._ACTIVITY_DBUS_INTERFACE)
- self._activity.connect_to_signal('BuddyJoined', self._buddy_joined_cb)
- self._activity.connect_to_signal('BuddyLeft', self._buddy_left_cb)
+ self._activity.connect_to_signal('BuddyHandleJoined',
+ self._buddy_handle_joined_cb)
+ self._activity.connect_to_signal('BuddyLeft',
+ self._buddy_left_cb)
self._activity.connect_to_signal('NewChannel', self._new_channel_cb)
self._activity.connect_to_signal('PropertiesChanged',
self._properties_changed_cb,
@@ -90,6 +91,9 @@ class Activity(gobject.GObject):
self._tags = None
self._private = True
self._joined = False
+ # Cache for get_buddy_by_handle, maps handles to buddy object paths
+ self._handle_to_buddy_path = {}
+ self._buddy_path_to_handle = {}
def _get_properties_reply_cb(self, new_props):
self._properties_changed_cb(new_props)
@@ -178,8 +182,10 @@ class Activity(gobject.GObject):
self.emit('buddy-joined', self._ps_new_object(object_path))
return False
- def _buddy_joined_cb(self, object_path):
+ def _buddy_handle_joined_cb(self, object_path, handle):
gobject.idle_add(self._emit_buddy_joined_signal, object_path)
+ self._handle_to_buddy_path[handle] = object_path
+ self._buddy_path_to_handle[object_path] = handle
def _emit_buddy_left_signal(self, object_path):
"""Generate buddy-left GObject signal with presence Buddy object
@@ -191,6 +197,8 @@ class Activity(gobject.GObject):
def _buddy_left_cb(self, object_path):
gobject.idle_add(self._emit_buddy_left_signal, object_path)
+ handle = self._buddy_path_to_handle.pop(object_path)
+ self._handle_to_buddy_path.pop(handle, None)
def _emit_new_channel_signal(self, object_path):
"""Generate new-channel GObject signal with channel object path
@@ -214,6 +222,18 @@ class Activity(gobject.GObject):
buddies.append(self._ps_new_object(item))
return buddies
+ def get_buddy_by_handle(self, handle):
+ """Retrieve the Buddy object given a telepathy handle.
+
+ buddy object paths are cached in self._handle_to_buddy_path,
+ so we can get the buddy without calling PS.
+ """
+ object_path = self._handle_to_buddy_path.get(handle, None)
+ if object_path:
+ buddy = self._ps_new_object(object_path)
+ return buddy
+ return None
+
def invite(self, buddy, message, response_cb):
"""Invite the given buddy to join this activity.
@@ -244,9 +264,13 @@ class Activity(gobject.GObject):
def get_channels(self):
"""Retrieve communications channel descriptions for the activity
- Returns (bus name, connection, channels) for the activity
-
- XXX what are those values?
+ Returns a tuple containing:
+ - the D-Bus well-known service name of the connection
+ (FIXME: this is redundant; in Telepathy it can be derived
+ from that of the connection)
+ - the D-Bus object path of the connection
+ - a list of D-Bus object paths representing the channels
+ associated with this activity
"""
(bus_name, connection, channels) = self._activity.GetChannels()
return bus_name, connection, channels
@@ -256,10 +280,8 @@ class Activity(gobject.GObject):
self.emit("joined", False, "left activity")
def _leave_error_cb(self, err):
- """Callback for error in async leaving of shared activity.
-
- XXX Add logging!"""
- pass
+ """Callback for error in async leaving of shared activity."""
+ _logger.debug('Failed to leave activity: %s', err)
def leave(self):
"""Leave this shared activity"""