From 1eb9932ab312ee0bd2f38585ae1caa0bc447dfd0 Mon Sep 17 00:00:00 2001 From: Marco Pesenti Gritti Date: Mon, 15 Oct 2007 21:48:17 +0000 Subject: Merge branch 'master' of git+ssh://dev.laptop.org/git/sugar --- (limited to 'sugar') 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""" -- cgit v0.9.1