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

This commit is contained in:
John (J5) Palmieri 2007-08-27 15:51:55 -04:00
commit f5f95f4d7b
46 changed files with 973 additions and 708 deletions

1
NEWS
View File

@ -1,3 +1,4 @@
* Update arabic translation. (khaled)
* Restore Icon's ability to load absolute file paths. (tomeu)
* #722 Show "charging" badge on battery. (danw)
* #2010 Remember state when scrubbing. (marco)

View File

@ -3,4 +3,8 @@
export SUGAR_PREFIX=@prefix@
export SUGAR_PATH=@prefix@/share/sugar
export GTK2_RC_FILES=@prefix@/share/sugar/data/sugar-xo.gtkrc
dbus-launch --exit-with-session sugar-shell
if [ -f /etc/olpc-security ] ; then
dbus-launch --exit-with-session --config-file=/etc/dbus-1/session-olpc.conf sugar-shell
else
dbus-launch --exit-with-session sugar-shell
fi

153
po/ar.po
View File

@ -7,82 +7,155 @@ msgid ""
msgstr ""
"Project-Id-Version: olpc-sugar.master\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-06-28 10:44-0700\n"
"PO-Revision-Date: 2007-06-28 21:36+0300\n"
"POT-Creation-Date: 2007-08-13 17:41-0700\n"
"PO-Revision-Date: 2007-08-16 00:17+0300\n"
"Last-Translator: Khaled Hosny <khaledhosny@eglug.org>\n"
"Language-Team: Arabic <doc@arabeyes.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: KBabel 1.11.4\n"
"Plural-Forms: nplurals=4; plural=n==1 ? 0 : n==2 ? 1 : n>=3 && n<=10 ? 2 : 3\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\nnplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
#: ../shell/intro/intro.py:77
msgid "Pick a buddy picture"
msgstr "اختر صورة صاحب"
#: ../shell/intro/intro.py:63
msgid "Name:"
msgstr "الاسم:"
#: ../shell/intro/intro.py:100
msgid "My Picture:"
msgstr "صورتي:"
#: ../shell/intro/intro.py:93
msgid "Click to change color:"
msgstr "انقر لتغيير اللون:"
#: ../shell/intro/intro.py:180
msgid "My Name:"
msgstr "اسمي:"
#: ../shell/intro/intro.py:147
msgid "Back"
msgstr "السابق"
#: ../shell/intro/intro.py:204
msgid "My Color:"
msgstr "لوني:"
#: ../shell/intro/intro.py:155
msgid "Done"
msgstr "تمّ"
#: ../shell/intro/intro.py:158
msgid "Next"
msgstr "التالي"
#: ../shell/view/BuddyMenu.py:83
msgid "Remove friend"
msgstr "أزل صديق"
#: ../shell/view/BuddyMenu.py:87
#: ../shell/view/BuddyMenu.py:86
msgid "Make friend"
msgstr "اصنع صديق"
#: ../shell/view/BuddyMenu.py:97
#. FIXME check that the buddy is not in the activity already
#: ../shell/view/BuddyMenu.py:98
msgid "Invite"
msgstr "ادعُ"
#: ../shell/view/clipboardmenu.py:103
#: ../shell/view/clipboardmenu.py:65
msgid "Remove"
msgstr "أزل"
#: ../shell/view/clipboardmenu.py:110
#: ../shell/view/clipboardmenu.py:70
msgid "Open"
msgstr "افتح"
#: ../shell/view/clipboardmenu.py:117
msgid "Stop download"
msgstr "أوقف التنزيل"
#: ../shell/view/clipboardmenu.py:124
#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
#. TODO: Implement stopping downloads
#. self._stop_item.connect('activate', self._stop_item_activate_cb)
#. self.append_menu_item(self._stop_item)
#: ../shell/view/clipboardmenu.py:80
msgid "Add to journal"
msgstr "أضف جرنال"
msgstr "أضف يوميّة"
#: ../services/clipboard/objecttypeservice.py:32
msgid "Text"
msgstr "نص"
#: ../services/clipboard/objecttypeservice.py:35
msgid "Image"
msgstr "صورة"
#: ../shell/view/Shell.py:227
msgid "Screenshot"
msgstr "لقطة شاشة"
#: ../shell/view/clipboardicon.py:211
#: ../shell/view/clipboardmenu.py:158
#, python-format
msgid "Clipboard object: %s."
msgstr "عنصر الحافظة: %s."
#: ../shell/view/home/MeshBox.py:122
#: ../shell/view/frame/zoombox.py:39
msgid "Neighborhood"
msgstr "الجِوَار"
#: ../shell/view/frame/zoombox.py:50
msgid "Group"
msgstr "مجموعة"
#: ../shell/view/frame/zoombox.py:61
msgid "Home"
msgstr "منزل"
#: ../shell/view/frame/zoombox.py:72
msgid "Activity"
msgstr "النشاط"
#: ../services/shell/objecttypeservice.py:32
msgid "Text"
msgstr "نص"
#: ../services/shell/objecttypeservice.py:36
msgid "Image"
msgstr "صورة"
#: ../shell/hardware/keydialog.py:113
msgid "Authentication Type:"
msgstr "نوع الاستيثاق:"
#: ../shell/hardware/keydialog.py:158
msgid "Encryption Type:"
msgstr "نوع التعمية:"
#: ../shell/view/home/activitiesdonut.py:75
msgid "Starting..."
msgstr "يبدأ..."
#: ../shell/view/home/activitiesdonut.py:89
msgid "Resume"
msgstr "استكمل"
#: ../shell/view/home/activitiesdonut.py:96 ../sugar/activity/activity.py:89
msgid "Stop"
msgstr "قف"
#: ../shell/view/Shell.py:214
msgid "Screenshot"
msgstr "لقطة شاشة"
#: ../shell/view/home/HomeBox.py:131
msgid "Shutdown"
msgstr "أطفيء"
#: ../shell/view/home/MeshBox.py:126
msgid "Mesh Network"
msgstr "شبكة عُروِيّة"
#: ../sugar/activity/activity.py:232
#: ../shell/view/devices/battery.py:34
msgid "My Battery life"
msgstr "عمر بطاريتي"
#: ../shell/view/devices/battery.py:87
msgid "Battery charging"
msgstr "شحن البطاريّة"
#: ../shell/view/devices/battery.py:89
msgid "Battery discharging"
msgstr "تفريغ البطاريّة"
#: ../shell/view/devices/battery.py:91
msgid "Battery fully charged"
msgstr "البطارية مشحونة بالكامل"
#: ../sugar/activity/activity.py:73
msgid "Private"
msgstr "خاص"
#: ../sugar/activity/activity.py:75
msgid "My Neighborhood"
msgstr "جِوارِي"
#: ../sugar/activity/activity.py:83
msgid "Keep"
msgstr "ابقِ"
#: ../sugar/activity/activity.py:262
#, python-format
msgid "%s Activity"
msgstr "نشاط %s"

View File

@ -1,13 +1,9 @@
#!/bin/sh
TODO="C0111,C0301,C0322,W0311,C0324,W0331,W0212,W0611,W0613,W0201,W0106,W0622,W0403,W0612,W0102,W0404,W0704,W0402,W0702,W0401,E0602,E1111,W0101,W0105,W0601,W0602,W0703,W0701,W0312,W0231,W0233"
TODO="C0111,C0301,C0322,W0311,C0324,W0331,W0212,W0611,W0613,W0201,W0106,W0622,W0403,W0102,W0404,W0704,W0402,W0702,W0401,E0602,E1102,C0321,E0611,E1103,W1001,E0213,W0107,R0921,R0401,E1111,W0101,W0105,W0601,W0602,W0703,W0701,W0312,W0231,W0233,F0401,W0612"
BROKEN="C0103,E1101"
DISABLE="W0142,R0913,W0621,R0903,R0201,R0904,W0511,W0232,R0902,W0603,R0914,C0302,C0102,I0011,R0911,R0912,R0901,R0801,R0923,R0915"
PYTHONPATH=.:./shell:$SUGAR_PREFIX/lib/python2.4/site-packages/gtk-2.0:$PYTHONPATH \
pylint \
--include-ids=y \
--disable-msg=$TODO,$BROKEN,$DISABLE \
shell sugar
pylint --include-ids=y --disable-msg=$TODO,$BROKEN,$DISABLE shell sugar

View File

@ -30,27 +30,27 @@ class ObjectTypeRegistry(dbus.service.Object):
self._types = {}
self._add_primitive('Text', _('Text'), 'theme:text-x-generic',
self._add_primitive('Text', _('Text'), 'text-x-generic',
['text/plain', 'text/rtf', 'application/pdf',
'application/x-pdf', 'text/html',
'application/vnd.oasis.opendocument.text',
'application/rtf', 'text/rtf'])
self._add_primitive('Image', _('Image'), 'theme:image-x-generic',
self._add_primitive('Image', _('Image'), 'image-x-generic',
['image/png', 'image/gif', 'image/jpeg'])
self._add_primitive('Audio', _('Audio'), 'theme:audio-x-generic',
self._add_primitive('Audio', _('Audio'), 'audio-x-generic',
['audio/ogg'])
self._add_primitive('Video', _('Video'), 'theme:video-x-generic',
self._add_primitive('Video', _('Video'), 'video-x-generic',
['video/ogg', 'application/ogg'])
self._add_primitive('Etoys project', _('Etoys project'),
'theme:application-x-squeak-project',
'application-x-squeak-project',
['application/x-squeak-project'])
self._add_primitive('Link', _('Link'),
'theme:text-uri-list',
'text-uri-list',
['text/x-moz-url', 'text/uri-list'])
def _add_primitive(self, type_id, name, icon, mime_types):

View File

@ -16,7 +16,7 @@
import hippo
from sugar.graphics.canvasicon import CanvasIcon
from sugar.graphics.icon import CanvasIcon
from sugar.graphics import style
from sugar.graphics.xocolor import XoColor
@ -26,7 +26,7 @@ class ColorPicker(hippo.CanvasBox, hippo.CanvasItem):
self.props.orientation = hippo.ORIENTATION_HORIZONTAL
self._xo = CanvasIcon(size=style.XLARGE_ICON_SIZE,
icon_name='theme:computer-xo')
icon_name='computer-xo')
self._set_random_colors()
self._xo.connect('activated', self._xo_activated_cb)
self.append(self._xo)

View File

@ -26,8 +26,8 @@ import logging
from sugar import env
from sugar.graphics import style
from sugar.graphics.canvasbutton import CanvasButton
from sugar.graphics.canvasentry import CanvasEntry
from sugar.graphics.button import CanvasButton
from sugar.graphics.entry import CanvasEntry
import colorpicker

View File

@ -103,7 +103,7 @@ class HomeActivity(gobject.GObject):
if self._activity_info:
return self._activity_info.icon
else:
return 'theme:image-missing'
return 'image-missing'
def get_icon_color(self):
"""Retrieve the appropriate icon colour for this activity

View File

@ -16,6 +16,7 @@
"""D-bus service providing access to the shell's functionality"""
import dbus
import os
_DBUS_SERVICE = "org.laptop.Shell"
_DBUS_SHELL_IFACE = "org.laptop.Shell"
@ -40,6 +41,9 @@ class ShellService(dbus.service.Object):
XXX At the moment the d-bus service methods do not appear to do
anything other than add_bundle
"""
_rainbow = None
def __init__(self, shell):
self._shell = shell
self._shell_model = shell.get_model()
@ -98,9 +102,20 @@ class ShellService(dbus.service.Object):
def _owner_icon_changed_cb(self, new_icon):
self.IconChanged(dbus.ByteArray(new_icon))
def _get_rainbow_service(self):
"""Lazily initializes an interface to the Rainbow security daemon."""
if self._rainbow is None:
service = iface = 'org.laptop.security.Rainbow'
system_bus = dbus.SystemBus()
object = system_bus.get_object(service, '/')
self._rainbow = dbus.Interface(object, dbus_interface=iface,
follow_name_owner_change=True)
return self._rainbow
@dbus.service.signal(_DBUS_OWNER_IFACE, signature="s")
def CurrentActivityChanged(self, activity_id):
pass
if os.path.exists('/etc/olpc-security'):
self._get_rainbow_service().ChangeActivity(activity_id, dbus_interface=iface)
def _cur_activity_changed_cb(self, owner, new_activity):
new_id = ""

View File

@ -14,13 +14,13 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
from sugar.graphics.canvasicon import CanvasIcon
from sugar.graphics.icon import CanvasIcon
from sugar.graphics.palette import Palette
from view.BuddyMenu import BuddyMenu
class BuddyIcon(CanvasIcon):
def __init__(self, shell, buddy):
CanvasIcon.__init__(self, icon_name='theme:computer-xo',
CanvasIcon.__init__(self, icon_name='computer-xo',
xo_color=buddy.get_color())
self._shell = shell

View File

@ -20,7 +20,7 @@ from gettext import gettext as _
import gobject
from sugar.graphics.canvasicon import CanvasIcon
from sugar.graphics.icon import CanvasIcon
from view.clipboardmenu import ClipboardMenu
from sugar.graphics.xocolor import XoColor
from sugar.graphics import style
@ -88,7 +88,7 @@ class ClipboardIcon(CanvasIcon):
if icon_name:
self.props.icon_name = icon_name
else:
self.props.icon_name = 'theme:application-octet-stream'
self.props.icon_name = 'application-octet-stream'
self._name = name
self._percent = percent

View File

@ -14,10 +14,13 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
from gettext import gettext as _
import gtk
from gettext import gettext as _
from sugar.graphics import canvasicon
from sugar import profile
from sugar.graphics.icon import CanvasIcon
from sugar.graphics.icon import get_icon_state
from sugar.graphics import style
from sugar.graphics.palette import Palette
@ -27,9 +30,10 @@ _STATUS_CHARGING = 0
_STATUS_DISCHARGING = 1
_STATUS_FULLY_CHARGED = 2
class DeviceView(canvasicon.CanvasIcon):
class DeviceView(CanvasIcon):
def __init__(self, model):
canvasicon.CanvasIcon.__init__(self, size=style.MEDIUM_ICON_SIZE)
CanvasIcon.__init__(self, size=style.MEDIUM_ICON_SIZE,
xo_color=profile.get_color())
self._model = model
self._palette = BatteryPalette(_('My Battery life'))
self.set_palette(self._palette)
@ -40,13 +44,13 @@ class DeviceView(canvasicon.CanvasIcon):
self._update_info()
def _update_info(self):
self.props.icon_name = canvasicon.get_icon_state(
_ICON_NAME, self._model.props.level)
name = get_icon_state(_ICON_NAME, self._model.props.level)
self.props.icon_name = name
# Update palette
if self._model.props.charging:
status = _STATUS_CHARGING
self.props.badge_name = 'theme:badge-charging'
self.props.badge_name = 'badge-charging'
elif self._model.props.discharging:
status = _STATUS_DISCHARGING
self.props.badge_name = None

View File

@ -14,7 +14,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
from sugar.graphics.canvasicon import CanvasIcon
from sugar.graphics.icon import CanvasIcon
def create(model):
name = 'view.devices.' + model.get_type()

View File

@ -15,6 +15,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
from sugar import profile
from sugar.graphics import canvasicon
from sugar.graphics import style
from model.devices import device
@ -22,7 +23,7 @@ from model.devices import device
class DeviceView(canvasicon.CanvasIcon):
def __init__(self, model):
canvasicon.CanvasIcon.__init__(self, size=style.MEDIUM_ICON_SIZE,
icon_name='theme:network-mesh')
icon_name='network-mesh')
self._model = model
model.connect('notify::state', self._state_changed_cb)
@ -35,11 +36,10 @@ class DeviceView(canvasicon.CanvasIcon):
# FIXME Change icon colors once we have real icons
state = self._model.props.state
if state == device.STATE_ACTIVATING:
self.props.fill_color = style.COLOR_INACTIVE_FILL
self.props.stroke_color = style.COLOR_INACTIVE_STROKE
self.props.fill_color = style.COLOR_INACTIVE_FILL.get_svg()
self.props.stroke_color = style.COLOR_INACTIVE_STROKE.get_svg()
elif state == device.STATE_ACTIVATED:
self.props.fill_color = None
self.props.stroke_color = None
self.props.xo_color = profile.get_color()
elif state == device.STATE_INACTIVE:
self.props.fill_color = style.COLOR_INACTIVE_FILL
self.props.stroke_color = style.COLOR_INACTIVE_STROKE
self.props.fill_color = style.COLOR_INACTIVE_FILL.get_svg()
self.props.stroke_color = style.COLOR_INACTIVE_STROKE.get_svg()

View File

@ -19,4 +19,4 @@ from view.devices import deviceview
class DeviceView(deviceview.DeviceView):
def __init__(self, model):
deviceview.DeviceView.__init__(self, model)
self.props.icon_name = 'theme:network-wired'
self.props.icon_name = 'network-wired'

View File

@ -15,11 +15,11 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
from sugar.graphics import canvasicon
from sugar.graphics import style
from sugar.graphics.icon import get_icon_state
from sugar.graphics.icon import CanvasIcon
from sugar.graphics import style
from model.devices.network import wireless
from sugar.graphics.canvasicon import CanvasIcon
from model.devices import device
_ICON_NAME = 'network-wireless'
@ -47,8 +47,7 @@ class DeviceView(CanvasIcon):
self._update_state()
def _update_icon(self):
icon_name = canvasicon.get_icon_state(
_ICON_NAME, self._model.props.strength)
icon_name = get_icon_state(_ICON_NAME, self._model.props.strength)
if icon_name:
self.props.icon_name = icon_name
@ -56,11 +55,11 @@ class DeviceView(CanvasIcon):
# FIXME Change icon colors once we have real icons
state = self._model.props.state
if state == device.STATE_ACTIVATING:
self.props.fill_color = style.COLOR_INACTIVE_FILL
self.props.stroke_color = style.COLOR_INACTIVE_STROKE
self.props.fill_color = style.COLOR_INACTIVE_FILL.get_svg()
self.props.stroke_color = style.COLOR_INACTIVE_STROKE.get_svg()
elif state == device.STATE_ACTIVATED:
self.props.fill_color = None
self.props.stroke_color = None
elif state == device.STATE_INACTIVE:
self.props.fill_color = style.COLOR_INACTIVE_FILL
self.props.stroke_color = style.COLOR_INACTIVE_STROKE
self.props.fill_color = style.COLOR_INACTIVE_FILL.get_svg()
self.props.stroke_color = style.COLOR_INACTIVE_STROKE.get_svg()

View File

@ -28,9 +28,9 @@ from frameinvoker import FrameCanvasInvoker
class ActivityButton(IconButton):
def __init__(self, activity_info):
IconButton.__init__(self, icon_name=activity_info.icon,
stroke_color=style.COLOR_WHITE,
fill_color=style.COLOR_TRANSPARENT)
IconButton.__init__(self, file_name=activity_info.icon,
stroke_color=style.COLOR_WHITE.get_svg(),
fill_color=style.COLOR_TRANSPARENT.get_svg())
palette = Palette(activity_info.name)
palette.props.invoker = FrameCanvasInvoker(self)
@ -44,7 +44,7 @@ class ActivityButton(IconButton):
class InviteButton(IconButton):
def __init__(self, activity_model, invite):
IconButton.__init__(self, icon_name=activity_model.get_color())
IconButton.__init__(self, file_name=activity_model.get_icon())
self.props.xo_color = activity_model.get_color()
self._invite = invite

View File

@ -17,7 +17,7 @@
import hippo
from sugar.graphics.palette import Palette
from sugar.graphics.canvasicon import CanvasIcon
from sugar.graphics.icon import CanvasIcon
from sugar.graphics import style
from sugar.presence import presenceservice

View File

@ -24,7 +24,7 @@ class OverlayBox(hippo.CanvasBox):
self._shell = shell
icon = IconButton(icon_name='theme:stock-chat')
icon = IconButton(icon_name='stock-chat')
icon.connect('activated', self._overlay_clicked_cb)
self.append(icon)

View File

@ -30,7 +30,7 @@ class ZoomBox(hippo.CanvasBox):
self._shell = shell
icon = IconButton(icon_name='theme:zoom-mesh')
icon = IconButton(icon_name='zoom-mesh')
icon.connect('activated',
self._level_clicked_cb,
ShellModel.ZOOM_MESH)
@ -41,7 +41,7 @@ class ZoomBox(hippo.CanvasBox):
palette.set_group_id('frame')
icon.set_palette(palette)
icon = IconButton(icon_name='theme:zoom-friends')
icon = IconButton(icon_name='zoom-friends')
icon.connect('activated',
self._level_clicked_cb,
ShellModel.ZOOM_FRIENDS)
@ -52,7 +52,7 @@ class ZoomBox(hippo.CanvasBox):
palette.set_group_id('frame')
icon.set_palette(palette)
icon = IconButton(icon_name='theme:zoom-home')
icon = IconButton(icon_name='zoom-home')
icon.connect('activated',
self._level_clicked_cb,
ShellModel.ZOOM_HOME)
@ -63,7 +63,7 @@ class ZoomBox(hippo.CanvasBox):
palette.set_group_id('frame')
icon.set_palette(palette)
icon = IconButton(icon_name='theme:zoom-activity')
icon = IconButton(icon_name='zoom-activity')
icon.connect('activated',
self._level_clicked_cb,
ShellModel.ZOOM_ACTIVITY)

View File

@ -17,7 +17,7 @@
import hippo
import gobject
from sugar.graphics.canvasicon import CanvasIcon
from sugar.graphics.icon import CanvasIcon
from sugar.graphics import style
from sugar.presence import presenceservice
from sugar import activity
@ -67,7 +67,7 @@ class FriendView(hippo.CanvasBox):
# than hiding the icon?
name = self._get_new_icon_name(home_activity)
if name:
self._activity_icon.props.icon_name = name
self._activity_icon.props.file_name = name
self._activity_icon.props.xo_color = buddy.get_color()
if not self._activity_icon_visible:
self.append(self._activity_icon, hippo.PACK_EXPAND)

View File

@ -21,10 +21,10 @@ import gobject
from gettext import gettext as _
from sugar.graphics.spreadlayout import SpreadLayout
from sugar.graphics.canvasicon import CanvasIcon
from sugar.graphics.icon import CanvasIcon
from sugar.graphics import style
from sugar.graphics import xocolor
from sugar.graphics import canvasicon
from sugar.graphics.icon import get_icon_state
from sugar.graphics import style
from sugar import profile
@ -86,8 +86,7 @@ class AccessPointView(PulsingIcon):
self.set_tooltip(self._model.props.name)
def _update_icon(self):
icon_name = canvasicon.get_icon_state(
_ICON_NAME, self._model.props.strength)
icon_name = get_icon_state(_ICON_NAME, self._model.props.strength)
if icon_name:
self.props.icon_name = icon_name
@ -95,33 +94,33 @@ class AccessPointView(PulsingIcon):
if self._model.props.state == accesspointmodel.STATE_CONNECTING:
self.props.pulse_time = 1.0
self.props.colors = [
[ style.Color(self._device_stroke),
style.Color(self._device_fill) ],
[ style.Color(self._device_stroke),
style.Color('#e2e2e2') ]
[ style.Color(self._device_stroke).get_svg(),
style.Color(self._device_fill).get_svg() ],
[ style.Color(self._device_stroke).get_svg(),
'#e2e2e2' ]
]
elif self._model.props.state == accesspointmodel.STATE_CONNECTED:
self.props.pulse_time = 2.0
self.props.colors = [
[ style.Color(self._device_stroke),
style.Color(self._device_fill) ],
[ style.Color('#ffffff'),
style.Color(self._device_fill) ]
[ style.Color(self._device_stroke).get_svg(),
style.Color(self._device_fill).get_svg() ],
[ '#ffffff',
style.Color(self._device_fill).get_svg() ]
]
elif self._model.props.state == accesspointmodel.STATE_NOTCONNECTED:
self.props.pulse_time = 0.0
self.props.colors = [
[ style.Color(self._device_stroke),
style.Color(self._device_fill) ]
[ style.Color(self._device_stroke).get_svg(),
style.Color(self._device_fill).get_svg() ]
]
_MESH_ICON_NAME = 'theme:network-mesh'
_MESH_ICON_NAME = 'network-mesh'
class MeshDeviceView(PulsingIcon):
def __init__(self, nm_device):
PulsingIcon.__init__(self, size=style.MEDIUM_ICON_SIZE,
icon_name=_MESH_ICON_NAME)
icon_name=_MESH_ICON_NAME)
self._nm_device = nm_device
self.set_tooltip(_("Mesh Network"))
@ -177,7 +176,7 @@ class ActivityView(hippo.CanvasBox):
self._layout = SnowflakeLayout()
self.set_layout(self._layout)
self._icon = CanvasIcon(icon_name=model.get_icon_name(),
self._icon = CanvasIcon(file_name=model.get_icon_name(),
xo_color=model.get_color(), box_width=80)
self._icon.connect('activated', self._clicked_cb)
self._icon.set_tooltip(self._model.get_title())

View File

@ -14,11 +14,11 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
from sugar.graphics.canvasicon import CanvasIcon
from sugar.graphics.icon import CanvasIcon
from sugar import profile
class MyIcon(CanvasIcon):
def __init__(self, size):
CanvasIcon.__init__(self, size=size,
icon_name='theme:computer-xo',
icon_name='computer-xo',
xo_color=profile.get_color())

View File

@ -24,7 +24,7 @@ import hippo
import gobject
import gtk
from sugar.graphics.canvasicon import CanvasIcon
from sugar.graphics.icon import CanvasIcon
from sugar.graphics.menuitem import MenuItem
from sugar.graphics.palette import Palette
from sugar.graphics import style
@ -73,8 +73,8 @@ class ActivityIcon(CanvasIcon):
self._level = self._level_max
color = self._icon_colors[self._level]
CanvasIcon.__init__(self, icon_name=icon_name, xo_color=color,
size=style.MEDIUM_ICON_SIZE, cache=True)
CanvasIcon.__init__(self, file_name=icon_name, xo_color=color,
size=style.MEDIUM_ICON_SIZE)
self._activity = activity
self._pulse_id = 0
@ -119,8 +119,6 @@ class ActivityIcon(CanvasIcon):
if self._pulse_id:
gobject.source_remove(self._pulse_id)
self._pulse_id = 0
# dispose of all rendered icons from launch feedback
self._clear_buffers()
def _compute_icon_colors(self):
_LEVEL_MAX = 1.6
@ -161,6 +159,7 @@ class ActivityIcon(CanvasIcon):
if self._pulse_id:
return
self.props.cache_size = self._level_max
self._pulse_id = gobject.timeout_add(self._INTERVAL, self._pulse_cb)
def _stop_pulsing(self):
@ -169,6 +168,7 @@ class ActivityIcon(CanvasIcon):
self._cleanup()
self._level = 100.0
self.props.cache_size = 1
self.props.xo_color = self._orig_color
def _resume_activate_cb(self, menuitem):
@ -317,7 +317,7 @@ class ActivitiesDonut(hippo.CanvasBox, hippo.CanvasItem):
try:
smaps = ProcSmaps(pid)
_subtract_mappings(smaps, shell_mappings)
self._subtract_mappings(smaps, shell_mappings)
for mapping in smaps.mappings:
if mapping.shared_clean > 0 or mapping.shared_dirty > 0:
if num_mappings.has_key(mapping.name):
@ -408,7 +408,7 @@ class ActivitiesDonut(hippo.CanvasBox, hippo.CanvasItem):
if icon.size > _MIN_WEDGE_SIZE:
icon.size -= (icon.size - _MIN_WEDGE_SIZE) * reduction
def _subtract_mappings(smaps, mappings_to_remove):
def _subtract_mappings(self, smaps, mappings_to_remove):
for mapping in smaps.mappings:
if mappings_to_remove.has_key(mapping.name):
mapping.shared_clean = 0

View File

@ -16,7 +16,7 @@
import gobject
from sugar.graphics.canvasicon import CanvasIcon
from sugar.graphics.icon import CanvasIcon
class PulsingIcon(CanvasIcon):
__gproperties__ = {

View File

@ -75,9 +75,9 @@ class ActivityToolbar(gtk.Toolbar):
self.share = ToolComboBox(label_text='Share with:')
self.share.combo.connect('changed', self._share_changed_cb)
self.share.combo.append_item(None, _('Private'),
'theme:zoom-home-mini')
'zoom-home-mini')
self.share.combo.append_item(None, _('My Neighborhood'),
'theme:zoom-neighborhood-mini')
'zoom-neighborhood-mini')
self.insert(self.share, -1)
self.share.show()
@ -469,13 +469,22 @@ class Activity(Window, gtk.Container):
self._shared_activity = activity
self.emit('shared')
def share(self):
"""Request that the activity be shared on the network."""
def share(self, private=False):
"""Request that the activity be shared on the network.
private -- bool: True to share by invitation only,
False to advertise as shared to everyone.
"""
# FIXME: Make private=True to turn on the by-invitation-only scope
if self._shared_activity and self._shared_activity.props.joined:
raise RuntimeError("Activity %s already shared." % self._activity_id)
logging.debug('Requesting share of activity %s.' % self._activity_id)
self._share_id = self._pservice.connect("activity-shared", self._internal_share_cb)
self._pservice.share_activity(self)
raise RuntimeError("Activity %s already shared." %
self._activity_id)
verb = private and 'private' or 'public'
logging.debug('Requesting %s share of activity %s.' %
(verb, self._activity_id))
self._share_id = self._pservice.connect("activity-shared",
self._internal_share_cb)
self._pservice.share_activity(self, private=private)
def _realize_cb(self, window):
wm.set_bundle_id(window.window, self.get_service_name())

View File

@ -26,12 +26,18 @@ from sugar.presence import presenceservice
from sugar.activity.activityhandle import ActivityHandle
from sugar import util
import os
_SHELL_SERVICE = "org.laptop.Shell"
_SHELL_PATH = "/org/laptop/Shell"
_SHELL_IFACE = "org.laptop.Shell"
_ACTIVITY_FACTORY_INTERFACE = "org.laptop.ActivityFactory"
_RAINBOW_SERVICE_NAME = "org.laptop.security.Rainbow"
_RAINBOW_ACTIVITY_FACTORY_PATH = "/"
_RAINBOW_ACTIVITY_FACTORY_INTERFACE = "org.laptop.security.Rainbow"
def create_activity_id():
"""Generate a new, unique ID for this activity"""
pservice = presenceservice.get_instance()
@ -84,6 +90,9 @@ class ActivityCreationHandler(gobject.GObject):
particular type of activity is created during the activity
registration process in shell bundle registry which creates
service definition files for each registered bundle type.
If the file '/etc/olpc-security' exists, then activity launching
will be delegated to the prototype 'Rainbow' security service.
"""
gobject.GObject.__init__(self)
self._service_name = service_name
@ -112,10 +121,22 @@ class ActivityCreationHandler(gobject.GObject):
reply_handler=self._no_reply_handler,
error_handler=self._notify_launch_error_handler)
self._factory.create(self._activity_handle.get_dict(),
timeout=120 * 1000,
reply_handler=self._no_reply_handler,
error_handler=self._create_error_handler)
if not os.path.exists('/etc/olpc-security'):
self._factory.create(self._activity_handle.get_dict(),
timeout=120 * 1000,
reply_handler=self._no_reply_handler,
error_handler=self._create_error_handler)
else:
system_bus = dbus.SystemBus()
factory = system_bus.get_object(_RAINBOW_SERVICE_NAME,
_RAINBOW_ACTIVITY_FACTORY_PATH)
factory.CreateActivity(
self._service_name,
self._activity_handle.get_dict(),
timeout=120 * 1000,
reply_handler=self._create_reply_handler,
error_handler=self._create_error_handler,
dbus_interface=_RAINBOW_ACTIVITY_FACTORY_INTERFACE)
def get_activity_id(self):
"""Retrieve the unique identity for this activity"""

View File

@ -63,6 +63,9 @@ class DSMetadata(gobject.GObject):
def get_dictionary(self):
return self._props
def copy(self):
return DSMetadata(self._props.copy())
class DSObject(object):
def __init__(self, object_id, metadata=None, file_path=None):
self.object_id = object_id
@ -161,6 +164,9 @@ class DSObject(object):
'Please call DSObject.destroy() before disposing it.')
self.destroy()
def copy(self):
return DSObject(None, self._metadata.copy(), self._file_path)
def get(object_id):
logging.debug('datastore.get')
metadata = dbus_helpers.get_properties(object_id)
@ -224,6 +230,16 @@ def find(query, sorting=None, limit=None, offset=None, reply_handler=None,
return objects, total_count
def copy(jobject, mount_point):
new_jobject = jobject.copy()
new_jobject.metadata['mountpoint'] = mount_point
# this will cause the file be retrieved from the DS
new_jobject.file_path = jobject.file_path
write(new_jobject)
def mount(uri, options):
return dbus_helpers.mount(uri, options)

View File

@ -2,11 +2,9 @@ sugardir = $(pythondir)/sugar/graphics
sugar_PYTHON = \
__init__.py \
animator.py \
canvasbutton.py \
canvasicon.py \
canvasentry.py \
canvasroundbox.py \
button.py \
combobox.py \
entry.py \
icon.py \
iconbutton.py \
iconentry.py \
@ -17,6 +15,7 @@ sugar_PYTHON = \
palette.py \
palettegroup.py \
panel.py \
roundbox.py \
spreadlayout.py \
style.py \
toggletoolbutton.py \

View File

@ -25,7 +25,7 @@ class CanvasButton(hippo.CanvasButton):
hippo.CanvasButton.__init__(self, text=label)
if icon_name:
icon = Icon(icon_name,icon_size=gtk.ICON_SIZE_BUTTON)
icon = Icon(icon_name=icon_name, icon_size=gtk.ICON_SIZE_BUTTON)
self.props.widget.set_image(icon)
icon.show()

View File

@ -1,433 +0,0 @@
# Copyright (C) 2006-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 logging
import re
import gobject
import gtk
import hippo
import rsvg
import cairo
import time
from sugar.graphics.xocolor import XoColor
from sugar.graphics import style
from sugar.graphics.palette import Palette, CanvasInvoker
_ICON_REQUEST_SIZE = 50
_BADGE_SIZE = 0.45
class _IconCacheIcon:
def __init__(self, name, fill_color, stroke_color, now):
self.last_used = now
self.usage_count = 1
self.badge_x = 1.0 - _BADGE_SIZE / 2
self.badge_y = 1.0 - _BADGE_SIZE / 2
if name[0:6] == "theme:":
info = gtk.icon_theme_get_default().lookup_icon(
name[6:], _ICON_REQUEST_SIZE, 0)
if not info:
raise ValueError("Icon '" + name + "' not found.")
fname = info.get_filename()
attach_points = info.get_attach_points()
if attach_points is not None:
self.badge_x = float(attach_points[0][0]) / _ICON_REQUEST_SIZE
self.badge_y = float(attach_points[0][1]) / _ICON_REQUEST_SIZE
del info
else:
fname = name
self.handle = self._read_icon_data(fname, fill_color, stroke_color)
def _read_icon_data(self, filename, fill_color, stroke_color):
icon_file = open(filename, 'r')
data = icon_file.read()
icon_file.close()
if fill_color:
entity = '<!ENTITY fill_color "%s">' % fill_color
data = re.sub('<!ENTITY fill_color .*>', entity, data)
if stroke_color:
entity = '<!ENTITY stroke_color "%s">' % stroke_color
data = re.sub('<!ENTITY stroke_color .*>', entity, data)
self.data_size = len(data)
return rsvg.Handle(data=data)
class _IconCache:
_CACHE_MAX = 50000 # in bytes
def __init__(self):
self._icons = {}
self._cache_size = 0
def _cache_cleanup(self, key, now):
while self._cache_size > self._CACHE_MAX:
evict_key = None
oldest_key = None
oldest_time = now
for icon_key, icon in self._icons.items():
# Don't evict the icon we are about to use if it's in the cache
if icon_key == key:
continue
# evict large icons first
if icon.data_size > self._CACHE_MAX:
evict_key = icon_key
break
# evict older icons next; those used over 2 minutes ago
if icon.last_used < now - 120:
evict_key = icon_key
break
# otherwise, evict the oldest
if oldest_time > icon.last_used:
oldest_time = icon.last_used
oldest_key = icon_key
# If there's nothing specific to evict, try evicting
# the oldest thing
if not evict_key:
if not oldest_key:
break
evict_key = oldest_key
self._cache_size -= self._icons[evict_key].data_size
del self._icons[evict_key]
def get_icon(self, name, fill_color, stroke_color):
if not name:
return None
if fill_color or stroke_color:
key = (name, fill_color, stroke_color)
else:
key = name
# If we're over the cache limit, evict something from the cache
now = time.time()
self._cache_cleanup(key, now)
if self._icons.has_key(key):
icon = self._icons[key]
icon.usage_count += 1
icon.last_used = now
else:
icon = _IconCacheIcon(name, fill_color, stroke_color, now)
self._icons[key] = icon
self._cache_size += icon.data_size
return icon
class CanvasIcon(hippo.CanvasBox, hippo.CanvasItem):
__gtype_name__ = 'CanvasIcon'
__gproperties__ = {
'icon-name' : (str, None, None, None,
gobject.PARAM_READWRITE),
'xo-color' : (object, None, None,
gobject.PARAM_WRITABLE),
'fill-color' : (object, None, None,
gobject.PARAM_READWRITE),
'stroke-color' : (object, None, None,
gobject.PARAM_READWRITE),
'size' : (int, None, None, 0, 1024, 0,
gobject.PARAM_READWRITE),
'scale' : (int, None, None, 0, 1024, 0,
gobject.PARAM_READWRITE),
'cache' : (bool, None, None, False,
gobject.PARAM_READWRITE),
'active' : (bool, None, None, True,
gobject.PARAM_READWRITE),
'badge-name' : (str, None, None, None,
gobject.PARAM_READWRITE)
}
_cache = _IconCache()
def __init__(self, **kwargs):
self._buffers = {}
self._cur_buffer = None
self._size = 0
self._scale = 0
self._fill_color = None
self._stroke_color = None
self._icon_name = None
self._cache = False
self._icon = None
self._active = True
self._palette = None
self._badge_name = None
self._badge_icon = None
hippo.CanvasBox.__init__(self, **kwargs)
self.connect_after('motion-notify-event', self._motion_notify_event_cb)
def _clear_buffers(self):
icon_key = self._get_current_buffer_key(self._icon_name)
badge_key = None
if self._badge_name:
badge_key = self._get_current_buffer_key(self._badge_name)
for key in self._buffers.keys():
if key != icon_key:
if not badge_key or (key != badge_key):
del self._buffers[key]
self._buffers = {}
def do_set_property(self, pspec, value):
if pspec.name == 'icon-name':
if self._icon_name != value and not self._cache:
self._clear_buffers()
self._icon_name = value
self._icon = None
self.emit_paint_needed(0, 0, -1, -1)
elif pspec.name == 'xo-color':
self.props.fill_color = style.Color(value.get_fill_color())
self.props.stroke_color = style.Color(value.get_stroke_color())
elif pspec.name == 'fill-color':
if self._fill_color != value:
if not self._cache:
self._clear_buffers()
self._fill_color = value
self._icon = None
self._badge_icon = None
self.emit_paint_needed(0, 0, -1, -1)
elif pspec.name == 'stroke-color':
if self._stroke_color != value:
if not self._cache:
self._clear_buffers()
self._stroke_color = value
self._icon = None
self._badge_icon = None
self.emit_paint_needed(0, 0, -1, -1)
elif pspec.name == 'size':
if self._size != value and not self._cache:
self._clear_buffers()
self._size = value
self.emit_request_changed()
elif pspec.name == 'scale':
if self._scale != value and not self._cache:
self._clear_buffers()
self._scale = value
self.emit_request_changed()
elif pspec.name == 'cache':
self._cache = value
elif pspec.name == 'active':
if self._active != value:
if not self._cache:
self._clear_buffers()
self._active = value
self._icon = None
self.emit_paint_needed(0, 0, -1, -1)
elif pspec.name == 'badge-name':
if self._badge_name != value and not self._cache:
self._clear_buffers()
self._badge_name = value
self._badge_icon = None
self.emit_paint_needed(0, 0, -1, -1)
def _choose_colors(self):
fill_color = None
stroke_color = None
if self._active:
if self._fill_color:
fill_color = self._fill_color.get_svg()
if self._stroke_color:
stroke_color = self._stroke_color.get_svg()
else:
stroke_color = color.ICON_STROKE_INACTIVE.get_svg()
if self._fill_color:
fill_color = self._fill_color.get_svg()
return [fill_color, stroke_color]
def _get_icon_from_cache(self, name, icon):
if not icon:
cache = CanvasIcon._cache
[fill_color, stroke_color] = self._choose_colors()
icon = cache.get_icon(name, fill_color, stroke_color)
return icon
def _get_icon(self):
self._icon = self._get_icon_from_cache(self._icon_name, self._icon)
return self._icon
def _get_badge_icon(self):
self._badge_icon = self._get_icon_from_cache(self._badge_name,
self._badge_icon)
return self._badge_icon
def _get_current_buffer_key(self, name):
[fill_color, stroke_color] = self._choose_colors()
return (name, fill_color, stroke_color, self._size)
def do_get_property(self, pspec):
if pspec.name == 'size':
return self._size
elif pspec.name == 'icon-name':
return self._icon_name
elif pspec.name == 'fill-color':
return self._fill_color
elif pspec.name == 'stroke-color':
return self._stroke_color
elif pspec.name == 'cache':
return self._cache
elif pspec.name == 'active':
return self._active
elif pspec.name == 'badge-name':
return self._badge_name
elif pspec.name == 'scale':
return self._scale
def _get_icon_size(self, icon):
if icon:
dimensions = icon.handle.get_dimension_data()
return int(dimensions[0]), int(dimensions[1])
else:
return [0, 0]
def _get_size(self, icon):
width, height = self._get_icon_size(icon)
if self._scale != 0:
width = int(width * self._scale)
height = int(height * self._scale)
elif self._size != 0:
width = height = self._size
return [width, height]
def _get_buffer(self, cr, name, icon, scale_factor=None):
"""Return a cached cairo surface for the SVG icon, or if none exists,
create a new cairo surface with the right size."""
buf = None
key = self._get_current_buffer_key(name)
if self._buffers.has_key(key):
buf = self._buffers[key]
else:
[icon_w, icon_h] = self._get_icon_size(icon)
[target_w, target_h] = self._get_size(icon)
if scale_factor:
target_w = int(target_w * scale_factor)
target_h = int(target_h * scale_factor)
target = cr.get_target()
buf = target.create_similar(cairo.CONTENT_COLOR_ALPHA,
target_w, target_h)
ctx = cairo.Context(buf)
ctx.scale(float(target_w) / float(icon_w),
float(target_h) / float(icon_h))
icon.handle.render_cairo(ctx)
del ctx
self._buffers[key] = buf
return buf
def do_paint_below_children(self, cr, damaged_box):
icon = self._get_icon()
if icon is None:
return
icon_buf = self._get_buffer(cr, self._icon_name, icon)
[width, height] = self.get_allocation()
icon_x = (width - icon_buf.get_width()) / 2
icon_y = (height - icon_buf.get_height()) / 2
cr.set_source_surface(icon_buf, icon_x, icon_y)
cr.paint()
if self._badge_name:
badge_icon = self._get_badge_icon()
if badge_icon:
badge_buf = self._get_buffer(cr, self._badge_name, badge_icon, _BADGE_SIZE)
badge_x = (icon_x + icon.badge_x * icon_buf.get_width() -
badge_buf.get_width() / 2)
badge_y = (icon_y + icon.badge_y * icon_buf.get_height() -
badge_buf.get_height() / 2)
cr.set_source_surface(badge_buf, badge_x, badge_y)
cr.paint()
def do_get_content_width_request(self):
icon = self._get_icon()
[width, height] = self._get_size(icon)
if self._badge_name is not None:
# If the badge goes outside the bounding box, add space
# on *both* sides (to keep the main icon centered)
if icon.badge_x < 0.0:
width = int(width * 2 * (1.0 - icon.badge_x))
elif icon.badge_x + _BADGE_SIZE > 1.0:
width = int(width * 2 * (icon.badge_x + _BADGE_SIZE - 1.0))
return (width, width)
def do_get_content_height_request(self, for_width):
icon = self._get_icon()
[width, height] = self._get_size(icon)
if self._badge_name is not None:
if icon.badge_y < 0.0:
height = int(height * 2 * (1.0 - icon.badge_y))
elif icon.badge_y + _BADGE_SIZE > 1.0:
height = int(height * 2 * (icon.badge_y + _BADGE_SIZE - 1.0))
return (height, height)
def do_button_press_event(self, event):
self.emit_activated()
return True
def _motion_notify_event_cb(self, button, event):
if event.detail == hippo.MOTION_DETAIL_ENTER:
self.prelight(True)
elif event.detail == hippo.MOTION_DETAIL_LEAVE:
self.prelight(False)
return False
def prelight(self, enter):
"""
Override this method for adding prelighting behavior.
"""
pass
def get_palette(self):
return self._palette
def set_palette(self, palette):
self._palette = palette
if not self._palette.props.invoker:
self._palette.props.invoker = CanvasInvoker(self)
def set_tooltip(self, text):
self.set_palette(Palette(text))
palette = property(get_palette, set_palette)
def get_icon_state(base_name, perc):
step = 5
strength = round(perc / step) * step
icon_theme = gtk.icon_theme_get_default()
while strength <= 100:
icon_name = '%s-%03d' % (base_name, strength)
if icon_theme.has_icon(icon_name):
return 'theme:' + icon_name
strength = strength + step

View File

@ -61,8 +61,8 @@ class ComboBox(gtk.ComboBox):
del info
return fname
def append_item(self, action_id, text, icon_name=None):
if not self._icon_renderer and icon_name:
def append_item(self, action_id, text, icon_name=None, file_name=None):
if not self._icon_renderer and (icon_name or file_name):
self._icon_renderer = gtk.CellRendererPixbuf()
settings = self.get_settings()
@ -77,16 +77,17 @@ class ComboBox(gtk.ComboBox):
self.pack_end(self._text_renderer, True)
self.add_attribute(self._text_renderer, 'text', 1)
if icon_name:
if icon_name or file_name:
if text:
size = gtk.ICON_SIZE_MENU
else:
size = gtk.ICON_SIZE_LARGE_TOOLBAR
width, height = gtk.icon_size_lookup(size)
if icon_name[0:6] == "theme:":
icon_name = self._get_real_name_from_theme(icon_name[6:], size)
pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(icon_name, width, height)
if icon_name:
file_name = self._get_real_name_from_theme(icon_name, size)
pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(file_name, width, height)
else:
pixbuf = None

View File

@ -16,11 +16,280 @@
# Boston, MA 02111-1307, USA.
import os
import re
import time
import logging
import gobject
import gtk
import re
import hippo
import rsvg
import cairo
from sugar.graphics.style import Color
from sugar.graphics.xocolor import XoColor
from sugar.graphics import style
from sugar.graphics.palette import Palette, CanvasInvoker
_BADGE_SIZE = 0.45
_svg_loader = None
def _get_svg_loader():
global _svg_loader
if _svg_loader == None:
_svg_loader = _SVGLoader()
return _svg_loader
class _SVGIcon(object):
def __init__(self, data):
self.data = data
self.data_size = len(data)
self.last_used = time.time()
class _SVGLoader(object):
CACHE_MAX_SIZE = 50000
CACHE_MAX_ICON_SIZE = 5000
def __init__(self):
self._cache = {}
self._cache_size = 0
def load(self, file_name, entities):
icon = self._get_icon(file_name)
for entity, value in entities.items():
xml = '<!ENTITY %s "%s">' % (entity, value)
icon.data = re.sub('<!ENTITY %s .*>' % entity, xml, icon.data)
return rsvg.Handle(data=icon.data)
def _get_icon(self, file_name):
if self._cache.has_key(file_name):
data = self._cache[file_name]
data.last_used = time.time()
return data
icon_file = open(file_name, 'r')
icon = _SVGIcon(icon_file.read())
icon_file.close()
self._cache[file_name] = icon
self._cleanup_cache()
return icon
def _cleanup_cache(self):
now = time.time()
while self._cache_size > self.CACHE_MAX_SIZE:
evict_key = None
oldest_key = None
oldest_time = now
for icon_key, icon in self._cache.items():
# evict large icons first
if icon.data_size > self.CACHE_MAX_ICON_SIZE:
evict_key = icon_key
break
# evict older icons next; those used over 2 minutes ago
if icon.last_used < now - 120:
evict_key = icon_key
break
# otherwise, evict the oldest
if oldest_time > icon.last_used:
oldest_time = icon.last_used
oldest_key = icon_key
# If there's nothing specific to evict, try evicting
# the oldest thing
if not evict_key:
if not oldest_key:
break
evict_key = oldest_key
self._cache_size -= self._cache[evict_key].data_size
del self._cache[evict_key]
class _IconInfo(object):
def __init__(self):
self.file_name = None
self.attach_x = 0
self.attach_y = 0
class _BadgeInfo(object):
def __init__(self):
self.attach_x = 0
self.attach_y = 0
self.size = 0
self.icon_padding = 0
class _IconBuffer(object):
def __init__(self):
self._svg_loader = _get_svg_loader()
self._surface_cache = {}
self._cache_size = 1
self.icon_name = None
self.file_name = None
self.fill_color = None
self.stroke_color = None
self.badge_name = None
self.width = None
self.height = None
def _get_cache_key(self):
return (self.icon_name, self.file_name, self.fill_color,
self.stroke_color, self.badge_name, self.width, self.height)
def _load_svg(self, file_name):
entities = {}
if self.fill_color:
entities['fill_color'] = self.fill_color
if self.stroke_color:
entities['stroke_color'] = self.stroke_color
return self._svg_loader.load(file_name, entities)
def _get_attach_points(self, info, size_request):
attach_points = info.get_attach_points()
if attach_points:
attach_x = float(attach_points[0][0]) / size_request
attach_y = float(attach_points[0][1]) / size_request
else:
attach_x = attach_y = 0
return attach_x, attach_y
def _get_icon_info(self):
icon_info = _IconInfo()
if self.file_name:
icon_info.file_name = self.file_name
elif self.icon_name:
theme = gtk.icon_theme_get_default()
size = 50
if self.width != None:
size = self.width
info = theme.lookup_icon(self.icon_name, size, 0)
if info:
attach_x, attach_y = self._get_attach_points(info, size)
icon_info.file_name = info.get_filename()
icon_info.attach_x = attach_x
icon_info.attach_y = attach_y
else:
logging.warning('No icon with the name %s was found in the theme.' % self.icon_name)
return icon_info
def _draw_badge(self, context, size):
theme = gtk.icon_theme_get_default()
badge_info = theme.lookup_icon(self.badge_name, size, 0)
if badge_info:
badge_file_name = badge_info.get_filename()
if badge_file_name.endswith('.svg'):
handle = self._svg_loader.load(badge_file_name, {})
handle.render_cairo(context)
else:
pixbuf = gtk.gdk.pixbuf_new_from_file(badge_file_name)
surface = hippo.cairo_surface_from_gdk_pixbuf(pixbuf)
context.set_source_surface(surface, 0, 0)
context.paint()
def _get_size(self, icon_width, icon_height):
if self.width is not None and self.height is not None:
width = self.width
height = self.height
else:
width = icon_width
height = icon_height
return width, height
def _get_badge_info(self, icon_info, icon_width, icon_height):
info = _BadgeInfo()
if self.badge_name is None:
return info
info.size = int(_BADGE_SIZE * icon_width)
info.attach_x = int(icon_info.attach_x * icon_width - info.size / 2)
info.attach_y = int(icon_info.attach_y * icon_height - info.size / 2)
if info.attach_x < 0 or info.attach_y < 0:
info.icon_padding = max(-info.attach_x, -info.attach_y)
elif info.attach_x + info.size > icon_width or \
info.attach_y + info.size > icon_height:
x_padding = info.attach_x + info.size - icon_width
y_padding = info.attach_y + info.size - icon_height
info.icon_padding = max(x_padding, y_padding)
return info
def get_surface(self):
cache_key = self._get_cache_key()
if self._surface_cache.has_key(cache_key):
return self._surface_cache[cache_key]
icon_info = self._get_icon_info()
if icon_info.file_name is None:
return None
is_svg = icon_info.file_name.endswith('.svg')
if is_svg:
handle = self._load_svg(icon_info.file_name)
dimensions = handle.get_dimension_data()
icon_width = int(dimensions[0])
icon_height = int(dimensions[1])
else:
pixbuf = gtk.gdk.pixbuf_new_from_file(icon_info.file_name)
icon_width = pixbuf.get_width()
icon_height = pixbuf.get_height()
badge_info = self._get_badge_info(icon_info, icon_width, icon_height)
width, height = self._get_size(icon_width, icon_height)
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
context = cairo.Context(surface)
padding = badge_info.icon_padding
context.scale(float(width) / (icon_width + padding * 2),
float(height) / (icon_height + padding * 2))
context.save()
context.translate(padding, padding)
if is_svg:
handle.render_cairo(context)
else:
pixbuf_surface = hippo.cairo_surface_from_gdk_pixbuf(pixbuf)
context.set_source_surface(pixbuf_surface, 0, 0)
context.paint()
if self.badge_name:
context.restore()
context.translate(badge_info.attach_x, badge_info.attach_y)
self._draw_badge(context, badge_info.size)
if (len(self._surface_cache) == self._cache_size):
self._surface_cache.popitem()
self._surface_cache[cache_key] = surface
return surface
def get_cache_size(self):
return self._cache_size
def set_cache_size(self, cache_size):
while len(self._surface_cache) > cache_size:
self._surface_cache.popitem()
self._cache_size = cache_size
cache_size = property(get_cache_size, set_cache_size)
class Icon(gtk.Image):
__gtype_name__ = 'SugarIcon'
@ -31,124 +300,219 @@ class Icon(gtk.Image):
'fill-color' : (object, None, None,
gobject.PARAM_READWRITE),
'stroke-color' : (object, None, None,
gobject.PARAM_READWRITE),
'badge-name' : (str, None, None, None,
gobject.PARAM_READWRITE)
}
def __init__(self, name, **kwargs):
self._constructed = False
self._fill_color = None
self._stroke_color = None
self._icon_name = name
self._theme = gtk.icon_theme_get_default()
self._data = None
def __init__(self, **kwargs):
self._buffer = _IconBuffer()
gobject.GObject.__init__(self, **kwargs)
self._constructed = True
self._update_icon()
def _sync_image_properties(self):
if self._buffer.icon_name != self.props.icon_name:
self._buffer.icon_name = self.props.icon_name
def _get_pixbuf(self, data, width, height):
loader = gtk.gdk.PixbufLoader('svg')
loader.set_size(width, height)
loader.write(data, len(data))
loader.close()
return loader.get_pixbuf()
if self._buffer.file_name != self.props.file:
self._buffer.file_name = self.props.file
def _read_icon_data(self, icon_name):
filename = self._get_real_name(icon_name)
icon_file = open(filename, 'r')
data = icon_file.read()
icon_file.close()
width, height = gtk.icon_size_lookup(self.props.icon_size)
if self._buffer.width != width and self._buffer.height != height:
self._buffer.width = width
self._buffer.height = height
return data
def _icon_size_changed_cb(self, image, pspec):
self._buffer.icon_size = self.props.icon_size
def _update_normal_icon(self):
icon_theme = gtk.icon_theme_get_for_screen(self.get_screen())
icon_set = gtk.IconSet()
def _icon_name_changed_cb(self, image, pspec):
self._buffer.icon_name = self.props.icon_name
if icon_theme.has_icon(self._icon_name) or os.path.exists(self._icon_name):
source = gtk.IconSource()
def _file_changed_cb(self, image, pspec):
self._buffer.file_name = self.props.file
if os.path.exists(self._icon_name):
source.set_filename(self._icon_name)
else:
source.set_icon_name(self._icon_name)
def _update_buffer_size(self):
width, height = gtk.icon_size_lookup(self.props.icon_size)
icon_set.add_source(source)
self._buffer.width = width
self._buffer.height = height
inactive_name = self._icon_name + '-inactive'
if icon_theme.has_icon(inactive_name) or os.path.exists(inactive_name):
source = gtk.IconSource()
def do_expose_event(self, event):
self._sync_image_properties()
if os.path.exists(inactive_name):
source.set_filename(inactive_name)
else:
source.set_icon_name(inactive_name)
surface = self._buffer.get_surface()
if surface is not None:
cr = self.window.cairo_create()
source.set_state(gtk.STATE_INSENSITIVE)
icon_set.add_source(source)
x = self.allocation.x
y = self.allocation.y
self.props.icon_set = icon_set
def _update_icon(self):
if not self._constructed:
return
if not self._fill_color and not self._stroke_color:
self._update_normal_icon()
return
if not self._data:
data = self._read_icon_data(self._icon_name)
else:
data = self._data
if self._fill_color:
entity = '<!ENTITY fill_color "%s">' % self._fill_color
data = re.sub('<!ENTITY fill_color .*>', entity, data)
if self._stroke_color:
entity = '<!ENTITY stroke_color "%s">' % self._stroke_color
data = re.sub('<!ENTITY stroke_color .*>', entity, data)
self._data = data
# Redraw pixbuf
[w, h] = gtk.icon_size_lookup(self.props.icon_size)
pixbuf = self._get_pixbuf(self._data, w, h)
self.set_from_pixbuf(pixbuf)
def _get_real_name(self, name):
if os.path.exists(name):
return name
info = self._theme.lookup_icon(name, self.props.icon_size, 0)
if not info:
raise ValueError("Icon '" + name + "' not found.")
fname = info.get_filename()
del info
return fname
cr.set_source_surface(surface, x, y)
cr.paint()
def do_set_property(self, pspec, value):
if pspec.name == 'xo-color':
self.props.fill_color = value.get_fill_color()
self.props.stroke_color = value.get_stroke_color()
elif pspec.name == 'fill-color':
self._fill_color = value
self._update_icon()
self._buffer.fill_color = value
elif pspec.name == 'stroke-color':
self._stroke_color = value
self._update_icon()
self._buffer.stroke_color = value
elif pspec.name == 'badge-name':
self._buffer.badge_name = value
else:
gtk.Image.do_set_property(self, pspec, value)
if pspec.name == 'icon-size':
self._update_icon()
def do_get_property(self, pspec):
if pspec.name == 'fill-color':
return self._fill_color
return self._buffer.fill_color
elif pspec.name == 'stroke-color':
return self._stroke_color
return self._buffer.stroke_color
elif pspec.name == 'badge-name':
return self._buffer.badge_name
else:
return gtk.Image.do_get_property(self, pspec)
class CanvasIcon(hippo.CanvasBox, hippo.CanvasItem):
__gtype_name__ = 'CanvasIcon'
__gproperties__ = {
'file-name' : (str, None, None, None,
gobject.PARAM_READWRITE),
'icon-name' : (str, None, None, None,
gobject.PARAM_READWRITE),
'xo-color' : (object, None, None,
gobject.PARAM_WRITABLE),
'fill-color' : (object, None, None,
gobject.PARAM_READWRITE),
'stroke-color' : (object, None, None,
gobject.PARAM_READWRITE),
'size' : (int, None, None, 0, 1024, 0,
gobject.PARAM_READWRITE),
'scale' : (float, None, None, -1024.0, 1024.0, 1.0,
gobject.PARAM_READWRITE),
'cache-size' : (int, None, None, 0, 1024, 0,
gobject.PARAM_READWRITE),
'badge-name' : (str, None, None, None,
gobject.PARAM_READWRITE)
}
def __init__(self, **kwargs):
self._buffer = _IconBuffer()
hippo.CanvasBox.__init__(self, **kwargs)
self._palette = None
def do_set_property(self, pspec, value):
if pspec.name == 'file-name':
self._buffer.file_name = value
self.emit_paint_needed(0, 0, -1, -1)
elif pspec.name == 'icon-name':
self._buffer.icon_name = value
self.emit_paint_needed(0, 0, -1, -1)
elif pspec.name == 'xo-color':
self.props.fill_color = value.get_fill_color()
self.props.stroke_color = value.get_stroke_color()
elif pspec.name == 'fill-color':
if not isinstance(value, basestring) and value is not None:
raise TypeError('fill-color must be a string, not %r' % type(value))
self._buffer.fill_color = value
self.emit_paint_needed(0, 0, -1, -1)
elif pspec.name == 'stroke-color':
if not isinstance(value, basestring) and value is not None:
raise TypeError('stroke-color must be a string, not %r' % type(value))
self._buffer.stroke_color = value
self.emit_paint_needed(0, 0, -1, -1)
elif pspec.name == 'size':
self._buffer.width = value
self._buffer.height = value
self.emit_request_changed()
elif pspec.name == 'scale':
self._buffer.scale = value
self.emit_request_changed()
elif pspec.name == 'cache-size':
self._buffer.cache_size = value
elif pspec.name == 'badge-name':
self._buffer.badge_name = value
self.emit_paint_needed(0, 0, -1, -1)
def do_get_property(self, pspec):
if pspec.name == 'size':
return self._buffer.width
elif pspec.name == 'file-name':
return self._buffer.file_name
elif pspec.name == 'icon-name':
return self._buffer.icon_name
elif pspec.name == 'fill-color':
return self._buffer.fill_color
elif pspec.name == 'stroke-color':
return self._buffer.stroke_color
elif pspec.name == 'cache-size':
return self._buffer.cache_size
elif pspec.name == 'badge-name':
return self._buffer.badge_name
elif pspec.name == 'scale':
return self._buffer.scale
def do_paint_below_children(self, cr, damaged_box):
surface = self._buffer.get_surface()
if surface:
width, height = self.get_allocation()
x = (width - surface.get_width()) / 2
y = (height - surface.get_height()) / 2
cr.set_source_surface(surface, x, y)
cr.paint()
def do_get_content_width_request(self):
surface = self._buffer.get_surface()
if surface:
size = surface.get_width()
elif self._buffer.width:
size = self._buffer.width
else:
size = 0
return size, size
def do_get_content_height_request(self, for_width):
surface = self._buffer.get_surface()
if surface:
size = surface.get_height()
elif self._buffer.height:
size = self._buffer.height
else:
size = 0
return size, size
def do_button_press_event(self, event):
self.emit_activated()
return True
def get_palette(self):
return self._palette
def set_palette(self, palette):
self._palette = palette
if not self._palette.props.invoker:
self._palette.props.invoker = CanvasInvoker(self)
def set_tooltip(self, text):
self.set_palette(Palette(text))
palette = property(get_palette, set_palette)
def get_icon_state(base_name, perc):
step = 5
strength = round(perc / step) * step
icon_theme = gtk.icon_theme_get_default()
while strength <= 100:
icon_name = '%s-%03d' % (base_name, strength)
if icon_theme.has_icon(icon_name):
return icon_name
strength = strength + step

View File

@ -24,18 +24,18 @@ import sys
import gobject
import hippo
from sugar.graphics.canvasicon import CanvasIcon
from sugar.graphics.icon import CanvasIcon
from sugar.graphics import style
class IconButton(CanvasIcon, hippo.CanvasItem):
__gtype_name__ = 'SugarIconButton'
def __init__(self, **kwargs):
CanvasIcon.__init__(self, cache=True, **kwargs)
CanvasIcon.__init__(self, **kwargs)
if not self.props.fill_color and not self.props.stroke_color:
self.props.fill_color = style.Color("#404040")
self.props.stroke_color = style.Color("#FFFFFF")
self.props.fill_color = style.Color("#404040").get_svg()
self.props.stroke_color = style.Color("#FFFFFF").get_svg()
self.connect('activated', self._icon_clicked_cb)
@ -43,18 +43,6 @@ class IconButton(CanvasIcon, hippo.CanvasItem):
self.props.box_height = style.GRID_CELL_SIZE
self.props.size = style.STANDARD_ICON_SIZE
def do_button_press_event(self, event):
if self._active:
self.emit_activated()
return True
def prelight(self, enter):
if enter:
if self.props.active:
self.props.background_color = 0x000000FF
else:
self.props.background_color = 0x00000000
def _icon_clicked_cb(self, button):
if self._palette:
self._palette.popdown(True)

View File

@ -22,7 +22,7 @@ class MenuItem(gtk.ImageMenuItem):
def __init__(self, text_label, icon_name=None):
gtk.ImageMenuItem.__init__(self, text_label)
if icon_name:
icon = Icon(icon_name, icon_size=gtk.ICON_SIZE_MENU)
icon = Icon(icon_name=icon_name, icon_size=gtk.ICON_SIZE_MENU)
self.set_image(icon)
icon.show()

View File

@ -24,9 +24,9 @@ import hippo
from sugar.activity.bundle import Bundle
from sugar.date import Date
from sugar.graphics import style
from sugar.graphics.canvasicon import CanvasIcon
from sugar.graphics.icon import CanvasIcon
from sugar.graphics.xocolor import XoColor
from sugar.graphics.canvasroundbox import CanvasRoundBox
from sugar.graphics.roundbox import CanvasRoundBox
from sugar.datastore import datastore
from sugar import activity
from sugar.objects import objecttype
@ -150,7 +150,7 @@ class CollapsedEntry(CanvasRoundBox):
self._icon_name = type.icon
if not self._icon_name:
self._icon_name = 'theme:image-missing'
self._icon_name = 'image-missing'
return self._icon_name

View File

@ -31,7 +31,7 @@ class RadioToolButton(gtk.RadioToolButton):
self.set_named_icon(named_icon)
def set_named_icon(self, named_icon):
icon = Icon(named_icon,
icon = Icon(icon_name=named_icon,
xo_color=self._xo_color,
icon_size=gtk.ICON_SIZE_LARGE_TOOLBAR)
self.set_icon_widget(icon)

View File

@ -29,7 +29,7 @@ class ToggleToolButton(gtk.ToggleToolButton):
self.set_named_icon(named_icon)
def set_named_icon(self, named_icon):
icon = Icon(named_icon)
icon = Icon(icon_name=named_icon)
self.set_icon_widget(icon)
icon.show()

View File

@ -33,7 +33,7 @@ class ToolButton(gtk.ToolButton):
self.connect('clicked', self._button_clicked_cb)
def set_icon(self, icon_name):
icon = Icon(icon_name)
icon = Icon(icon_name=icon_name)
self.set_icon_widget(icon)
icon.show()

89
sugar/graphics/tray.py Normal file
View File

@ -0,0 +1,89 @@
# 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.
import gobject
import gtk
from sugar.graphics.toolbutton import ToolButton
from sugar.graphics.icon import Icon
class _TrayViewport(gtk.Viewport):
def __init__(self):
gobject.GObject.__init__(self)
self.set_shadow_type(gtk.SHADOW_NONE)
self.traybar = gtk.Toolbar()
self.traybar.set_show_arrow(False)
self.add(self.traybar)
self.traybar.show()
def scroll_right(self):
adj = self.get_hadjustment()
new_value = adj.value + self.allocation.width
adj.value = min(new_value, adj.upper - self.allocation.width)
def scroll_left(self):
adj = self.get_hadjustment()
new_value = adj.value - self.allocation.width
adj.value = max(adj.lower, new_value)
class HTray(gtk.HBox):
def __init__(self, **kwargs):
gobject.GObject.__init__(self, **kwargs)
self._scroll_left = gtk.Button()
self._scroll_left.set_relief(gtk.RELIEF_NONE)
self._scroll_left.connect('clicked', self._scroll_left_cb)
icon = Icon(icon_name='go-left', icon_size=gtk.ICON_SIZE_MENU)
self._scroll_left.set_image(icon)
icon.show()
self.pack_start(self._scroll_left, False)
self._scroll_left.show()
self._viewport = _TrayViewport()
self.pack_start(self._viewport)
self._viewport.show()
self._scroll_right = gtk.Button()
self._scroll_right.set_relief(gtk.RELIEF_NONE)
self._scroll_right.connect('clicked', self._scroll_right_cb)
icon = Icon(icon_name='go-right', icon_size=gtk.ICON_SIZE_MENU)
self._scroll_right.set_image(icon)
icon.show()
self.pack_start(self._scroll_right, False)
self._scroll_right.show()
def _scroll_left_cb(self, button):
self._viewport.scroll_left()
def _scroll_right_cb(self, button):
self._viewport.scroll_right()
def add_item(self, item, index=-1):
self._viewport.traybar.insert(item, index)
def remove_item(self, index):
self._viewport.traybar.remove(item)
class TrayButton(ToolButton):
def __init__(self, **kwargs):
ToolButton.__init__(self, **kwargs)

View File

@ -167,16 +167,17 @@ class Activity(gobject.GObject):
return bus_name, connection, channels
def _leave_cb(self):
# XXX Is this the right thing to do?
"""Callback for async action of leaving shared activity."""
self.emit("joined", False, "left activity")
def _leave_error_cb(self, err):
# XXX We are closing down anyway
"""Callback for error in async leaving of shared activity.
XXX Add logging!"""
pass
def leave(self):
"""Leave this shared activity"""
# FIXME
self._joined = False
self._activity.Leave(reply_handler=self._leave_cb,
error_handler=self._leave_error_cb)

View File

@ -421,7 +421,11 @@ class PresenceService(gobject.GObject):
return self._new_object(owner_op)
def _share_activity_cb(self, activity, op):
"""Notify with GObject event of successful sharing of activity"""
"""Notify with GObject event of successful sharing of activity
op -- full dbus path of the new object, must be
prefixed with either of _PS_BUDDY_OP or _PS_ACTIVITY_OP
"""
psact = self._new_object(op)
psact._joined = True
self.emit("activity-shared", True, psact, None)
@ -431,10 +435,10 @@ class PresenceService(gobject.GObject):
_logger.debug("Error sharing activity %s: %s" % (activity.get_id(), err))
self.emit("activity-shared", False, None, err)
def share_activity(self, activity, properties={}):
"""Ask presence service to ask the activity to share itself
def share_activity(self, activity, properties={}, private=True):
"""Ask presence service to ask the activity to share itself publicly.
Uses the ShareActivity method on the service to ask for the
Uses the AdvertiseActivity method on the service to ask for the
sharing of the given activity. Arranges to emit activity-shared
event with:
@ -445,19 +449,33 @@ class PresenceService(gobject.GObject):
returns None
"""
actid = activity.get_id()
_logger.debug('XXXX in share_activity')
# Ensure the activity is not already shared/joined
for obj in self._objcache.values():
if not isinstance(object, Activity):
continue
if obj.props.id == actid or obj.props.joined:
raise RuntimeError("Activity %s is already shared." % actid)
raise RuntimeError("Activity %s is already shared." %
actid)
atype = activity.get_service_name()
name = activity.props.title
self._ps.ShareActivity(actid, atype, name, properties,
reply_handler=lambda *args: self._share_activity_cb(activity, *args),
error_handler=lambda *args: self._share_activity_error_cb(activity, *args))
if private:
_logger.debug('XXXX private, so calling InviteActivity')
self._ps.InviteActivity(actid, atype, name, properties,
reply_handler=lambda *args: \
self._share_activity_cb(activity, *args),
error_handler=lambda *args: \
self._share_activity_error_cb(activity, *args))
else:
# FIXME: Test, then make this AdvertiseActivity:
_logger.debug('XXXX not private, so calling ShareActivity')
self._ps.ShareActivity(actid, atype, name, properties,
reply_handler=lambda *args: \
self._share_activity_cb(activity, *args),
error_handler=lambda *args: \
self._share_activity_error_cb(activity, *args))
def get_preferred_connection(self):
"""Gets the preferred telepathy connection object that an activity

View File

@ -0,0 +1,51 @@
# 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.
"""
Test the sugar.graphics.icon.Icon widget.
"""
import gtk
from sugar.graphics.icon import Icon
from sugar.graphics.xocolor import XoColor
import common
test = common.Test()
icon = Icon(icon_name='go-previous')
icon.props.icon_size = gtk.ICON_SIZE_LARGE_TOOLBAR
test.pack_start(icon)
icon.show()
icon = Icon(icon_name='computer-xo',
icon_size=gtk.ICON_SIZE_LARGE_TOOLBAR,
xo_color=XoColor())
test.pack_start(icon)
icon.show()
icon = Icon(icon_name='battery-000',
icon_size=gtk.ICON_SIZE_LARGE_TOOLBAR,
badge_name='badge-busy')
test.pack_start(icon)
icon.show()
test.show()
if __name__ == "__main__":
common.main(test)

50
tests/graphics/tray.py Normal file
View File

@ -0,0 +1,50 @@
# 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.
"""
Test the sugar.graphics.icon.Icon widget.
"""
import gtk
from sugar.graphics.tray import HTray
from sugar.graphics.tray import TrayButton
import common
test = common.Test()
box = gtk.VBox()
tray = HTray()
box.pack_start(tray, False)
tray.show()
theme_icons = gtk.icon_theme_get_default().list_icons()
for i in range(0, 100):
button = TrayButton(icon_name=theme_icons[i])
tray.add_item(button)
button.show()
test.pack_start(box)
box.show()
test.show()
if __name__ == "__main__":
common.main(test)