Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDafydd Harries <daf@rhydd.org>2007-04-30 17:43:59 (GMT)
committer Dafydd Harries <daf@rhydd.org>2007-04-30 17:43:59 (GMT)
commit9a8d5ac32a3dc7692cd4d72bca7e88fc8381073a (patch)
treea5b6be6d02b98c9d4e78f1420b96cc1ddf692538
parentf6c5b63a589f923f2e7ea3f8f2f5c7f94db9981e (diff)
parentdc2cae382ca21dbad9df21e1ac28353c86a9287a (diff)
Merge branch 'master' of git://dev.laptop.org/sugar
-rw-r--r--services/presence/activity.py134
-rw-r--r--services/presence/buddy.py6
-rw-r--r--services/presence/presenceservice.py10
-rwxr-xr-xservices/presence/sugar-presence-service28
-rw-r--r--sugar/activity/activity.py25
-rw-r--r--sugar/graphics/Makefile.am2
-rw-r--r--sugar/graphics/panel.py23
-rw-r--r--sugar/graphics/toggletoolbutton.py28
-rw-r--r--sugar/graphics/toolbox.py1
-rwxr-xr-xtests/presence/test-ps-bindings.py2
10 files changed, 205 insertions, 54 deletions
diff --git a/services/presence/activity.py b/services/presence/activity.py
index e9c3c05..c856f54 100644
--- a/services/presence/activity.py
+++ b/services/presence/activity.py
@@ -29,6 +29,15 @@ class DBusGObjectMetaclass(dbus.service.InterfaceType, gobject.GObjectMeta): pas
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):
"""Represents a potentially shareable activity on the network.
"""
@@ -41,17 +50,21 @@ class Activity(DBusGObject):
}
__gproperties__ = {
- 'id' : (str, None, None, None,
- gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT_ONLY),
- 'name' : (str, None, None, None, gobject.PARAM_READWRITE),
- 'color' : (str, None, None, None, gobject.PARAM_READWRITE),
- 'type' : (str, None, None, None, gobject.PARAM_READWRITE),
- 'valid' : (bool, None, None, False, gobject.PARAM_READABLE),
- 'local' : (bool, None, None, False,
- gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT_ONLY),
- 'joined' : (bool, None, None, False, gobject.PARAM_READABLE)
+ _PROP_ID : (str, None, None, None,
+ gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT_ONLY),
+ _PROP_NAME : (str, None, None, None, gobject.PARAM_READWRITE),
+ _PROP_COLOR : (str, None, None, None, gobject.PARAM_READWRITE),
+ _PROP_TYPE : (str, None, None, None, gobject.PARAM_READWRITE),
+ _PROP_VALID : (bool, None, None, False, gobject.PARAM_READABLE),
+ _PROP_LOCAL : (bool, None, None, False,
+ gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT_ONLY),
+ _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):
"""Initializes the activity and sets its properties to default values.
@@ -85,11 +98,18 @@ class Activity(DBusGObject):
self._color = None
self._local = False
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")
- if not util.validate_activity_id(kwargs['id']):
- raise ValueError("Invalid activity id '%s'" % kwargs['id'])
+ if not util.validate_activity_id(kwargs[_PROP_ID]):
+ raise ValueError("Invalid activity id '%s'" % kwargs[_PROP_ID])
gobject.GObject.__init__(self, **kwargs)
if self.props.local and not self.props.valid:
@@ -107,19 +127,19 @@ class Activity(DBusGObject):
returns The value of the given property.
"""
- if pspec.name == "id":
+ if pspec.name == _PROP_ID:
return self._id
- elif pspec.name == "name":
+ elif pspec.name == _PROP_NAME:
return self._name
- elif pspec.name == "color":
+ elif pspec.name == _PROP_COLOR:
return self._color
- elif pspec.name == "type":
+ elif pspec.name == _PROP_TYPE:
return self._type
- elif pspec.name == "valid":
+ elif pspec.name == _PROP_VALID:
return self._valid
- elif pspec.name == "joined":
+ elif pspec.name == _PROP_JOINED:
return self._joined
- elif pspec.name == "local":
+ elif pspec.name == _PROP_LOCAL:
return self._local
def do_set_property(self, pspec, value):
@@ -132,20 +152,29 @@ class Activity(DBusGObject):
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
- elif pspec.name == "name":
+ elif pspec.name == _PROP_NAME:
self._name = value
- elif pspec.name == "color":
+ elif pspec.name == _PROP_COLOR:
self._color = value
- elif pspec.name == "type":
+ elif pspec.name == _PROP_TYPE:
if self._type:
raise RuntimeError("activity type is already set")
self._type = value
- elif pspec.name == "joined":
+ elif pspec.name == _PROP_JOINED:
self._joined = value
- elif pspec.name == "local":
+ elif pspec.name == _PROP_LOCAL:
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()
@@ -441,6 +470,11 @@ class Activity(DBusGObject):
props['name'] = self._name
props['color'] = self._color
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)
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
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
- do_set_property method, it *is* possible to change an already-set activity type
- to something else; this may be a bug.) Called by the PresenceService on the
- local machine.
+ a "validity-changed" signal being generated. Called by the PresenceService
+ on the local machine.
"""
changed = False
- if "name" in properties.keys():
- name = properties["name"]
+ # split reserved properties from activity-custom properties
+ (rprops, cprops) = self._split_properties(properties)
+ if _PROP_NAME in rprops.keys():
+ name = rprops[_PROP_NAME]
if name != self._name:
self._name = name
changed = True
- if "color" in properties.keys():
- color = properties["color"]
+ if _PROP_COLOR in rprops.keys():
+ color = rprops[_PROP_COLOR]
if color != self._color:
self._color = color
changed = True
- if "type" in properties.keys():
- type = properties["type"]
- if type != self._type:
- self._type = type
- changed = True
+ if _PROP_TYPE in rprops.keys():
+ type = rprops[_PROP_TYPE]
+ # Type can never be changed after first set
+ if self._type:
+ 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:
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)
diff --git a/services/presence/buddy.py b/services/presence/buddy.py
index 25bdb69..ca3aff2 100644
--- a/services/presence/buddy.py
+++ b/services/presence/buddy.py
@@ -560,7 +560,7 @@ class TestOwner(GenericOwner):
__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._section = "Info"
self._test_activities = []
@@ -588,7 +588,9 @@ class TestOwner(GenericOwner):
GenericOwner.__init__(self, ps, bus_name, object_id, key=pubkey, nick=nick,
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):
activity = self._ps.internal_get_activity(actid)
diff --git a/services/presence/presenceservice.py b/services/presence/presenceservice.py
index d90eb56..46ac1a2 100644
--- a/services/presence/presenceservice.py
+++ b/services/presence/presenceservice.py
@@ -51,7 +51,7 @@ class PresenceService(DBusGObject):
([gobject.TYPE_BOOLEAN]))
}
- def __init__(self, test=0):
+ def __init__(self, test_num=0, randomize=False):
self._next_object_id = 0
self._connected = False
@@ -66,8 +66,8 @@ class PresenceService(DBusGObject):
# Create the Owner object
objid = self._get_next_object_id()
- if test > 0:
- self._owner = TestOwner(self, self._bus_name, objid, test)
+ if test_num > 0:
+ self._owner = TestOwner(self, self._bus_name, objid, test_num, randomize)
else:
self._owner = ShellOwner(self, self._bus_name, objid)
self._buddies[self._owner.props.key] = self._owner
@@ -357,9 +357,9 @@ class PresenceService(DBusGObject):
return self._activities[actid]
-def main(test=False):
+def main(test_num=0, randomize=False):
loop = gobject.MainLoop()
- ps = PresenceService(test)
+ ps = PresenceService(test_num, randomize)
try:
loop.run()
except KeyboardInterrupt:
diff --git a/services/presence/sugar-presence-service b/services/presence/sugar-presence-service
index 7eec696..1680fea 100755
--- a/services/presence/sugar-presence-service
+++ b/services/presence/sugar-presence-service
@@ -24,24 +24,36 @@ import os
from sugar import logger
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'))
-test=0
-if len(sys.argv) > 1:
+test_num = 0
+randomize = False
+if len(sys.argv) in [2, 3]:
try:
- test = int(sys.argv[1])
+ test_num = int(sys.argv[1])
except ValueError:
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.")
-if test > 0:
- logger.start('test-%d-presenceservice' % test)
+ if len(sys.argv) == 3 and sys.argv[2] == "randomize":
+ 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:
logger.start('presenceservice')
import presenceservice
-logging.info('Starting presence service')
+logging.info('Starting presence service...')
-presenceservice.main(test)
+presenceservice.main(test_num, randomize)
diff --git a/sugar/activity/activity.py b/sugar/activity/activity.py
index fa5b888..a859810 100644
--- a/sugar/activity/activity.py
+++ b/sugar/activity/activity.py
@@ -64,6 +64,31 @@ class ActivityToolbar(gtk.Toolbar):
def _activity_shared_cb(self, activity):
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):
def __init__(self, activity):
Toolbox.__init__(self)
diff --git a/sugar/graphics/Makefile.am b/sugar/graphics/Makefile.am
index 6756aa9..eb4b379 100644
--- a/sugar/graphics/Makefile.am
+++ b/sugar/graphics/Makefile.am
@@ -2,6 +2,7 @@ sugardir = $(pythondir)/sugar/graphics
sugar_PYTHON = \
__init__.py \
animator.py \
+ icon.py \
iconbutton.py \
canvasicon.py \
color.py \
@@ -11,6 +12,7 @@ sugar_PYTHON = \
menu.py \
menushell.py \
roundbox.py \
+ panel.py \
popup.py \
popupcontext.py \
snowflakebox.py \
diff --git a/sugar/graphics/panel.py b/sugar/graphics/panel.py
new file mode 100644
index 0000000..bf3ed24
--- /dev/null
+++ b/sugar/graphics/panel.py
@@ -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)
diff --git a/sugar/graphics/toggletoolbutton.py b/sugar/graphics/toggletoolbutton.py
new file mode 100644
index 0000000..09ec0ef
--- /dev/null
+++ b/sugar/graphics/toggletoolbutton.py
@@ -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()
diff --git a/sugar/graphics/toolbox.py b/sugar/graphics/toolbox.py
index 441d157..6dd805f 100644
--- a/sugar/graphics/toolbox.py
+++ b/sugar/graphics/toolbox.py
@@ -26,6 +26,7 @@ class Toolbox(gtk.VBox):
gtk.VBox.__init__(self)
self._notebook = gtk.Notebook()
+ self._notebook.set_name('sugar-toolbox-notebook')
self._notebook.set_tab_pos(gtk.POS_BOTTOM)
self._notebook.set_show_border(False)
self.pack_start(self._notebook)
diff --git a/tests/presence/test-ps-bindings.py b/tests/presence/test-ps-bindings.py
index 8da94a1..ccf6617 100755
--- a/tests/presence/test-ps-bindings.py
+++ b/tests/presence/test-ps-bindings.py
@@ -24,7 +24,7 @@ from sugar.presence import presenceservice
import mockps
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)
# Wait until it shows up on the bus