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

This commit is contained in:
Dafydd Harries 2007-04-30 18:43:59 +01:00
commit 9a8d5ac32a
10 changed files with 205 additions and 54 deletions

View File

@ -29,6 +29,15 @@ class DBusGObjectMetaclass(dbus.service.InterfaceType, gobject.GObjectMeta): pas
class DBusGObject(dbus.service.Object, gobject.GObject): __metaclass__ = DBusGObjectMetaclass class DBusGObject(dbus.service.Object, gobject.GObject): __metaclass__ = DBusGObjectMetaclass
_PROP_ID = "id"
_PROP_NAME = "name"
_PROP_COLOR = "color"
_PROP_TYPE = "type"
_PROP_VALID = "valid"
_PROP_LOCAL = "local"
_PROP_JOINED = "joined"
_PROP_CUSTOM_PROPS = "custom-props"
class Activity(DBusGObject): class Activity(DBusGObject):
"""Represents a potentially shareable activity on the network. """Represents a potentially shareable activity on the network.
""" """
@ -41,17 +50,21 @@ class Activity(DBusGObject):
} }
__gproperties__ = { __gproperties__ = {
'id' : (str, None, None, None, _PROP_ID : (str, None, None, None,
gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT_ONLY), gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT_ONLY),
'name' : (str, None, None, None, gobject.PARAM_READWRITE), _PROP_NAME : (str, None, None, None, gobject.PARAM_READWRITE),
'color' : (str, None, None, None, gobject.PARAM_READWRITE), _PROP_COLOR : (str, None, None, None, gobject.PARAM_READWRITE),
'type' : (str, None, None, None, gobject.PARAM_READWRITE), _PROP_TYPE : (str, None, None, None, gobject.PARAM_READWRITE),
'valid' : (bool, None, None, False, gobject.PARAM_READABLE), _PROP_VALID : (bool, None, None, False, gobject.PARAM_READABLE),
'local' : (bool, None, None, False, _PROP_LOCAL : (bool, None, None, False,
gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT_ONLY), gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT_ONLY),
'joined' : (bool, None, None, False, gobject.PARAM_READABLE) _PROP_JOINED : (bool, None, None, False, gobject.PARAM_READABLE),
_PROP_CUSTOM_PROPS : (object, None, None,
gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT_ONLY)
} }
_RESERVED_PROPNAMES = __gproperties__.keys()
def __init__(self, bus_name, object_id, tp, **kwargs): def __init__(self, bus_name, object_id, tp, **kwargs):
"""Initializes the activity and sets its properties to default values. """Initializes the activity and sets its properties to default values.
@ -85,11 +98,18 @@ class Activity(DBusGObject):
self._color = None self._color = None
self._local = False self._local = False
self._type = None self._type = None
self._custom_props = {}
if not kwargs.get("id"): # ensure no reserved property names are in custom properties
if kwargs.get(_PROP_CUSTOM_PROPS):
(rprops, cprops) = self._split_properties(kwargs.get(_PROP_CUSTOM_PROPS))
if len(rprops.keys()) > 0:
raise ValueError("Cannot use reserved property names '%s'" % ", ".join(rprops.keys()))
if not kwargs.get(_PROP_ID):
raise ValueError("activity id is required") raise ValueError("activity id is required")
if not util.validate_activity_id(kwargs['id']): if not util.validate_activity_id(kwargs[_PROP_ID]):
raise ValueError("Invalid activity id '%s'" % kwargs['id']) raise ValueError("Invalid activity id '%s'" % kwargs[_PROP_ID])
gobject.GObject.__init__(self, **kwargs) gobject.GObject.__init__(self, **kwargs)
if self.props.local and not self.props.valid: if self.props.local and not self.props.valid:
@ -107,19 +127,19 @@ class Activity(DBusGObject):
returns The value of the given property. returns The value of the given property.
""" """
if pspec.name == "id": if pspec.name == _PROP_ID:
return self._id return self._id
elif pspec.name == "name": elif pspec.name == _PROP_NAME:
return self._name return self._name
elif pspec.name == "color": elif pspec.name == _PROP_COLOR:
return self._color return self._color
elif pspec.name == "type": elif pspec.name == _PROP_TYPE:
return self._type return self._type
elif pspec.name == "valid": elif pspec.name == _PROP_VALID:
return self._valid return self._valid
elif pspec.name == "joined": elif pspec.name == _PROP_JOINED:
return self._joined return self._joined
elif pspec.name == "local": elif pspec.name == _PROP_LOCAL:
return self._local return self._local
def do_set_property(self, pspec, value): def do_set_property(self, pspec, value):
@ -132,20 +152,29 @@ class Activity(DBusGObject):
to something different later will raise a RuntimeError. to something different later will raise a RuntimeError.
""" """
if pspec.name == "id": if pspec.name == _PROP_ID:
if self._id:
raise RuntimeError("activity ID is already set")
self._id = value self._id = value
elif pspec.name == "name": elif pspec.name == _PROP_NAME:
self._name = value self._name = value
elif pspec.name == "color": elif pspec.name == _PROP_COLOR:
self._color = value self._color = value
elif pspec.name == "type": elif pspec.name == _PROP_TYPE:
if self._type: if self._type:
raise RuntimeError("activity type is already set") raise RuntimeError("activity type is already set")
self._type = value self._type = value
elif pspec.name == "joined": elif pspec.name == _PROP_JOINED:
self._joined = value self._joined = value
elif pspec.name == "local": elif pspec.name == _PROP_LOCAL:
self._local = value self._local = value
elif pspec.name == _PROP_CUSTOM_PROPS:
if not value:
value = {}
(rprops, cprops) = self._split_properties(value)
self._custom_props = {}
for (key, dvalue) in cprops.items():
self._custom_props[str(key)] = str(dvalue)
self._update_validity() self._update_validity()
@ -441,6 +470,11 @@ class Activity(DBusGObject):
props['name'] = self._name props['name'] = self._name
props['color'] = self._color props['color'] = self._color
props['type'] = self._type props['type'] = self._type
# Add custom properties
for (key, value) in self._custom_props.items():
props[key] = value
self._tp.set_activity_properties(self.props.id, props) self._tp.set_activity_properties(self.props.id, props)
def set_properties(self, properties): def set_properties(self, properties):
@ -450,29 +484,53 @@ class Activity(DBusGObject):
Note that if any of the name, colour and/or type property values is changed from Note that if any of the name, colour and/or type property values is changed from
what it originally was, the update_validity method will be called, resulting in what it originally was, the update_validity method will be called, resulting in
a "validity-changed" signal being generated. (Also note that unlike with the a "validity-changed" signal being generated. Called by the PresenceService
do_set_property method, it *is* possible to change an already-set activity type on the local machine.
to something else; this may be a bug.) Called by the PresenceService on the
local machine.
""" """
changed = False changed = False
if "name" in properties.keys(): # split reserved properties from activity-custom properties
name = properties["name"] (rprops, cprops) = self._split_properties(properties)
if _PROP_NAME in rprops.keys():
name = rprops[_PROP_NAME]
if name != self._name: if name != self._name:
self._name = name self._name = name
changed = True changed = True
if "color" in properties.keys(): if _PROP_COLOR in rprops.keys():
color = properties["color"] color = rprops[_PROP_COLOR]
if color != self._color: if color != self._color:
self._color = color self._color = color
changed = True changed = True
if "type" in properties.keys(): if _PROP_TYPE in rprops.keys():
type = properties["type"] type = rprops[_PROP_TYPE]
if type != self._type: # Type can never be changed after first set
self._type = type if self._type:
changed = True logging.debug("Activity type changed by network; this is illegal")
else:
if type != self._type:
self._type = type
changed = True
# Set custom properties
if len(cprops.keys()) > 0:
self.props.custom_props = cprops
if changed: if changed:
self._update_validity() self._update_validity()
def _split_properties(self, properties):
"""Extracts reserved properties.
properties - Dictionary object containing properties keyed by property names
returns a tuple of 2 dictionaries, reserved properties and custom properties
"""
rprops = {}
cprops = {}
for (key, value) in properties.items():
if key in self._RESERVED_PROPNAMES:
rprops[key] = value
else:
cprops[key] = value
return (rprops, cprops)

View File

@ -560,7 +560,7 @@ class TestOwner(GenericOwner):
__gtype_name__ = "TestOwner" __gtype_name__ = "TestOwner"
def __init__(self, ps, bus_name, object_id, test_num): def __init__(self, ps, bus_name, object_id, test_num, randomize):
self._cp = ConfigParser() self._cp = ConfigParser()
self._section = "Info" self._section = "Info"
self._test_activities = [] self._test_activities = []
@ -588,7 +588,9 @@ class TestOwner(GenericOwner):
GenericOwner.__init__(self, ps, bus_name, object_id, key=pubkey, nick=nick, GenericOwner.__init__(self, ps, bus_name, object_id, key=pubkey, nick=nick,
color=color, icon=icon, registered=registered, key_hash=privkey_hash) color=color, icon=icon, registered=registered, key_hash=privkey_hash)
self._ps.connect('connection-status', self._ps_connection_status_cb) # Only do the random stuff if randomize is true
if randomize:
self._ps.connect('connection-status', self._ps_connection_status_cb)
def _share_reply_cb(self, actid, object_path): def _share_reply_cb(self, actid, object_path):
activity = self._ps.internal_get_activity(actid) activity = self._ps.internal_get_activity(actid)

View File

@ -51,7 +51,7 @@ class PresenceService(DBusGObject):
([gobject.TYPE_BOOLEAN])) ([gobject.TYPE_BOOLEAN]))
} }
def __init__(self, test=0): def __init__(self, test_num=0, randomize=False):
self._next_object_id = 0 self._next_object_id = 0
self._connected = False self._connected = False
@ -66,8 +66,8 @@ class PresenceService(DBusGObject):
# Create the Owner object # Create the Owner object
objid = self._get_next_object_id() objid = self._get_next_object_id()
if test > 0: if test_num > 0:
self._owner = TestOwner(self, self._bus_name, objid, test) self._owner = TestOwner(self, self._bus_name, objid, test_num, randomize)
else: else:
self._owner = ShellOwner(self, self._bus_name, objid) self._owner = ShellOwner(self, self._bus_name, objid)
self._buddies[self._owner.props.key] = self._owner self._buddies[self._owner.props.key] = self._owner
@ -357,9 +357,9 @@ class PresenceService(DBusGObject):
return self._activities[actid] return self._activities[actid]
def main(test=False): def main(test_num=0, randomize=False):
loop = gobject.MainLoop() loop = gobject.MainLoop()
ps = PresenceService(test) ps = PresenceService(test_num, randomize)
try: try:
loop.run() loop.run()
except KeyboardInterrupt: except KeyboardInterrupt:

View File

@ -24,24 +24,36 @@ import os
from sugar import logger from sugar import logger
from sugar import env from sugar import env
def usage():
logging.debug("Usage: sugar-presence-service [<test buddy number (1 - 10)>] [randomize]")
sys.path.append(env.get_service_path('presence')) sys.path.append(env.get_service_path('presence'))
test=0 test_num = 0
if len(sys.argv) > 1: randomize = False
if len(sys.argv) in [2, 3]:
try: try:
test = int(sys.argv[1]) test_num = int(sys.argv[1])
except ValueError: except ValueError:
logging.debug("Bad test user number.") logging.debug("Bad test user number.")
if test < 1 or test > 10: if test_num < 1 or test_num > 10:
logging.debug("Bad test user number.") logging.debug("Bad test user number.")
if test > 0: if len(sys.argv) == 3 and sys.argv[2] == "randomize":
logger.start('test-%d-presenceservice' % test) randomize = True
elif len(sys.argv) == 1:
pass
else:
usage()
os._exit(1)
if test_num > 0:
logger.start('test-%d-presenceservice' % test_num)
else: else:
logger.start('presenceservice') logger.start('presenceservice')
import presenceservice import presenceservice
logging.info('Starting presence service') logging.info('Starting presence service...')
presenceservice.main(test) presenceservice.main(test_num, randomize)

View File

@ -64,6 +64,31 @@ class ActivityToolbar(gtk.Toolbar):
def _activity_shared_cb(self, activity): def _activity_shared_cb(self, activity):
self._share_button.set_sensitive(False) self._share_button.set_sensitive(False)
class EditToolbar(gtk.Toolbar):
def __init__(self):
gtk.Toolbar.__init__(self)
self.undo = ToolButton('edit-undo')
self.insert(self.undo, -1)
self.undo.show()
self.redo = ToolButton('edit-redo')
self.insert(self.redo, -1)
self.redo.show()
separator = gtk.SeparatorToolItem()
separator.set_draw(True)
self.insert(separator, -1)
separator.show()
self.copy = ToolButton('edit-copy')
self.insert(self.copy, -1)
self.copy.show()
self.paste = ToolButton('edit-paste')
self.insert(self.paste, -1)
self.paste.show()
class ActivityToolbox(Toolbox): class ActivityToolbox(Toolbox):
def __init__(self, activity): def __init__(self, activity):
Toolbox.__init__(self) Toolbox.__init__(self)

View File

@ -2,6 +2,7 @@ sugardir = $(pythondir)/sugar/graphics
sugar_PYTHON = \ sugar_PYTHON = \
__init__.py \ __init__.py \
animator.py \ animator.py \
icon.py \
iconbutton.py \ iconbutton.py \
canvasicon.py \ canvasicon.py \
color.py \ color.py \
@ -11,6 +12,7 @@ sugar_PYTHON = \
menu.py \ menu.py \
menushell.py \ menushell.py \
roundbox.py \ roundbox.py \
panel.py \
popup.py \ popup.py \
popupcontext.py \ popupcontext.py \
snowflakebox.py \ snowflakebox.py \

23
sugar/graphics/panel.py Normal file
View File

@ -0,0 +1,23 @@
# Copyright (C) 2007, Red Hat, Inc.
#
# 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.
import gtk
class Panel(gtk.VBox):
__gtype_name__ = 'SugarPanel'
def __init__(self):
gtk.VBox.__init__(self)

View File

@ -0,0 +1,28 @@
# Copyright (C) 2007, Red Hat, Inc.
#
# 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.
import gtk
from sugar.graphics.icon import Icon
class ToggleToolButton(gtk.ToggleToolButton):
def __init__(self, icon_resource=None):
gtk.ToggleToolButton.__init__(self)
icon = Icon(icon_resource)
self.set_icon_widget(icon)
icon.show()

View File

@ -26,6 +26,7 @@ class Toolbox(gtk.VBox):
gtk.VBox.__init__(self) gtk.VBox.__init__(self)
self._notebook = gtk.Notebook() self._notebook = gtk.Notebook()
self._notebook.set_name('sugar-toolbox-notebook')
self._notebook.set_tab_pos(gtk.POS_BOTTOM) self._notebook.set_tab_pos(gtk.POS_BOTTOM)
self._notebook.set_show_border(False) self._notebook.set_show_border(False)
self.pack_start(self._notebook) self.pack_start(self._notebook)

View File

@ -24,7 +24,7 @@ from sugar.presence import presenceservice
import mockps import mockps
def start_ps(): def start_ps():
argv = ["mockps.py", "mockps.py"] argv = ["mockps.py"]
(pid, stdin, stdout, stderr) = gobject.spawn_async(argv, flags=gobject.SPAWN_LEAVE_DESCRIPTORS_OPEN) (pid, stdin, stdout, stderr) = gobject.spawn_async(argv, flags=gobject.SPAWN_LEAVE_DESCRIPTORS_OPEN)
# Wait until it shows up on the bus # Wait until it shows up on the bus