Merge branch 'master' of git+ssh://dev.laptop.org/git/sugar

This commit is contained in:
Marco Pesenti Gritti 2007-10-15 23:48:17 +02:00
commit 1eb9932ab3
3 changed files with 122 additions and 20 deletions

2
NEWS
View File

@ -1,3 +1,5 @@
Added TimeoutAlert (erikos)
Snapshot 68ff71a0cb Snapshot 68ff71a0cb
Snapshot 29bc0a8a20 Snapshot 29bc0a8a20

View File

@ -1,7 +1,26 @@
# 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 _ from gettext import gettext as _
import gtk import gtk
import gobject import gobject
import hippo
import math
from sugar.graphics import style from sugar.graphics import style
from sugar.graphics.icon import Icon from sugar.graphics.icon import Icon
@ -28,7 +47,7 @@ class Alert(gtk.EventBox, gobject.GObject):
__gsignals__ = { __gsignals__ = {
'response': (gobject.SIGNAL_RUN_FIRST, 'response': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, ([int])) gobject.TYPE_NONE, ([object]))
} }
__gproperties__ = { __gproperties__ = {
@ -69,7 +88,8 @@ class Alert(gtk.EventBox, gobject.GObject):
self._hbox.pack_start(self._msg_box) self._hbox.pack_start(self._msg_box)
self._buttons_box = gtk.HButtonBox() 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._hbox.pack_start(self._buttons_box)
self._buttons_box.show() self._buttons_box.show()
@ -99,16 +119,19 @@ class Alert(gtk.EventBox, gobject.GObject):
elif pspec.name == 'msg': elif pspec.name == 'msg':
return self._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 """Add a button to the alert
response_id: will be emitted with the response signal 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 label: that will occure right to the buttom
icon: this can be a SugarIcon or a gtk.Image icon: this can be a SugarIcon or a gtk.Image
position: the position of the button in the box (optional) position: the position of the button in the box (optional)
""" """
button = gtk.Button() button = gtk.Button()
self._buttons[response_id] = button self._buttons[response_id] = button
if icon is not None:
button.set_image(icon) button.set_image(icon)
button.set_label(label) button.set_label(label)
self._buttons_box.pack_start(button) self._buttons_box.pack_start(button)
@ -142,11 +165,66 @@ class ConfirmationAlert(Alert):
Alert.__init__(self, **kwargs) Alert.__init__(self, **kwargs)
icon = Icon(icon_name='dialog-cancel') 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.show()
icon = Icon(icon_name='dialog-ok') 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() 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

View File

@ -26,9 +26,8 @@ _logger = logging.getLogger('sugar.presence.activity')
class Activity(gobject.GObject): class Activity(gobject.GObject):
"""UI interface for an Activity in the presence service """UI interface for an Activity in the presence service
Activities in the presence service represent other user's Activities in the presence service represent your and other user's
shared activities and your own activities (XXX shared or shared activities.
otherwise?)
Properties: Properties:
id id
@ -69,8 +68,10 @@ class Activity(gobject.GObject):
self._ps_del_object = del_obj_cb self._ps_del_object = del_obj_cb
bobj = bus.get_object(self._PRESENCE_SERVICE, object_path) bobj = bus.get_object(self._PRESENCE_SERVICE, object_path)
self._activity = dbus.Interface(bobj, self._ACTIVITY_DBUS_INTERFACE) self._activity = dbus.Interface(bobj, self._ACTIVITY_DBUS_INTERFACE)
self._activity.connect_to_signal('BuddyJoined', self._buddy_joined_cb) self._activity.connect_to_signal('BuddyHandleJoined',
self._activity.connect_to_signal('BuddyLeft', self._buddy_left_cb) 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('NewChannel', self._new_channel_cb)
self._activity.connect_to_signal('PropertiesChanged', self._activity.connect_to_signal('PropertiesChanged',
self._properties_changed_cb, self._properties_changed_cb,
@ -90,6 +91,9 @@ class Activity(gobject.GObject):
self._tags = None self._tags = None
self._private = True self._private = True
self._joined = False 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): def _get_properties_reply_cb(self, new_props):
self._properties_changed_cb(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)) self.emit('buddy-joined', self._ps_new_object(object_path))
return False 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) 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): def _emit_buddy_left_signal(self, object_path):
"""Generate buddy-left GObject signal with presence Buddy object """Generate buddy-left GObject signal with presence Buddy object
@ -191,6 +197,8 @@ class Activity(gobject.GObject):
def _buddy_left_cb(self, object_path): def _buddy_left_cb(self, object_path):
gobject.idle_add(self._emit_buddy_left_signal, 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): def _emit_new_channel_signal(self, object_path):
"""Generate new-channel GObject signal with channel 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)) buddies.append(self._ps_new_object(item))
return buddies 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): def invite(self, buddy, message, response_cb):
"""Invite the given buddy to join this activity. """Invite the given buddy to join this activity.
@ -244,9 +264,13 @@ class Activity(gobject.GObject):
def get_channels(self): def get_channels(self):
"""Retrieve communications channel descriptions for the activity """Retrieve communications channel descriptions for the activity
Returns (bus name, connection, channels) for the activity Returns a tuple containing:
- the D-Bus well-known service name of the connection
XXX what are those values? (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() (bus_name, connection, channels) = self._activity.GetChannels()
return bus_name, connection, channels return bus_name, connection, channels
@ -256,10 +280,8 @@ class Activity(gobject.GObject):
self.emit("joined", False, "left activity") self.emit("joined", False, "left activity")
def _leave_error_cb(self, err): def _leave_error_cb(self, err):
"""Callback for error in async leaving of shared activity. """Callback for error in async leaving of shared activity."""
_logger.debug('Failed to leave activity: %s', err)
XXX Add logging!"""
pass
def leave(self): def leave(self):
"""Leave this shared activity""" """Leave this shared activity"""