Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/sugar
diff options
context:
space:
mode:
authorMarco Pesenti Gritti <mpg@redhat.com>2007-10-16 09:04:59 (GMT)
committer Marco Pesenti Gritti <mpg@redhat.com>2007-10-16 09:04:59 (GMT)
commit6240c1cf6fbd47da6743d4a66ebee21cf07fa6a5 (patch)
tree2c5276f5c820d2b5174bcc95cd15328adc98d7be /sugar
parent087856f23317537dbc6b112564c64db68601410e (diff)
Cleanup the source structure
Diffstat (limited to 'sugar')
-rw-r--r--sugar/.gitignore2
-rw-r--r--sugar/.license1
-rw-r--r--sugar/Makefile.am48
-rw-r--r--sugar/_sugaruiext.defs171
-rw-r--r--sugar/_sugaruiext.override29
-rw-r--r--sugar/_sugaruiextmodule.c48
-rw-r--r--sugar/activity/Makefile.am9
-rw-r--r--sugar/activity/__init__.py58
-rw-r--r--sugar/activity/__init__py0
-rw-r--r--sugar/activity/activity.py633
-rw-r--r--sugar/activity/activityfactory.py256
-rw-r--r--sugar/activity/activityhandle.py68
-rw-r--r--sugar/activity/activityservice.py66
-rw-r--r--sugar/activity/bundlebuilder.py403
-rw-r--r--sugar/activity/registry.py156
-rw-r--r--sugar/bundle/Makefile.am6
-rw-r--r--sugar/bundle/__init__.py16
-rw-r--r--sugar/bundle/activitybundle.py285
-rw-r--r--sugar/bundle/bundle.py146
-rw-r--r--sugar/bundle/contentbundle.py189
-rw-r--r--sugar/clipboard/Makefile.am5
-rw-r--r--sugar/clipboard/__init__.py22
-rw-r--r--sugar/clipboard/clipboardservice.py229
-rw-r--r--sugar/datastore/Makefile.am5
-rw-r--r--sugar/datastore/__init__.py16
-rw-r--r--sugar/datastore/datastore.py307
-rw-r--r--sugar/datastore/dbus_helpers.py99
-rw-r--r--sugar/env.py93
-rw-r--r--sugar/graphics/Makefile.am26
-rw-r--r--sugar/graphics/__init__.py18
-rw-r--r--sugar/graphics/alert.py230
-rw-r--r--sugar/graphics/animator.py94
-rw-r--r--sugar/graphics/combobox.py114
-rw-r--r--sugar/graphics/entry.py25
-rw-r--r--sugar/graphics/icon.py504
-rw-r--r--sugar/graphics/iconentry.py45
-rw-r--r--sugar/graphics/menuitem.py28
-rw-r--r--sugar/graphics/notebook.py115
-rw-r--r--sugar/graphics/objectchooser.py209
-rw-r--r--sugar/graphics/palette.py722
-rw-r--r--sugar/graphics/palettegroup.py90
-rw-r--r--sugar/graphics/panel.py23
-rw-r--r--sugar/graphics/radiotoolbutton.py67
-rw-r--r--sugar/graphics/roundbox.py66
-rw-r--r--sugar/graphics/spreadlayout.py239
-rw-r--r--sugar/graphics/style.py147
-rw-r--r--sugar/graphics/toggletoolbutton.py63
-rw-r--r--sugar/graphics/toolbox.py91
-rw-r--r--sugar/graphics/toolbutton.py71
-rw-r--r--sugar/graphics/toolcombobox.py59
-rw-r--r--sugar/graphics/tray.py241
-rw-r--r--sugar/graphics/window.py84
-rw-r--r--sugar/graphics/xocolor.py255
-rw-r--r--sugar/network.py575
-rw-r--r--sugar/objects/Makefile.am5
-rw-r--r--sugar/objects/__init__.py16
-rw-r--r--sugar/objects/objecttype.py79
-rw-r--r--sugar/presence/Makefile.am8
-rw-r--r--sugar/presence/__init__.py24
-rw-r--r--sugar/presence/activity.py290
-rw-r--r--sugar/presence/buddy.py225
-rw-r--r--sugar/presence/presenceservice.py570
-rw-r--r--sugar/presence/test_presence.txt26
-rw-r--r--sugar/presence/tubeconn.py107
-rw-r--r--sugar/profile.py199
-rw-r--r--sugar/util.py175
-rw-r--r--sugar/wm.py38
67 files changed, 0 insertions, 9329 deletions
diff --git a/sugar/.gitignore b/sugar/.gitignore
deleted file mode 100644
index 191b96c..0000000
--- a/sugar/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-_sugarext.c
-_sugaruiext.c
diff --git a/sugar/.license b/sugar/.license
deleted file mode 100644
index 6989ebe..0000000
--- a/sugar/.license
+++ /dev/null
@@ -1 +0,0 @@
-LGPL
diff --git a/sugar/Makefile.am b/sugar/Makefile.am
deleted file mode 100644
index 0f5da84..0000000
--- a/sugar/Makefile.am
+++ /dev/null
@@ -1,48 +0,0 @@
-SUBDIRS = activity bundle clipboard graphics objects presence datastore
-
-sugardir = $(pythondir)/sugar
-sugar_PYTHON = \
- env.py \
- network.py \
- profile.py \
- util.py \
- wm.py
-
-pkgpyexecdir = $(pythondir)/sugar
-
-pkgpyexec_LTLIBRARIES = _sugaruiext.la
-
-_sugaruiext_la_CFLAGS = \
- $(LIBUI_CFLAGS) \
- $(LIBUI_BINDINGS_CFLAGS) \
- $(PYTHON_INCLUDES) \
- -I$(top_srcdir)/lib
-
-_sugaruiext_la_LDFLAGS = -module -avoid-version
-_sugaruiext_la_LIBADD = \
- $(LIBUI_BINDINGS_LIBS) \
- $(LIBUI_LIBS) \
- $(top_builddir)/lib/libsugarui.la
-
-_sugaruiext_la_SOURCES = \
- _sugaruiextmodule.c
-
-nodist__sugaruiext_la_SOURCES = _sugaruiext.c
-
-_sugaruiext.c: _sugaruiext.defs _sugaruiext.override
-
-CLEANFILES = _sugaruiext.c
-
-EXTRA_DIST = \
- _sugaruiext.defs \
- _sugaruiext.override
-
-.defs.c:
- (cd $(srcdir)\
- && $(PYGTK_CODEGEN) \
- --register $(PYGTK_DEFSDIR)/gdk-types.defs \
- --register $(PYGTK_DEFSDIR)/gtk-types.defs \
- --override $*.override \
- --prefix py$* $*.defs) > gen-$*.c \
- && cp gen-$*.c $*.c \
- && rm -f gen-$*.c
diff --git a/sugar/_sugaruiext.defs b/sugar/_sugaruiext.defs
deleted file mode 100644
index 6a9129d..0000000
--- a/sugar/_sugaruiext.defs
+++ /dev/null
@@ -1,171 +0,0 @@
-;; -*- scheme -*-
-; object definitions
-
-(define-object AddressEntry
- (in-module "Sugar")
- (parent "GtkEntry")
- (c-name "SugarAddressEntry")
- (gtype-id "SUGAR_TYPE_ADDRESS_ENTRY")
-)
-
-(define-object KeyGrabber
- (in-module "Sugar")
- (parent "GObject")
- (c-name "SugarKeyGrabber")
- (gtype-id "SUGAR_TYPE_KEY_GRABBER")
-)
-
-(define-object Menu
- (in-module "Sugar")
- (parent "GtkMenu")
- (c-name "SugarMenu")
- (gtype-id "SUGAR_TYPE_MENU")
-)
-
-(define-object IconEntry
- (in-module "Sexy")
- (parent "GtkEntry")
- (c-name "SexyIconEntry")
- (gtype-id "SEXY_TYPE_ICON_ENTRY")
-)
-
-;; Enumerations and flags ...
-
-(define-enum IconEntryPosition
- (in-module "Sexy")
- (c-name "SexyIconEntryPosition")
- (gtype-id "SEXY_TYPE_ICON_ENTRY_POSITION")
- (values
- '("primary" "SEXY_ICON_ENTRY_PRIMARY")
- '("secondary" "SEXY_ICON_ENTRY_SECONDARY")
- )
-)
-
-;; From sugar-menu.h
-
-(define-method set_active
- (of-object "SugarMenu")
- (c-name "sugar_menu_set_active")
- (return-type "none")
- (parameters
- '("gboolean" "active")
- )
-)
-
-(define-method embed
- (of-object "SugarMenu")
- (c-name "sugar_menu_embed")
- (return-type "none")
- (parameters
- '("GtkContainer" "container")
- )
-)
-
-(define-method unembed
- (of-object "SugarMenu")
- (c-name "sugar_menu_unembed")
- (return-type "none")
-)
-
-;; From sugar-key-grabber.h
-
-(define-function sugar_key_grabber_get_type
- (c-name "sugar_key_grabber_get_type")
- (return-type "GType")
-)
-
-(define-method grab
- (of-object "SugarKeyGrabber")
- (c-name "sugar_key_grabber_grab")
- (return-type "none")
- (parameters
- '("const-char*" "key")
- )
-)
-
-(define-method get_key
- (of-object "SugarKeyGrabber")
- (c-name "sugar_key_grabber_get_key")
- (return-type "char*")
- (parameters
- '("guint" "keycode")
- '("guint" "state")
- )
-)
-; functions
-
-(define-function x11_set_string_property
- (c-name "sugar_x11_util_set_string_property")
- (parameters
- '("GdkWindow*" "window")
- '("const-char*" "property")
- '("const-char*" "value")
- )
-)
-
-(define-function x11_get_string_property
- (c-name "sugar_x11_util_get_string_property")
- (return-type "char*")
- (parameters
- '("GdkWindow*" "window")
- '("const-char*" "property")
- )
-)
-
-;; From sexy-icon-entry.h
-
-(define-function sexy_icon_entry_get_type
- (c-name "sexy_icon_entry_get_type")
- (return-type "GType")
-)
-
-(define-function sexy_icon_entry_new
- (c-name "sexy_icon_entry_new")
- (is-constructor-of "SexyIconEntry")
- (return-type "GtkWidget*")
-)
-
-(define-method set_icon
- (of-object "SexyIconEntry")
- (c-name "sexy_icon_entry_set_icon")
- (return-type "none")
- (parameters
- '("SexyIconEntryPosition" "position")
- '("GtkImage*" "icon")
- )
-)
-
-(define-method set_icon_highlight
- (of-object "SexyIconEntry")
- (c-name "sexy_icon_entry_set_icon_highlight")
- (return-type "none")
- (parameters
- '("SexyIconEntryPosition" "position")
- '("gboolean" "highlight")
- )
-)
-
-(define-method get_icon
- (of-object "SexyIconEntry")
- (c-name "sexy_icon_entry_get_icon")
- (return-type "GtkImage*")
- (parameters
- '("SexyIconEntryPosition" "position")
- )
-)
-
-(define-method get_icon_highlight
- (of-object "SexyIconEntry")
- (c-name "sexy_icon_entry_get_icon_highlight")
- (return-type "gboolean")
- (parameters
- '("SexyIconEntryPosition" "position")
- )
-)
-
-(define-method add_clear_button
- (of-object "SexyIconEntry")
- (c-name "sexy_icon_entry_add_clear_button")
- (return-type "none")
-)
-
diff --git a/sugar/_sugaruiext.override b/sugar/_sugaruiext.override
deleted file mode 100644
index beeaad0..0000000
--- a/sugar/_sugaruiext.override
+++ /dev/null
@@ -1,29 +0,0 @@
-/* -*- Mode: C; c-basic-offset: 4 -*- */
-%%
-headers
-#include <Python.h>
-
-#include "pygobject.h"
-#include "sugar-address-entry.h"
-#include "sugar-key-grabber.h"
-#include "sugar-menu.h"
-#include "sugar-x11-util.h"
-#include "sexy-icon-entry.h"
-
-#include <pygtk/pygtk.h>
-#include <glib.h>
-
-%%
-modulename _sugarext
-%%
-import gobject.GObject as PyGObject_Type
-import gtk.Entry as PyGtkEntry_Type
-import gtk.Menu as PyGtkMenu_Type
-import gtk.Container as PyGtkContainer_Type
-import gtk.gdk.Window as PyGdkWindow_Type
-import gtk.Image as PyGtkImage_Type
-%%
-ignore-glob
- *_get_type
- _*
-%%
diff --git a/sugar/_sugaruiextmodule.c b/sugar/_sugaruiextmodule.c
deleted file mode 100644
index 719b153..0000000
--- a/sugar/_sugaruiextmodule.c
+++ /dev/null
@@ -1,48 +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.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-/* include this first, before NO_IMPORT_PYGOBJECT is defined */
-#include <pygobject.h>
-
-extern PyMethodDef py_sugaruiext_functions[];
-
-void py_sugaruiext_register_classes (PyObject *d);
-void py_sugaruiext_add_constants (PyObject *module, const gchar *strip_prefix);
-
-DL_EXPORT(void)
-init_sugaruiext(void)
-{
- PyObject *m, *d;
-
- init_pygobject ();
-
- m = Py_InitModule ("_sugaruiext", py_sugaruiext_functions);
- d = PyModule_GetDict (m);
-
- py_sugaruiext_register_classes (d);
- py_sugaruiext_add_constants(m, "SEXY_");
-
- if (PyErr_Occurred ()) {
- Py_FatalError ("can't initialise module _sugaruiext");
- }
-}
diff --git a/sugar/activity/Makefile.am b/sugar/activity/Makefile.am
deleted file mode 100644
index 9dfc8de..0000000
--- a/sugar/activity/Makefile.am
+++ /dev/null
@@ -1,9 +0,0 @@
-sugardir = $(pythondir)/sugar/activity
-sugar_PYTHON = \
- __init__.py \
- activity.py \
- activityfactory.py \
- activityhandle.py \
- activityservice.py \
- bundlebuilder.py \
- registry.py
diff --git a/sugar/activity/__init__.py b/sugar/activity/__init__.py
deleted file mode 100644
index 8a984ad..0000000
--- a/sugar/activity/__init__.py
+++ /dev/null
@@ -1,58 +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.
-
-"""Activity implementation code for Sugar-based activities
-
-Each activity within the OLPC environment must provide two
-dbus services. The first, patterned after the
-
- sugar.activity.activityfactory.ActivityFactory
-
-class is responsible for providing a "create" method which
-takes a small dictionary with values corresponding to a
-
- sugar.activity.activityhandle.ActivityHandle
-
-describing an individual instance of the activity.
-
-Each activity so registered is described by a
-
- sugar.activity.bundle.Bundle
-
-instance, which parses a specially formatted activity.info
-file (stored in the activity directory's ./activity
-subdirectory). The
-
- sugar.activity.bundlebuilder
-
-module provides facilities for the standard setup.py module
-which produces and registers bundles from activity source
-directories.
-
-Once instantiated by the ActivityFactory's create method,
-each activity must provide an introspection API patterned
-after the
-
- sugar.activity.activityservice.ActivityService
-
-class. This class allows for querying the ID of the root
-window, requesting sharing across the network, and basic
-"what type of application are you" queries.
-"""
-from sugar.activity.registry import ActivityRegistry
-from sugar.activity.registry import get_registry
-from sugar.activity.registry import ActivityInfo
diff --git a/sugar/activity/__init__py b/sugar/activity/__init__py
deleted file mode 100644
index e69de29..0000000
--- a/sugar/activity/__init__py
+++ /dev/null
diff --git a/sugar/activity/activity.py b/sugar/activity/activity.py
deleted file mode 100644
index c581c15..0000000
--- a/sugar/activity/activity.py
+++ /dev/null
@@ -1,633 +0,0 @@
-"""Base class for Python-coded activities
-
-This is currently the only reference for what an
-activity must do to participate in the Sugar desktop.
-"""
-# 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.
-
-from gettext import gettext as _
-import logging
-import os
-import time
-import tempfile
-from hashlib import sha1
-
-import gtk, gobject
-import dbus
-import json
-
-from sugar import util
-from sugar.presence import presenceservice
-from sugar.activity.activityservice import ActivityService
-from sugar.graphics import style
-from sugar.graphics.window import Window
-from sugar.graphics.toolbox import Toolbox
-from sugar.graphics.toolbutton import ToolButton
-from sugar.graphics.toolcombobox import ToolComboBox
-from sugar.datastore import datastore
-from sugar import wm
-from sugar import profile
-from sugar import _sugarbaseext
-
-SCOPE_PRIVATE = "private"
-SCOPE_INVITE_ONLY = "invite" # shouldn't be shown in UI, it's implicit when you invite somebody
-SCOPE_NEIGHBORHOOD = "public"
-
-class ActivityToolbar(gtk.Toolbar):
- def __init__(self, activity):
- gtk.Toolbar.__init__(self)
-
- self._activity = activity
- self._updating_share = False
-
- activity.connect('shared', self._activity_shared_cb)
- activity.connect('joined', self._activity_shared_cb)
- activity.connect('notify::max_participants',
- self._max_participants_changed_cb)
-
- if activity.metadata:
- self.title = gtk.Entry()
- self.title.set_size_request(int(gtk.gdk.screen_width() / 6), -1)
- self.title.set_text(activity.metadata['title'])
- self.title.connect('changed', self._title_changed_cb)
- self._add_widget(self.title)
-
- activity.metadata.connect('updated', self._jobject_updated_cb)
-
- separator = gtk.SeparatorToolItem()
- separator.props.draw = False
- separator.set_expand(True);
- self.insert(separator, -1)
- separator.show()
-
- self.share = ToolComboBox(label_text=_('Share with:'))
- self.share.combo.connect('changed', self._share_changed_cb)
- self.share.combo.append_item(SCOPE_PRIVATE, _('Private'),
- 'zoom-home-mini')
- self.share.combo.append_item(SCOPE_NEIGHBORHOOD, _('My Neighborhood'),
- 'zoom-neighborhood-mini')
- self.insert(self.share, -1)
- self.share.show()
-
- self._update_share()
-
- self.keep = ToolButton('document-save')
- self.keep.set_tooltip(_('Keep'))
- self.keep.connect('clicked', self._keep_clicked_cb)
- self.insert(self.keep, -1)
- self.keep.show()
-
- self.stop = ToolButton('activity-stop')
- self.stop.set_tooltip(_('Stop'))
- self.stop.connect('clicked', self._stop_clicked_cb)
- self.insert(self.stop, -1)
- self.stop.show()
-
- self._update_title_sid = None
-
- def _update_share(self):
- self._updating_share = True
-
- if self._activity.props.max_participants == 1:
- self.share.hide()
-
- if self._activity.get_shared():
- self.share.set_sensitive(False)
- self.share.combo.set_active(1)
- else:
- self.share.set_sensitive(True)
- self.share.combo.set_active(0)
-
- self._updating_share = False
-
- def _share_changed_cb(self, combo):
- if self._updating_share:
- return
-
- model = self.share.combo.get_model()
- it = self.share.combo.get_active_iter()
- (scope, ) = model.get(it, 0)
- if scope == SCOPE_NEIGHBORHOOD:
- self._activity.share()
-
- def _keep_clicked_cb(self, button):
- self._activity.copy()
-
- def _stop_clicked_cb(self, button):
- self._activity.close()
-
- def _jobject_updated_cb(self, jobject):
- self.title.set_text(jobject['title'])
-
- def _title_changed_cb(self, entry):
- if not self._update_title_sid:
- self._update_title_sid = gobject.timeout_add(1000, self._update_title_cb)
-
- def _update_title_cb(self):
- title = self.title.get_text()
-
- self._activity.metadata['title'] = title
- self._activity.metadata['title_set_by_user'] = '1'
- self._activity.save()
-
- shared_activity = self._activity._shared_activity
- if shared_activity:
- shared_activity.props.name = title
-
- self._update_title_sid = None
- return False
-
- def _add_widget(self, widget, expand=False):
- tool_item = gtk.ToolItem()
- tool_item.set_expand(expand)
-
- tool_item.add(widget)
- widget.show()
-
- self.insert(tool_item, -1)
- tool_item.show()
-
- def _activity_shared_cb(self, activity):
- self._update_share()
-
- def _max_participants_changed_cb(self, activity, pspec):
- self._update_share()
-
-class EditToolbar(gtk.Toolbar):
- def __init__(self):
- gtk.Toolbar.__init__(self)
-
- self.undo = ToolButton('edit-undo')
- self.undo.set_tooltip(_('Undo'))
- self.insert(self.undo, -1)
- self.undo.show()
-
- self.redo = ToolButton('edit-redo')
- self.redo.set_tooltip(_('Redo'))
- self.insert(self.redo, -1)
- self.redo.show()
-
- self.separator = gtk.SeparatorToolItem()
- self.separator.set_draw(True)
- self.insert(self.separator, -1)
- self.separator.show()
-
- self.copy = ToolButton('edit-copy')
- self.copy.set_tooltip(_('Copy'))
- self.insert(self.copy, -1)
- self.copy.show()
-
- self.paste = ToolButton('edit-paste')
- self.paste.set_tooltip(_('Paste'))
- self.insert(self.paste, -1)
- self.paste.show()
-
-class ActivityToolbox(Toolbox):
- def __init__(self, activity):
- Toolbox.__init__(self)
-
- self._activity_toolbar = ActivityToolbar(activity)
- self.add_toolbar('Activity', self._activity_toolbar)
- self._activity_toolbar.show()
-
- def get_activity_toolbar(self):
- return self._activity_toolbar
-
-class Activity(Window, gtk.Container):
- """Base Activity class that all other Activities derive from."""
- __gtype_name__ = 'SugarActivity'
-
- __gsignals__ = {
- 'shared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
- 'joined': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([]))
- }
-
- __gproperties__ = {
- 'active' : (bool, None, None, False,
- gobject.PARAM_READWRITE),
- 'max-participants': (int, None, None, 0, 1000, 0,
- gobject.PARAM_READWRITE)
- }
-
- def __init__(self, handle, create_jobject=True):
- """Initialise the Activity
-
- handle -- sugar.activity.activityhandle.ActivityHandle
- instance providing the activity id and access to the
- presence service which *may* provide sharing for this
- application
-
- create_jobject -- boolean
- define if it should create a journal object if we are
- not resuming
-
- Side effects:
-
- Sets the gdk screen DPI setting (resolution) to the
- Sugar screen resolution.
-
- Connects our "destroy" message to our _destroy_cb
- method.
-
- Creates a base gtk.Window within this window.
-
- Creates an ActivityService (self._bus) servicing
- this application.
- """
- Window.__init__(self)
-
- # process titles will only show 15 characters
- # but they get truncated anyway so if more characters
- # are supported in the future we will get a better view
- # of the processes
- proc_title = "%s <%s>" % (get_bundle_name(), handle.activity_id)
- util.set_proc_title(proc_title)
-
- self.connect('realize', self._realize_cb)
- self.connect('delete-event', self.__delete_event_cb)
-
- self._active = False
- self._activity_id = handle.activity_id
- self._pservice = presenceservice.get_instance()
- self._shared_activity = None
- self._share_id = None
- self._join_id = None
- self._preview = None
- self._updating_jobject = False
- self._closing = False
- self._deleting = False
- self._max_participants = 0
- self._invites_queue = []
-
- self._bus = ActivityService(self)
- self._owns_file = False
-
- share_scope = SCOPE_PRIVATE
-
- if handle.object_id:
- self._jobject = datastore.get(handle.object_id)
- # TODO: Don't create so many objects until we have versioning
- # support in the datastore
- #self._jobject.object_id = ''
- #del self._jobject.metadata['ctime']
- del self._jobject.metadata['mtime']
-
- self.set_title(self._jobject.metadata['title'])
-
- if self._jobject.metadata.has_key('share-scope'):
- share_scope = self._jobject.metadata['share-scope']
-
- elif create_jobject:
- logging.debug('Creating a jobject.')
- self._jobject = datastore.create()
- self._jobject.metadata['title'] = _('%s Activity') % get_bundle_name()
- self.set_title(self._jobject.metadata['title'])
- self._jobject.metadata['title_set_by_user'] = '0'
- self._jobject.metadata['activity'] = self.get_bundle_id()
- self._jobject.metadata['activity_id'] = self.get_id()
- self._jobject.metadata['keep'] = '0'
- self._jobject.metadata['preview'] = ''
- self._jobject.metadata['share-scope'] = SCOPE_PRIVATE
-
- if self._shared_activity is not None:
- icon_color = self._shared_activity.props.color
- else:
- icon_color = profile.get_color().to_string()
-
- self._jobject.metadata['icon-color'] = icon_color
-
- self._jobject.file_path = ''
- datastore.write(self._jobject,
- reply_handler=self._internal_jobject_create_cb,
- error_handler=self._internal_jobject_error_cb)
- else:
- self._jobject = None
-
- # handle activity share/join
- mesh_instance = self._pservice.get_activity(self._activity_id)
- logging.debug("*** Act %s, mesh instance %r, scope %s" % (self._activity_id, mesh_instance, share_scope))
- if mesh_instance:
- # There's already an instance on the mesh, join it
- logging.debug("*** Act %s joining existing mesh instance" % self._activity_id)
- self._shared_activity = mesh_instance
- self._shared_activity.connect('notify::private',
- self._privacy_changed_cb)
- self._join_id = self._shared_activity.connect("joined", self._internal_joined_cb)
- if not self._shared_activity.props.joined:
- self._shared_activity.join()
- else:
- self._internal_joined_cb(self._shared_activity, True, None)
- elif share_scope != SCOPE_PRIVATE:
- logging.debug("*** Act %s no existing mesh instance, but used to be shared, will share" % self._activity_id)
- # no existing mesh instance, but activity used to be shared, so
- # restart the share
- if share_scope == SCOPE_INVITE_ONLY:
- self.share(private=True)
- elif share_scope == SCOPE_NEIGHBORHOOD:
- self.share(private=False)
- else:
- logging.debug("Unknown share scope %r" % share_scope)
-
- def do_set_property(self, pspec, value):
- if pspec.name == 'active':
- if self._active != value:
- self._active = value
- if not self._active and self._jobject:
- self.save()
- elif pspec.name == 'max-participants':
- self._max_participants = value
-
- def do_get_property(self, pspec):
- if pspec.name == 'active':
- return self._active
- elif pspec.name == 'max-participants':
- return self._max_participants
-
- def get_id(self):
- return self._activity_id
-
- def get_bundle_id(self):
- return _sugarbaseext.get_prgname()
-
- def set_canvas(self, canvas):
- Window.set_canvas(self, canvas)
- canvas.connect('map', self._canvas_map_cb)
-
- def _canvas_map_cb(self, canvas):
- if self._jobject and self._jobject.file_path:
- self.read_file(self._jobject.file_path)
-
- def _internal_jobject_create_cb(self):
- pass
-
- def _internal_jobject_error_cb(self, err):
- logging.debug("Error creating activity datastore object: %s" % err)
-
- def get_activity_root(self):
- """
- Return the appropriate location in the fs where to store activity related
- data that doesn't pertain to the current execution of the activity and
- thus cannot go into the DataStore.
- """
- if os.environ.has_key('SUGAR_ACTIVITY_ROOT') and \
- os.environ['SUGAR_ACTIVITY_ROOT']:
- return os.environ['SUGAR_ACTIVITY_ROOT']
- else:
- return '/'
-
- def read_file(self, file_path):
- """
- Subclasses implement this method if they support resuming objects from
- the journal. 'file_path' is the file to read from.
- """
- raise NotImplementedError
-
- def write_file(self, file_path):
- """
- Subclasses implement this method if they support saving data to objects
- in the journal. 'file_path' is the file to write to.
- """
- raise NotImplementedError
-
- def _internal_save_cb(self):
- logging.debug('Activity._internal_save_cb')
- self._updating_jobject = False
- if self._closing:
- self._cleanup_jobject()
- self.destroy()
-
- def _internal_save_error_cb(self, err):
- logging.debug('Activity._internal_save_error_cb')
- self._updating_jobject = False
- if self._closing:
- self._cleanup_jobject()
- self.destroy()
- logging.debug("Error saving activity object to datastore: %s" % err)
-
- def _cleanup_jobject(self):
- if self._jobject:
- if self._owns_file and os.path.isfile(self._jobject.file_path):
- logging.debug('_cleanup_jobject: removing %r' % self._jobject.file_path)
- os.remove(self._jobject.file_path)
- self._owns_file = False
- self._jobject.destroy()
- self._jobject = None
-
- def _get_preview(self):
- preview_pixbuf = self.get_canvas_screenshot()
- if preview_pixbuf is None:
- return None
- preview_pixbuf = preview_pixbuf.scale_simple(style.zoom(300),
- style.zoom(225),
- gtk.gdk.INTERP_BILINEAR)
-
- # TODO: Find a way of taking a png out of the pixbuf without saving to a temp file.
- # Impementing gtk.gdk.Pixbuf.save_to_buffer in pygtk would solve this.
- fd, file_path = tempfile.mkstemp('.png')
- del fd
- preview_pixbuf.save(file_path, 'png')
- f = open(file_path)
- try:
- preview_data = f.read()
- finally:
- f.close()
- os.remove(file_path)
-
- return preview_data
-
- def _get_buddies(self):
- if self._shared_activity is not None:
- buddies = {}
- for buddy in self._shared_activity.get_joined_buddies():
- if not buddy.props.owner:
- buddy_id = sha1(buddy.props.key).hexdigest()
- buddies[buddy_id] = [buddy.props.nick, buddy.props.color]
- return buddies
- else:
- return {}
-
- def save(self):
- """Request that the activity is saved to the Journal."""
-
- logging.debug('Activity.save: %r' % self._jobject.object_id)
-
- if self._updating_jobject:
- logging.info('Activity.save: still processing a previous request.')
- return
-
- buddies_dict = self._get_buddies()
- if buddies_dict:
- self.metadata['buddies_id'] = json.write(buddies_dict.keys())
- self.metadata['buddies'] = json.write(self._get_buddies())
-
- if self._preview is None:
- self.metadata['preview'] = ''
- else:
- self.metadata['preview'] = dbus.ByteArray(self._preview)
-
- try:
- if self._jobject.file_path:
- self.write_file(self._jobject.file_path)
- else:
- file_path = os.path.join(tempfile.gettempdir(), '%i' % time.time())
- self.write_file(file_path)
- self._owns_file = True
- self._jobject.file_path = file_path
- except NotImplementedError:
- pass
-
- # Cannot call datastore.write async for creates: https://dev.laptop.org/ticket/3071
- if self._jobject.object_id is None:
- datastore.write(self._jobject, transfer_ownership=True)
- else:
- self._updating_jobject = True
- datastore.write(self._jobject,
- transfer_ownership=True,
- reply_handler=self._internal_save_cb,
- error_handler=self._internal_save_error_cb)
-
- def copy(self):
- logging.debug('Activity.copy: %r' % self._jobject.object_id)
- self._preview = self._get_preview()
- self.save()
- self._jobject.object_id = None
-
- def _privacy_changed_cb(self, shared_activity, param_spec):
- if shared_activity.props.private:
- self._jobject.metadata['share-scope'] = SCOPE_INVITE_ONLY
- else:
- self._jobject.metadata['share-scope'] = SCOPE_NEIGHBORHOOD
-
- def _internal_joined_cb(self, activity, success, err):
- """Callback when join has finished"""
- self._shared_activity.disconnect(self._join_id)
- self._join_id = None
- if not success:
- logging.debug("Failed to join activity: %s" % err)
- return
-
- self.present()
- self.emit('joined')
- self._privacy_changed_cb(self._shared_activity, None)
-
- def get_shared(self):
- """Returns TRUE if the activity is shared on the mesh."""
- if not self._shared_activity:
- return False
- return self._shared_activity.props.joined
-
- def _internal_share_cb(self, ps, success, activity, err):
- self._pservice.disconnect(self._share_id)
- self._share_id = None
- if not success:
- logging.debug('Share of activity %s failed: %s.' % (self._activity_id, err))
- return
-
- logging.debug('Share of activity %s successful.' % self._activity_id)
-
- activity.props.name = self._jobject.metadata['title']
-
- self._shared_activity = activity
- self._shared_activity.connect('notify::private',
- self._privacy_changed_cb)
- self.emit('shared')
- self._privacy_changed_cb(self._shared_activity, None)
-
- self._send_invites()
-
- def _invite_response_cb(self, error):
- if error:
- logging.error('Invite failed: %s' % error)
-
- def _send_invites(self):
- while self._invites_queue:
- buddy_key = self._invites_queue.pop()
- buddy = self._pservice.get_buddy(buddy_key)
- if buddy:
- self._shared_activity.invite(buddy, '', self._invite_response_cb)
- else:
- logging.error('Cannot invite %s, no such buddy.' % buddy_key)
-
- def invite(self, buddy_key):
- self._invites_queue.append(buddy_key)
-
- if (self._shared_activity is None
- or not self._shared_activity.props.joined):
- self.share(True)
- else:
- self._send_invites()
-
- 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.
-
- Once the activity is shared, its privacy can be changed by setting
- its 'private' property.
- """
- # 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)
- 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 close(self):
- self._preview = self._get_preview()
-
- self.save()
-
- if self._shared_activity:
- self._shared_activity.leave()
-
- if self._updating_jobject:
- self._closing = True
- else:
- self.destroy()
-
- def _realize_cb(self, window):
- wm.set_bundle_id(window.window, self.get_bundle_id())
- wm.set_activity_id(window.window, self._activity_id)
-
- def __delete_event_cb(self, widget, event):
- self.close()
- return True
-
- def get_metadata(self):
- if self._jobject:
- return self._jobject.metadata
- else:
- return None
-
- metadata = property(get_metadata, None)
-
-def get_bundle_name():
- """Return the bundle name for the current process' bundle
- """
- return _sugarbaseext.get_application_name()
-
-def get_bundle_path():
- """Return the bundle path for the current process' bundle
- """
- return os.environ['SUGAR_BUNDLE_PATH']
-
diff --git a/sugar/activity/activityfactory.py b/sugar/activity/activityfactory.py
deleted file mode 100644
index ae08ada..0000000
--- a/sugar/activity/activityfactory.py
+++ /dev/null
@@ -1,256 +0,0 @@
-"""Shell side object which manages request to start activity"""
-# 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 subprocess
-
-import dbus
-import gobject
-import gtk
-
-from sugar.presence import presenceservice
-from sugar.activity.activityhandle import ActivityHandle
-from sugar.activity import registry
-from sugar.datastore import datastore
-from sugar import util
-from sugar import env
-
-import os
-
-# #3903 - this constant can be removed and assumed to be 1 when dbus-python
-# 0.82.3 is the only version used
-if dbus.version >= (0, 82, 3):
- DBUS_PYTHON_TIMEOUT_UNITS_PER_SECOND = 1
-else:
- DBUS_PYTHON_TIMEOUT_UNITS_PER_SECOND = 1000
-
-_SHELL_SERVICE = "org.laptop.Shell"
-_SHELL_PATH = "/org/laptop/Shell"
-_SHELL_IFACE = "org.laptop.Shell"
-
-_DS_SERVICE = "org.laptop.sugar.DataStore"
-_DS_INTERFACE = "org.laptop.sugar.DataStore"
-_DS_PATH = "/org/laptop/sugar/DataStore"
-
-_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()
-
- # create a new unique activity ID
- i = 0
- act_id = None
- while i < 10:
- act_id = util.unique_id()
- i += 1
-
- # check through network activities
- found = False
- activities = pservice.get_activities()
- for act in activities:
- if act_id == act.props.id:
- found = True
- break
- if not found:
- return act_id
- raise RuntimeError("Cannot generate unique activity id.")
-
-def get_environment(activity):
- environ = os.environ.copy()
-
- bin_path = os.path.join(activity.path, 'bin')
- environ['SUGAR_BUNDLE_PATH'] = activity.path
- environ['PATH'] = bin_path + ':' + environ['PATH']
-
- return environ
-
-def get_command(activity, activity_id=None, object_id=None, uri=None):
- if not activity_id:
- activity_id = create_activity_id()
-
- command = activity.command
- command += ' -b %s' % activity.bundle_id
- command += ' -a %s' % activity_id
-
- if object_id is not None:
- command += ' -o %s' % object_id
- if uri is not None:
- command += ' -u %s' % uri
-
- return command
-
-def open_log_file(activity, activity_id):
- for i in range(1, 100):
- path = env.get_logs_path('%s-%s.log' % (activity.bundle_id, i))
- if not os.path.exists(path):
- return open(path, 'w')
-
-class ActivityCreationHandler(gobject.GObject):
- """Sugar-side activity creation interface
-
- This object uses a dbus method on the ActivityFactory
- service to create the new activity. It generates
- GObject events in response to the success/failure of
- activity startup using callbacks to the service's
- create call.
- """
-
- def __init__(self, service_name, handle):
- """Initialise the handler
-
- service_name -- the service name of the bundle factory
- activity_handle -- stores the values which are to
- be passed to the service to uniquely identify
- the activity to be created and the sharing
- service that may or may not be connected with it
-
- sugar.activity.activityhandle.ActivityHandle instance
-
- calls the "create" method on the service for this
- particular activity type and registers the
- _reply_handler and _error_handler methods on that
- call's results.
-
- The specific service which creates new instances of this
- 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
- self._handle = handle
-
- bus = dbus.SessionBus()
-
- bus_object = bus.get_object(_SHELL_SERVICE, _SHELL_PATH)
- self._shell = dbus.Interface(bus_object, _SHELL_IFACE)
-
- if handle.activity_id is not None and \
- handle.object_id is None:
- datastore = dbus.Interface(
- bus.get_object(_DS_SERVICE, _DS_PATH), _DS_INTERFACE)
- datastore.find({ 'activity_id': self._handle.activity_id }, [],
- reply_handler=self._find_object_reply_handler,
- error_handler=self._find_object_error_handler)
- else:
- self._launch_activity()
-
- def _launch_activity(self):
- if self._handle.activity_id != None:
- self._shell.ActivateActivity(self._handle.activity_id,
- reply_handler=self._activate_reply_handler,
- error_handler=self._activate_error_handler)
- else:
- self._create_activity()
-
- def _create_activity(self):
- if self._handle.activity_id is None:
- self._handle.activity_id = create_activity_id()
-
- self._shell.NotifyLaunch(
- self._service_name, self._handle.activity_id,
- reply_handler=self._no_reply_handler,
- error_handler=self._notify_launch_error_handler)
-
- if not os.path.exists('/etc/olpc-security'):
- activity_registry = registry.get_registry()
- activity = activity_registry.get_activity(self._service_name)
- if activity:
- env = get_environment(activity)
- log_file = open_log_file(activity, self._handle.activity_id)
- command = get_command(activity, self._handle.activity_id,
- self._handle.object_id,
- self._handle.uri)
- process = subprocess.Popen(command, env=env, shell=True,
- cwd=activity.path, stdout=log_file,
- stderr=log_file)
- else:
- system_bus = dbus.SystemBus()
- factory = system_bus.get_object(_RAINBOW_SERVICE_NAME,
- _RAINBOW_ACTIVITY_FACTORY_PATH)
- stdio_paths = {'stdout': '/logs/stdout', 'stderr': '/logs/stderr'}
- factory.CreateActivity(
- self._service_name,
- self._handle.get_dict(),
- stdio_paths,
- timeout=120 * DBUS_PYTHON_TIMEOUT_UNITS_PER_SECOND,
- reply_handler=self._create_reply_handler,
- error_handler=self._create_error_handler,
- dbus_interface=_RAINBOW_ACTIVITY_FACTORY_INTERFACE)
-
- def _no_reply_handler(self, *args):
- pass
-
- def _notify_launch_failure_error_handler(self, err):
- logging.error('Notify launch failure failed %s' % err)
-
- def _notify_launch_error_handler(self, err):
- logging.debug('Notify launch failed %s' % err)
-
- def _activate_reply_handler(self, activated):
- if not activated:
- self._create_activity()
-
- def _activate_error_handler(self, err):
- logging.error("Activity activation request failed %s" % err)
-
- def _create_reply_handler(self, xid):
- logging.debug("Activity created %s (%s)." %
- (self._handle.activity_id, self._service_name))
-
- def _create_error_handler(self, err):
- logging.error("Couldn't create activity %s (%s): %s" %
- (self._handle.activity_id, self._service_name, err))
- self._shell.NotifyLaunchFailure(
- self._handle.activity_id, reply_handler=self._no_reply_handler,
- error_handler=self._notify_launch_failure_error_handler)
-
- def _find_object_reply_handler(self, jobjects, count):
- if count > 0:
- if count > 1:
- logging.debug("Multiple objects has the same activity_id.")
- self._handle.object_id = jobjects[0]['uid']
- self._create_activity()
-
- def _find_object_error_handler(self, err):
- logging.error("Datastore find failed %s" % err)
- self._create_activity()
-
-def create(service_name, activity_handle=None):
- """Create a new activity from its name."""
- if not activity_handle:
- activity_handle = ActivityHandle()
- return ActivityCreationHandler(service_name, activity_handle)
-
-def create_with_uri(service_name, uri):
- """Create a new activity and pass the uri as handle."""
- activity_handle = ActivityHandle(uri=uri)
- return ActivityCreationHandler(service_name, activity_handle)
-
-def create_with_object_id(service_name, object_id):
- """Create a new activity and pass the object id as handle."""
- activity_handle = ActivityHandle(object_id=object_id)
- return ActivityCreationHandler(service_name, activity_handle)
diff --git a/sugar/activity/activityhandle.py b/sugar/activity/activityhandle.py
deleted file mode 100644
index f91651e..0000000
--- a/sugar/activity/activityhandle.py
+++ /dev/null
@@ -1,68 +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.
-
-from sugar.presence import presenceservice
-
-class ActivityHandle(object):
- """Data structure storing simple activity metadata"""
- def __init__(
- self, activity_id=None, object_id=None, uri=None
- ):
- """Initialise the handle from activity_id
-
- activity_id -- unique id for the activity to be
- created
- object_id -- identity of the journal object
- associated with the activity. It was used by
- the journal prototype implementation, might
- change when we do the real one.
-
- When you resume an activity from the journal
- the object_id will be passed in. It's optional
- since new activities does not have an
- associated object (yet).
-
- XXX Not clear how this relates to the activity
- id yet, i.e. not sure we really need both. TBF
- uri -- URI associated with the activity. Used when
- opening an external file or resource in the
- activity, rather than a journal object
- (downloads stored on the file system for
- example or web pages)
- """
- self.activity_id = activity_id
- self.object_id = object_id
- self.uri = uri
-
- def get_dict(self):
- """Retrieve our settings as a dictionary"""
- result = { 'activity_id' : self.activity_id }
- if self.object_id:
- result['object_id'] = self.object_id
- if self.uri:
- result['uri'] = self.uri
-
- return result
-
-def create_from_dict(handle_dict):
- """Create a handle from a dictionary of parameters"""
- result = ActivityHandle(
- handle_dict['activity_id'],
- object_id = handle_dict.get('object_id'),
- uri = handle_dict.get('uri'),
- )
- return result
diff --git a/sugar/activity/activityservice.py b/sugar/activity/activityservice.py
deleted file mode 100644
index b2f7e15..0000000
--- a/sugar/activity/activityservice.py
+++ /dev/null
@@ -1,66 +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 dbus
-import dbus.service
-
-_ACTIVITY_SERVICE_NAME = "org.laptop.Activity"
-_ACTIVITY_SERVICE_PATH = "/org/laptop/Activity"
-_ACTIVITY_INTERFACE = "org.laptop.Activity"
-
-class ActivityService(dbus.service.Object):
- """Base dbus service object that each Activity uses to export dbus methods.
-
- The dbus service is separate from the actual Activity object so that we can
- tightly control what stuff passes through the dbus python bindings."""
-
- def __init__(self, activity):
- """Initialise the service for the given activity
-
- activity -- sugar.activity.activity.Activity instance
-
- Creates dbus services that use the instance's activity_id
- as discriminants among all active services
- of this type. That is, the services are all available
- as names/paths derived from the instance's activity_id.
-
- The various methods exposed on dbus are just forwarded
- to the client Activity object's equally-named methods.
- """
- activity.realize()
-
- activity_id = activity.get_id()
- service_name = _ACTIVITY_SERVICE_NAME + activity_id
- object_path = _ACTIVITY_SERVICE_PATH + "/" + activity_id
-
- bus = dbus.SessionBus()
- bus_name = dbus.service.BusName(service_name, bus=bus)
- dbus.service.Object.__init__(self, bus_name, object_path)
-
- self._activity = activity
-
- @dbus.service.method(_ACTIVITY_INTERFACE)
- def SetActive(self, active):
- logging.debug('ActivityService.set_active: %s.' % active)
- self._activity.props.active = active
-
- @dbus.service.method(_ACTIVITY_INTERFACE)
- def Invite(self, buddy_key):
- self._activity.invite(buddy_key)
-
diff --git a/sugar/activity/bundlebuilder.py b/sugar/activity/bundlebuilder.py
deleted file mode 100644
index c2e3278..0000000
--- a/sugar/activity/bundlebuilder.py
+++ /dev/null
@@ -1,403 +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 sys
-import os
-import zipfile
-import shutil
-import subprocess
-import re
-import gettext
-
-from sugar import env
-from sugar.bundle.activitybundle import ActivityBundle
-
-class _SvnFileList(list):
- def __init__(self):
- f = os.popen('svn list -R')
- for line in f.readlines():
- filename = line.strip()
- if os.path.isfile(filename):
- self.append(filename)
- f.close()
-
-class _GitFileList(list):
- def __init__(self):
- f = os.popen('git-ls-files')
- for line in f.readlines():
- filename = line.strip()
- if not filename.startswith('.'):
- self.append(filename)
- f.close()
-
-class _DefaultFileList(list):
- def __init__(self):
- for name in os.listdir('activity'):
- if name.endswith('.svg'):
- self.append(os.path.join('activity', name))
-
- self.append('activity/activity.info')
-
- if os.path.isfile(_get_source_path('NEWS')):
- self.append('NEWS')
-
-class _ManifestFileList(_DefaultFileList):
- def __init__(self, manifest):
- _DefaultFileList.__init__(self)
- self.append(manifest)
-
- f = open(manifest,'r')
- for line in f.readlines():
- stripped_line = line.strip()
- if stripped_line and not stripped_line in self:
- self.append(stripped_line)
- f.close()
-
-def _extract_bundle(source_file, dest_dir):
- if not os.path.exists(dest_dir):
- os.mkdir(dest_dir)
-
- zf = zipfile.ZipFile(source_file)
-
- for i, name in enumerate(zf.namelist()):
- path = os.path.join(dest_dir, name)
-
- if not os.path.exists(os.path.dirname(path)):
- os.makedirs(os.path.dirname(path))
-
- outfile = open(path, 'wb')
- outfile.write(zf.read(name))
- outfile.flush()
- outfile.close()
-
-def _get_source_path(path=None):
- if path:
- return os.path.join(os.getcwd(), path)
- else:
- return os.getcwd()
-
-def _get_bundle_dir():
- bundle_name = os.path.basename(_get_source_path())
- return bundle_name + '.activity'
-
-def _get_install_dir(prefix):
- return os.path.join(prefix, 'share/activities')
-
-def _get_package_name(bundle_name):
- bundle = ActivityBundle(_get_source_path())
- zipname = '%s-%d.xo' % (bundle_name, bundle.get_activity_version())
- return zipname
-
-def _delete_backups(arg, dirname, names):
- for name in names:
- if name.endswith('~') or name.endswith('pyc'):
- os.remove(os.path.join(dirname, name))
-
-def _get_bundle_id():
- bundle = ActivityBundle(_get_source_path())
- return bundle.get_bundle_id()
-
-def cmd_help():
- print 'Usage: \n\
-setup.py dev - setup for development \n\
-setup.py dist - create a bundle package \n\
-setup.py install [dirname] - install the bundle \n\
-setup.py uninstall [dirname] - uninstall the bundle \n\
-setup.py genpot - generate the gettext pot file \n\
-setup.py genl10n - generate localization files \n\
-setup.py clean - clean the directory \n\
-setup.py release - do a new release of the bundle \n\
-setup.py help - print this message \n\
-'
-
-def cmd_dev():
- bundle_path = env.get_user_activities_path()
- if not os.path.isdir(bundle_path):
- os.mkdir(bundle_path)
- bundle_path = os.path.join(bundle_path, _get_bundle_dir())
- try:
- os.symlink(_get_source_path(), bundle_path)
- except OSError:
- if os.path.islink(bundle_path):
- print 'ERROR - The bundle has been already setup for development.'
- else:
- print 'ERROR - A bundle with the same name is already installed.'
-
-def _get_file_list(manifest):
- if os.path.isfile(manifest):
- return _ManifestFileList(manifest)
- elif os.path.isdir('.git'):
- return _GitFileList()
- elif os.path.isdir('.svn'):
- return _SvnFileList()
- else:
- return _DefaultFileList()
-
-def _get_po_list(manifest):
- file_list = {}
-
- po_regex = re.compile("po/(.*)\.po$")
- for file_name in _get_file_list(manifest):
- match = po_regex.match(file_name)
- if match:
- file_list[match.group(1)] = file_name
-
- return file_list
-
-def _get_l10n_list(manifest):
- l10n_list = []
-
- for lang in _get_po_list(manifest).keys():
- filename = _get_bundle_id() + '.mo'
- l10n_list.append(os.path.join('locale', lang, 'LC_MESSAGES', filename))
- l10n_list.append(os.path.join('locale', lang, 'activity.linfo'))
-
- return l10n_list
-
-def _get_activity_name():
- info_path = os.path.join(_get_source_path(), 'activity', 'activity.info')
- f = open(info_path,'r')
- info = f.read()
- f.close()
- match = re.search('^name\s*=\s*(.*)$', info, flags = re.MULTILINE)
- return match.group(1)
-
-def cmd_dist(bundle_name, manifest):
- cmd_genl10n(bundle_name, manifest)
- file_list = _get_file_list(manifest)
-
- zipname = _get_package_name(bundle_name)
- bundle_zip = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)
- base_dir = bundle_name + '.activity'
-
- for filename in file_list:
- bundle_zip.write(filename, os.path.join(base_dir, filename))
-
- for filename in _get_l10n_list(manifest):
- bundle_zip.write(filename, os.path.join(base_dir, filename))
-
- bundle_zip.close()
-
-def cmd_install(bundle_name, manifest, prefix):
- cmd_dist(bundle_name, manifest)
- cmd_uninstall(prefix)
-
- _extract_bundle(_get_package_name(bundle_name),
- _get_install_dir(prefix))
-
-def cmd_uninstall(prefix):
- path = os.path.join(_get_install_dir(prefix), _get_bundle_dir())
- if os.path.isdir(path):
- shutil.rmtree(path)
-
-def cmd_genpot(bundle_name, manifest):
- po_path = os.path.join(_get_source_path(), 'po')
- if not os.path.isdir(po_path):
- os.mkdir(po_path)
-
- python_files = []
- file_list = _get_file_list(manifest)
- for file_name in file_list:
- if file_name.endswith('.py'):
- python_files.append(file_name)
-
- # First write out a stub .pot file containing just the translated
- # activity name, then have xgettext merge the rest of the
- # translations into that. (We can't just append the activity name
- # to the end of the .pot file afterwards, because that might
- # create a duplicate msgid.)
- pot_file = os.path.join('po', '%s.pot' % bundle_name)
- activity_name = _get_activity_name()
- escaped_name = re.sub('([\\\\"])', '\\\\\\1', activity_name)
- f = open(pot_file, 'w')
- f.write('#: activity/activity.info:2\n')
- f.write('msgid "%s"\n' % escaped_name)
- f.write('msgstr ""\n')
- f.close()
-
- args = [ 'xgettext', '--join-existing', '--language=Python',
- '--keyword=_', '--add-comments=TRANS:', '--output=%s' % pot_file ]
-
- args += python_files
- retcode = subprocess.call(args)
- if retcode:
- print 'ERROR - xgettext failed with return code %i.' % retcode
-
- for file_name in _get_po_list(manifest).values():
- args = [ 'msgmerge', '-U', file_name, pot_file ]
- retcode = subprocess.call(args)
- if retcode:
- print 'ERROR - msgmerge failed with return code %i.' % retcode
-
-def cmd_genl10n(bundle_name, manifest):
- source_path = _get_source_path()
- activity_name = _get_activity_name()
-
- po_list = _get_po_list(manifest)
- for lang in po_list.keys():
- file_name = po_list[lang]
-
- localedir = os.path.join(source_path, 'locale', lang)
- mo_path = os.path.join(localedir, 'LC_MESSAGES')
- if not os.path.isdir(mo_path):
- os.makedirs(mo_path)
-
- mo_file = os.path.join(mo_path, "%s.mo" % _get_bundle_id())
- args = ["msgfmt", "--output-file=%s" % mo_file, file_name]
- retcode = subprocess.call(args)
- if retcode:
- print 'ERROR - msgfmt failed with return code %i.' % retcode
-
- cat = gettext.GNUTranslations(open(mo_file, 'r'))
- translated_name = cat.gettext(activity_name)
- linfo_file = os.path.join(localedir, 'activity.linfo')
- f = open(linfo_file, 'w')
- f.write('[Activity]\nname = %s\n' % translated_name)
- f.close()
-
-def cmd_release(bundle_name, manifest):
- if not os.path.isdir('.git'):
- print 'ERROR - this command works only for git repositories'
-
- retcode = subprocess.call(['git', 'pull'])
- if retcode:
- print 'ERROR - cannot pull from git'
-
- print 'Bumping activity version...'
-
- info_path = os.path.join(_get_source_path(), 'activity', 'activity.info')
- f = open(info_path,'r')
- info = f.read()
- f.close()
-
- exp = re.compile('activity_version\s?=\s?([0-9]*)')
- match = re.search(exp, info)
- version = int(match.group(1)) + 1
- info = re.sub(exp, 'activity_version = %d' % version, info)
-
- f = open(info_path, 'w')
- f.write(info)
- f.close()
-
- news_path = os.path.join(_get_source_path(), 'NEWS')
-
- if os.environ.has_key('SUGAR_NEWS'):
- print 'Update NEWS.sugar...'
-
- sugar_news_path = os.environ['SUGAR_NEWS']
- if os.path.isfile(sugar_news_path):
- f = open(sugar_news_path,'r')
- sugar_news = f.read()
- f.close()
- else:
- sugar_news = ''
-
- sugar_news += '%s - %d\n\n' % (bundle_name, version)
-
- f = open(news_path,'r')
- for line in f.readlines():
- if len(line.strip()) > 0:
- sugar_news += line
- else:
- break
- f.close()
-
- sugar_news += '\n'
-
- f = open(sugar_news_path, 'w')
- f.write(sugar_news)
- f.close()
-
- print 'Update NEWS...'
-
- f = open(news_path,'r')
- news = f.read()
- f.close()
-
- news = '%d\n\n' % version + news
-
- f = open(news_path, 'w')
- f.write(news)
- f.close()
-
- print 'Committing to git...'
-
- changelog = 'Release version %d.' % version
- retcode = subprocess.call(['git', 'commit', '-a', '-m % s' % changelog])
- if retcode:
- print 'ERROR - cannot commit to git'
-
- retcode = subprocess.call(['git', 'push'])
- if retcode:
- print 'ERROR - cannot push to git'
-
- print 'Creating the bundle...'
- cmd_dist(bundle_name, manifest)
-
- if os.environ.has_key('ACTIVITIES_REPOSITORY'):
- print 'Uploading to the activities repository...'
- repo = os.environ['ACTIVITIES_REPOSITORY']
-
- server, path = repo.split(':')
- retcode = subprocess.call(['ssh', server, 'rm',
- '%s/%s*' % (path, bundle_name)])
- if retcode:
- print 'ERROR - cannot remove old bundles from the repository.'
-
- bundle_path = os.path.join(_get_source_path(),
- _get_package_name(bundle_name))
- retcode = subprocess.call(['scp', bundle_path, repo])
- if retcode:
- print 'ERROR - cannot upload the bundle to the repository.'
-
- print 'Done.'
-
-def cmd_clean():
- os.path.walk('.', _delete_backups, None)
-
-def sanity_check():
- if not os.path.isfile(_get_source_path('NEWS')):
- print 'WARNING: NEWS file is missing.'
-
-def start(bundle_name, manifest='MANIFEST'):
- sanity_check()
-
- if len(sys.argv) < 2:
- cmd_help()
- elif sys.argv[1] == 'build':
- pass
- elif sys.argv[1] == 'dev':
- cmd_dev()
- elif sys.argv[1] == 'dist':
- cmd_dist(bundle_name, manifest)
- elif sys.argv[1] == 'install' and len(sys.argv) == 3:
- cmd_install(bundle_name, manifest, sys.argv[2])
- elif sys.argv[1] == 'uninstall' and len(sys.argv) == 3:
- cmd_uninstall(sys.argv[2])
- elif sys.argv[1] == 'genpot':
- cmd_genpot(bundle_name, manifest)
- elif sys.argv[1] == 'genl10n':
- cmd_genl10n(bundle_name, manifest)
- elif sys.argv[1] == 'clean':
- cmd_clean()
- elif sys.argv[1] == 'release':
- cmd_release(bundle_name, manifest)
- else:
- cmd_help()
-
-if __name__ == '__main__':
- start()
diff --git a/sugar/activity/registry.py b/sugar/activity/registry.py
deleted file mode 100644
index a279aa9..0000000
--- a/sugar/activity/registry.py
+++ /dev/null
@@ -1,156 +0,0 @@
-# Copyright (C) 2006-2007 Red Hat, Inc.
-# 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 logging
-
-import dbus
-import gobject
-
-_ACTIVITY_REGISTRY_SERVICE_NAME = 'org.laptop.ActivityRegistry'
-_ACTIVITY_REGISTRY_IFACE = 'org.laptop.ActivityRegistry'
-_ACTIVITY_REGISTRY_PATH = '/org/laptop/ActivityRegistry'
-
-def _activity_info_from_dict(info_dict):
- if not info_dict:
- return None
- return ActivityInfo(info_dict['name'], info_dict['icon'],
- info_dict['bundle_id'], info_dict['path'],
- info_dict['show_launcher'], info_dict['command'])
-
-class ActivityInfo(object):
- def __init__(self, name, icon, bundle_id,
- path, show_launcher, command):
- self.name = name
- self.icon = icon
- self.bundle_id = bundle_id
- self.path = path
- self.command = command
- self.show_launcher = show_launcher
-
-class ActivityRegistry(gobject.GObject):
- __gsignals__ = {
- 'activity-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'activity-removed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT]))
- }
- def __init__(self):
- gobject.GObject.__init__(self)
-
- bus = dbus.SessionBus()
-
- # NOTE: We need to follow_name_owner_changes here
- # because we can not connect to a signal unless
- # we follow the changes or we start the service
- # before we connect. Starting the service here
- # causes a major bottleneck during startup
- bus_object = bus.get_object(_ACTIVITY_REGISTRY_SERVICE_NAME,
- _ACTIVITY_REGISTRY_PATH,
- follow_name_owner_changes = True)
- self._registry = dbus.Interface(bus_object, _ACTIVITY_REGISTRY_IFACE)
- self._registry.connect_to_signal('ActivityAdded', self._activity_added_cb)
- self._registry.connect_to_signal('ActivityRemoved', self._activity_removed_cb)
-
- # Two caches fo saving some travel across dbus.
- self._service_name_to_activity_info = {}
- self._mime_type_to_activities = {}
-
- def _convert_info_list(self, info_list):
- result = []
-
- for info_dict in info_list:
- result.append(_activity_info_from_dict(info_dict))
-
- return result
-
- def get_activities(self):
- info_list = self._registry.GetActivities()
- return self._convert_info_list(info_list)
-
- def _get_activities_cb(self, reply_handler, info_list):
- result = []
- i = 0
- for info_dict in info_list:
- result.append(_activity_info_from_dict(info_dict))
-
- reply_handler(result)
-
- def _get_activities_error_cb(self, error_handler, e):
- if error_handler:
- error_handler(e)
- else:
- logging.error('Error getting activities async: %s' % str(e))
-
- def get_activities_async(self, reply_handler=None, error_handler=None):
- if not reply_handler:
- logging.error('Function get_activities_async called without a reply handler. Can not run.')
- return
-
- self._registry.GetActivities(
- reply_handler=lambda info_list:self._get_activities_cb(reply_handler, info_list),
- error_handler=lambda e:self._get_activities_error_cb(error_handler, e))
-
- def get_activity(self, service_name):
- if self._service_name_to_activity_info.has_key(service_name):
- return self._service_name_to_activity_info[service_name]
-
- info_dict = self._registry.GetActivity(service_name)
- activity_info = _activity_info_from_dict(info_dict)
-
- self._service_name_to_activity_info[service_name] = activity_info
- return activity_info
-
- def find_activity(self, name):
- info_list = self._registry.FindActivity(name)
- return self._convert_info_list(info_list)
-
- def get_activities_for_type(self, mime_type):
- if self._mime_type_to_activities.has_key(mime_type):
- return self._mime_type_to_activities[mime_type]
-
- info_list = self._registry.GetActivitiesForType(mime_type)
- activities = self._convert_info_list(info_list)
-
- self._mime_type_to_activities[mime_type] = activities
- return activities
-
- def add_bundle(self, bundle_path):
- return self._registry.AddBundle(bundle_path)
-
- def _activity_added_cb(self, info_dict):
- logging.debug('ActivityRegistry._activity_added_cb: flushing caches')
- self._service_name_to_activity_info.clear()
- self._mime_type_to_activities.clear()
- self.emit('activity-added', _activity_info_from_dict(info_dict))
-
- def remove_bundle(self, bundle_path):
- return self._registry.RemoveBundle(bundle_path)
-
- def _activity_removed_cb(self, info_dict):
- logging.debug('ActivityRegistry._activity_removed_cb: flushing caches')
- self._service_name_to_activity_info.clear()
- self._mime_type_to_activities.clear()
- self.emit('activity-removed', _activity_info_from_dict(info_dict))
-
-_registry = None
-
-def get_registry():
- global _registry
- if not _registry:
- _registry = ActivityRegistry()
- return _registry
diff --git a/sugar/bundle/Makefile.am b/sugar/bundle/Makefile.am
deleted file mode 100644
index f1af791..0000000
--- a/sugar/bundle/Makefile.am
+++ /dev/null
@@ -1,6 +0,0 @@
-sugardir = $(pythondir)/sugar/bundle
-sugar_PYTHON = \
- __init__.py \
- bundle.py \
- activitybundle.py \
- contentbundle.py
diff --git a/sugar/bundle/__init__.py b/sugar/bundle/__init__.py
deleted file mode 100644
index 85ebced..0000000
--- a/sugar/bundle/__init__.py
+++ /dev/null
@@ -1,16 +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.
diff --git a/sugar/bundle/activitybundle.py b/sugar/bundle/activitybundle.py
deleted file mode 100644
index 8ba61fe..0000000
--- a/sugar/bundle/activitybundle.py
+++ /dev/null
@@ -1,285 +0,0 @@
-# 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.
-
-"""Sugar activity bundles"""
-
-from ConfigParser import ConfigParser
-import locale
-import os
-import tempfile
-
-from sugar.bundle.bundle import Bundle, MalformedBundleException
-from sugar import activity
-from sugar import env
-
-class ActivityBundle(Bundle):
- """A Sugar activity bundle
-
- See http://wiki.laptop.org/go/Activity_bundles for details
- """
-
- MIME_TYPE = 'application/vnd.olpc-sugar'
- DEPRECATED_MIME_TYPE = 'application/vnd.olpc-x-sugar'
-
- _zipped_extension = '.xo'
- _unzipped_extension = '.activity'
- _infodir = 'activity'
-
- def __init__(self, path):
- Bundle.__init__(self, path)
- self.activity_class = None
- self.bundle_exec = None
-
- self._name = None
- self._icon = None
- self._bundle_id = None
- self._mime_types = None
- self._show_launcher = True
- self._activity_version = 0
-
- info_file = self._get_file('activity/activity.info')
- if info_file is None:
- raise MalformedBundleException('No activity.info file')
- self._parse_info(info_file)
-
- linfo_file = self._get_linfo_file()
- if linfo_file:
- self._parse_linfo(linfo_file)
-
- def _parse_info(self, info_file):
- cp = ConfigParser()
- cp.readfp(info_file)
-
- section = 'Activity'
-
- if cp.has_option(section, 'bundle_id'):
- self._bundle_id = cp.get(section, 'bundle_id')
- # FIXME deprecated
- elif cp.has_option(section, 'service_name'):
- self._bundle_id = cp.get(section, 'service_name')
- else:
- raise MalformedBundleException(
- 'Activity bundle %s does not specify a bundle id' %
- self._path)
-
- if cp.has_option(section, 'name'):
- self._name = cp.get(section, 'name')
- else:
- raise MalformedBundleException(
- 'Activity bundle %s does not specify a name' % self._path)
-
- # FIXME class is deprecated
- if cp.has_option(section, 'class'):
- self.activity_class = cp.get(section, 'class')
- elif cp.has_option(section, 'exec'):
- self.bundle_exec = cp.get(section, 'exec')
- else:
- raise MalformedBundleException(
- 'Activity bundle %s must specify either class or exec' %
- self._path)
-
- if cp.has_option(section, 'mime_types'):
- mime_list = cp.get(section, 'mime_types')
- self._mime_types = mime_list.strip(';').split(';')
-
- if cp.has_option(section, 'show_launcher'):
- if cp.get(section, 'show_launcher') == 'no':
- self._show_launcher = False
-
- if cp.has_option(section, 'icon'):
- self._icon = cp.get(section, 'icon')
-
- if cp.has_option(section, 'activity_version'):
- version = cp.get(section, 'activity_version')
- try:
- self._activity_version = int(version)
- except ValueError:
- raise MalformedBundleException(
- 'Activity bundle %s has invalid version number %s' %
- (self._path, version))
-
- def _get_linfo_file(self):
- lang = locale.getdefaultlocale()[0]
- if not lang:
- return None
-
- linfo_path = os.path.join('locale', lang, 'activity.linfo')
- linfo_file = self._get_file(linfo_path)
- if linfo_file is not None:
- return linfo_file
-
- linfo_path = os.path.join('locale', lang[:2], 'activity.linfo')
- linfo_file = self._get_file(linfo_path)
- if linfo_file is not None:
- return linfo_file
-
- return None
-
- def _parse_linfo(self, linfo_file):
- cp = ConfigParser()
- cp.readfp(linfo_file)
-
- section = 'Activity'
-
- if cp.has_option(section, 'name'):
- self._name = cp.get(section, 'name')
-
- def get_locale_path(self):
- """Get the locale path inside the (installed) activity bundle."""
- if not self._unpacked:
- raise NotInstalledException
- return os.path.join(self._path, 'locale')
-
- def get_icons_path(self):
- """Get the icons path inside the (installed) activity bundle."""
- if not self._unpacked:
- raise NotInstalledException
- return os.path.join(self._path, 'icons')
-
- def get_path(self):
- """Get the activity bundle path."""
- return self._path
-
- def get_name(self):
- """Get the activity user visible name."""
- return self._name
-
- def get_bundle_id(self):
- """Get the activity bundle id"""
- return self._bundle_id
-
- # FIXME: this should return the icon data, not a filename, so that
- # we don't need to create a temp file in the zip case
- def get_icon(self):
- """Get the activity icon name"""
- icon_path = os.path.join('activity', self._icon + '.svg')
- if self._unpacked:
- return os.path.join(self._path, icon_path)
- else:
- icon_data = self._get_file(icon_path).read()
- temp_file, temp_file_path = tempfile.mkstemp(self._icon)
- os.write(temp_file, icon_data)
- os.close(temp_file)
- return temp_file_path
-
- def get_activity_version(self):
- """Get the activity version"""
- return self._activity_version
-
- def get_command(self):
- """Get the command to execute to launch the activity factory"""
- if self.bundle_exec:
- command = os.path.expandvars(self.bundle_exec)
- else:
- command = 'sugar-activity ' + self.activity_class
-
- return command
-
-
- def get_mime_types(self):
- """Get the MIME types supported by the activity"""
- return self._mime_types
-
- def get_show_launcher(self):
- """Get whether there should be a visible launcher for the activity"""
- return self._show_launcher
-
- def is_installed(self):
- if activity.get_registry().get_activity(self._bundle_id):
- return True
- else:
- return False
-
- def install(self):
- if self.is_installed():
- raise AlreadyInstalledException
-
- install_dir = env.get_user_activities_path()
- self._unzip(install_dir)
-
- install_path = os.path.join(install_dir, self._zip_root_dir)
-
- xdg_data_home = os.getenv('XDG_DATA_HOME', os.path.expanduser('~/.local/share'))
-
- mime_path = os.path.join(install_path, 'activity', 'mimetypes.xml')
- if os.path.isfile(mime_path):
- mime_dir = os.path.join(xdg_data_home, 'mime')
- mime_pkg_dir = os.path.join(mime_dir, 'packages')
- if not os.path.isdir(mime_pkg_dir):
- os.makedirs(mime_pkg_dir)
- installed_mime_path = os.path.join(mime_pkg_dir, '%s.xml' % self._bundle_id)
- os.symlink(mime_path, installed_mime_path)
- os.spawnlp(os.P_WAIT, 'update-mime-database',
- 'update-mime-database', mime_dir)
-
- mime_types = self.get_mime_types()
- if mime_types is not None:
- installed_icons_dir = os.path.join(xdg_data_home,
- 'icons/sugar/scalable/mimetypes')
- if not os.path.isdir(installed_icons_dir):
- os.makedirs(installed_icons_dir)
-
- for mime_type in mime_types:
- mime_icon_base = os.path.join(install_path, 'activity',
- mime_type.replace('/', '-'))
- svg_file = mime_icon_base + '.svg'
- info_file = mime_icon_base + '.icon'
- if os.path.isfile(svg_file):
- os.symlink(svg_file,
- os.path.join(installed_icons_dir,
- os.path.basename(svg_file)))
- if os.path.isfile(info_file):
- os.symlink(info_file,
- os.path.join(installed_icons_dir,
- os.path.basename(info_file)))
-
- if not activity.get_registry().add_bundle(install_path):
- raise RegistrationException
-
- def uninstall(self):
- if self._unpacked:
- install_path = self._path
- else:
- if not self.is_installed():
- raise NotInstalledException
- install_path = os.path.join(env.get_user_activities_path(),
- self._zip_root_dir)
-
- xdg_data_home = os.getenv('XDG_DATA_HOME', os.path.expanduser('~/.local/share'))
-
- mime_dir = os.path.join(xdg_data_home, 'mime')
- installed_mime_path = os.path.join(mime_dir, 'packages', '%s.xml' % self._bundle_id)
- if os.path.exists(installed_mime_path):
- os.remove(installed_mime_path)
- os.spawnlp(os.P_WAIT, 'update-mime-database',
- 'update-mime-database', mime_dir)
-
- mime_types = self.get_mime_types()
- if mime_types is not None:
- installed_icons_dir = os.path.join(xdg_data_home,
- 'icons/sugar/scalable/mimetypes')
- for file in os.listdir(installed_icons_dir):
- path = os.path.join(installed_icons_dir, file)
- if os.path.islink(path) and \
- os.readlink(path).startswith(install_path):
- os.remove(path)
-
- self._uninstall(install_path)
-
- if not activity.get_registry().remove_bundle(install_path):
- raise RegistrationException
-
diff --git a/sugar/bundle/bundle.py b/sugar/bundle/bundle.py
deleted file mode 100644
index 8ce3dda..0000000
--- a/sugar/bundle/bundle.py
+++ /dev/null
@@ -1,146 +0,0 @@
-# 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.
-
-"""Sugar bundle file handler"""
-
-import os
-import StringIO
-import zipfile
-
-class AlreadyInstalledException(Exception): pass
-class NotInstalledException(Exception): pass
-class InvalidPathException(Exception): pass
-class ZipExtractException(Exception): pass
-class RegistrationException(Exception): pass
-class MalformedBundleException(Exception): pass
-
-class Bundle:
- """A Sugar activity, content module, etc.
-
- The bundle itself may be either a zip file or a directory
- hierarchy, with metadata about the bundle stored various files
- inside it.
-
- This is an abstract base class. See ActivityBundle and
- ContentBundle for more details on those bundle types.
- """
- def __init__(self, path):
- self._path = path
-
- if os.path.isdir(self._path):
- self._unpacked = True
- else:
- self._unpacked = False
- self._check_zip_bundle()
-
- # manifest = self._get_file(self._infodir + '/contents')
- # if manifest is None:
- # raise MalformedBundleException('No manifest file')
- #
- # signature = self._get_file(self._infodir + '/contents.sig')
- # if signature is None:
- # raise MalformedBundleException('No signature file')
-
- def _check_zip_bundle(self):
- zip_file = zipfile.ZipFile(self._path)
- file_names = zip_file.namelist()
- if len(file_names) == 0:
- raise MalformedBundleException('Empty zip file')
-
- if file_names[0] == 'mimetype':
- del file_names[0]
-
- self._zip_root_dir = file_names[0].split('/')[0]
- if self._unzipped_extension is not None:
- (name, ext) = os.path.splitext(self._zip_root_dir)
- if ext != self._unzipped_extension:
- raise MalformedBundleException(
- 'All files in the bundle must be inside a single ' +
- 'directory whose name ends with "%s"' %
- self._unzipped_extension)
-
- for file_name in file_names:
- if not file_name.startswith(self._zip_root_dir):
- raise MalformedBundleException(
- 'All files in the bundle must be inside a single ' +
- 'top-level directory')
-
- def _get_file(self, filename):
- file = None
-
- if self._unpacked:
- path = os.path.join(self._path, filename)
- if os.path.isfile(path):
- file = open(path)
- else:
- zip_file = zipfile.ZipFile(self._path)
- path = os.path.join(self._zip_root_dir, filename)
- try:
- data = zip_file.read(path)
- file = StringIO.StringIO(data)
- except KeyError:
- # == "file not found"
- pass
- zip_file.close()
-
- return file
-
- def get_path(self):
- """Get the bundle path."""
- return self._path
-
- def _unzip(self, install_dir):
- if self._unpacked:
- raise AlreadyInstalledException
-
- if not os.path.isdir(install_dir):
- os.mkdir(install_dir)
-
- # zipfile provides API that in theory would let us do this
- # correctly by hand, but handling all the oddities of
- # Windows/UNIX mappings, extension attributes, deprecated
- # features, etc makes it impractical.
- # FIXME: use manifest
- if os.spawnlp(os.P_WAIT, 'unzip', 'unzip', self._path,
- '-x', 'mimetype', '-d', install_dir):
- raise ZipExtractException
-
- def _zip(self, bundle_path):
- if not self._unpacked:
- raise NotInstalledException
-
- # FIXME: use manifest
- zip = zipfile.ZipFile(bundle_path, 'w', zipfile.ZIP_DEFLATED)
- for root, dirs, files in os.walk(self._path):
- for name in files:
- zip.write(filename, os.path.join(base_dir, filename))
- zip.close()
-
- def _uninstall(self, install_path):
- if not os.path.isdir(install_path):
- raise InvalidPathException
- if self._unzipped_extension is not None:
- ext = os.path.splitext(install_path)[1]
- if ext != self._unzipped_extension:
- raise InvalidPathException
-
- for root, dirs, files in os.walk(install_path, topdown=False):
- for name in files:
- os.remove(os.path.join(root, name))
- for name in dirs:
- os.rmdir(os.path.join(root, name))
- os.rmdir(install_path)
diff --git a/sugar/bundle/contentbundle.py b/sugar/bundle/contentbundle.py
deleted file mode 100644
index 517ee9a..0000000
--- a/sugar/bundle/contentbundle.py
+++ /dev/null
@@ -1,189 +0,0 @@
-# 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.
-
-"""Sugar content bundles"""
-
-from ConfigParser import ConfigParser
-import os
-
-from sugar import env
-from sugar.bundle.bundle import Bundle, NotInstalledException
-
-class ContentBundle(Bundle):
- """A Sugar content bundle
-
- See http://wiki.laptop.org/go/Content_bundles for details
- """
-
- MIME_TYPE = 'application/vnd.olpc-content'
-
- _zipped_extension = '.xol'
- _unzipped_extension = None
- _infodir = 'library'
-
- def __init__(self, path):
- Bundle.__init__(self, path)
-
- info_file = self._get_file('library/library.info')
- if info_file is None:
- raise MalformedBundleException('No library.info file')
- self._parse_info(info_file)
-
- if (self._get_file('index.html') is None and
- self._get_file('library/library.xml') is None):
- raise MalformedBundleException(
- 'Content bundle %s has neither index.html nor library.xml' %
- self._path)
-
- def _parse_info(self, info_file):
- cp = ConfigParser()
- cp.readfp(info_file)
-
- section = 'Library'
-
- if cp.has_option(section, 'host_version'):
- version = cp.get(section, 'host_version')
- try:
- if int(version) != 1:
- raise MalformedBundleException(
- 'Content bundle %s has unknown host_version number %s' %
- (self._path, version))
- except ValueError:
- raise MalformedBundleException(
- 'Content bundle %s has invalid host_version number %s' %
- (self._path, version))
-
- if cp.has_option(section, 'name'):
- self._name = cp.get(section, 'name')
- else:
- raise MalformedBundleException(
- 'Content bundle %s does not specify a name' % self._path)
-
- if cp.has_option(section, 'library_version'):
- version = cp.get(section, 'library_version')
- try:
- self._library_version = int(version)
- except ValueError:
- raise MalformedBundleException(
- 'Content bundle %s has invalid version number %s' %
- (self._path, version))
-
- if cp.has_option(section, 'l10n'):
- l10n = cp.get(section, 'l10n')
- if l10n == 'true':
- self._l10n = True
- elif l10n == 'false':
- self._l10n = False
- else:
- raise MalformedBundleException(
- 'Content bundle %s has invalid l10n key "%s"' %
- (self._path, l10n))
- else:
- raise MalformedBundleException(
- 'Content bundle %s does not specify if it is localized' %
- self._path)
-
- if cp.has_option(section, 'locale'):
- self._locale = cp.get(section, 'locale')
- else:
- raise MalformedBundleException(
- 'Content bundle %s does not specify a locale' % self._path)
-
- if cp.has_option(section, 'category'):
- self._category = cp.get(section, 'category')
- else:
- raise MalformedBundleException(
- 'Content bundle %s does not specify a category' % self._path)
-
- if cp.has_option(section, 'category_icon'):
- self._category_icon = cp.get(section, 'category_icon')
- else:
- self._category_icon = None
-
- if cp.has_option(section, 'category_class'):
- self._category_class = cp.get(section, 'category_class')
- else:
- self._category_class = None
-
- if cp.has_option(section, 'subcategory'):
- self._subcategory = cp.get(section, 'subcategory')
- else:
- self._subcategory = None
-
- if cp.has_option(section, 'bundle_class'):
- self._bundle_class = cp.get(section, 'bundle_class')
- else:
- self._bundle_class = None
-
- def get_name(self):
- return self._name
-
- def get_library_version(self):
- return self._library_version
-
- def get_l10n(self):
- return self._l10n
-
- def get_locale(self):
- return self._locale
-
- def get_category(self):
- return self._category
-
- def get_category(self):
- return self._category
-
- def get_category_icon(self):
- return self._category_icon
-
- def get_category_class(self):
- return self._category_class
-
- def get_subcategory(self):
- return self._subcategory
-
- def get_bundle_class(self):
- return self._bundle_class
-
- def _run_indexer(self):
- os.spawnlp(os.P_WAIT, 'python',
- 'python',
- os.path.join(env.get_user_library_path(), 'makeIndex.py'))
-
- def is_installed(self):
- if self._unpacked:
- return True
- elif os.path.isdir(os.path.join(env.get_user_library_path(),
- self._zip_root_dir)):
- return True
- else:
- return False
-
- def install(self):
- self._unzip(env.get_user_library_path())
- self._run_indexer()
-
- def uninstall(self):
- if self._unpacked:
- if not self.is_installed():
- raise NotInstalledException
- install_dir = self._path
- else:
- install_dir = os.path.join(env.get_user_library_path(),
- self._zip_root_dir)
- self._uninstall(install_dir)
- self._run_indexer()
diff --git a/sugar/clipboard/Makefile.am b/sugar/clipboard/Makefile.am
deleted file mode 100644
index 0d61c29..0000000
--- a/sugar/clipboard/Makefile.am
+++ /dev/null
@@ -1,5 +0,0 @@
-sugardir = $(pythondir)/sugar/clipboard
-sugar_PYTHON = \
- __init__.py \
- clipboardservice.py
-
diff --git a/sugar/clipboard/__init__.py b/sugar/clipboard/__init__.py
deleted file mode 100644
index deee8dd..0000000
--- a/sugar/clipboard/__init__.py
+++ /dev/null
@@ -1,22 +0,0 @@
-"""Client-code's interface to the ClipboardService
-
-Provides a simplified API for accessing the dbus service
-which coordinates clipboard operations within Sugar.
-"""
-# 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.
-
diff --git a/sugar/clipboard/clipboardservice.py b/sugar/clipboard/clipboardservice.py
deleted file mode 100644
index d975330..0000000
--- a/sugar/clipboard/clipboardservice.py
+++ /dev/null
@@ -1,229 +0,0 @@
-"""UI class to access system-level clipboard object"""
-# 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 logging
-import dbus
-import gobject
-
-NAME_KEY = 'NAME'
-PERCENT_KEY = 'PERCENT'
-ICON_KEY = 'ICON'
-PREVIEW_KEY = 'PREVIEW'
-ACTIVITIES_KEY = 'ACTIVITIES'
-FORMATS_KEY = 'FORMATS'
-
-TYPE_KEY = 'TYPE'
-DATA_KEY = 'DATA'
-ON_DISK_KEY = 'ON_DISK'
-
-DBUS_SERVICE = "org.laptop.Clipboard"
-DBUS_INTERFACE = "org.laptop.Clipboard"
-DBUS_PATH = "/org/laptop/Clipboard"
-
-class ClipboardService(gobject.GObject):
- """GUI interfaces for the system clipboard dbus service
-
- This object is used to provide convenient access to the clipboard
- service (see source/services/clipboard/clipboardservice.py). It
- provides utility methods for adding/getting/removing objects from
- the clipboard as well as generating events when such events occur.
-
- Meaning is source/services/clipboard/clipboardobject.py
- objects when describing "objects" on the clipboard.
- """
- __gsignals__ = {
- 'object-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([str, str])),
- 'object-deleted': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([str])),
- 'object-state-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([str, str, int, str, str, object])),
- }
-
- def __init__(self):
- """Initialise the ClipboardService instance
-
- If the service is not yet active in the background uses
- a signal watcher to connect when the service appears.
- """
- gobject.GObject.__init__(self)
-
- self._dbus_service = None
-
- bus = dbus.SessionBus()
- self._nameOwnerChangedHandler = bus.add_signal_receiver(
- self._name_owner_changed_cb,
- signal_name="NameOwnerChanged",
- dbus_interface="org.freedesktop.DBus",
- arg0=DBUS_SERVICE)
-
- self._connected = False
- # Try to register to ClipboardService, if we fail, we'll try later.
- try:
- self._connect_clipboard_signals()
- except dbus.DBusException, exception:
- logging.debug(exception)
-
- def _connect_clipboard_signals(self):
- """Connect dbus signals to our GObject signal generating callbacks"""
- bus = dbus.SessionBus()
- if not self._connected:
- # NOTE: We need to follow_name_owner_changes here
- # because we can not connect to a signal unless
- # we follow the changes or we start the service
- # before we connect. Starting the service here
- # causes a major bottleneck during startup
- proxy_obj = bus.get_object(DBUS_SERVICE,
- DBUS_PATH,
- follow_name_owner_changes=True)
- self._dbus_service = dbus.Interface(proxy_obj, DBUS_SERVICE)
- self._dbus_service.connect_to_signal('object_added',
- self._object_added_cb)
- self._dbus_service.connect_to_signal('object_deleted',
- self._object_deleted_cb)
- self._dbus_service.connect_to_signal('object_state_changed',
- self._object_state_changed_cb)
- self._connected = True
-
- bus.remove_signal_receiver(self._nameOwnerChangedHandler)
-
- def _name_owner_changed_cb(self, name, old, new):
- """On backend service creation, connect to the server"""
- if not old and new:
- # ClipboardService started up
- self._connect_clipboard_signals()
-
- def _object_added_cb(self, object_id, name):
- """Emit an object-added GObject event when dbus event arrives"""
- self.emit('object-added', str(object_id), name)
-
- def _object_deleted_cb(self, object_id):
- """Emit an object-deleted GObject event when dbus event arrives"""
- self.emit('object-deleted', str(object_id))
-
- def _object_state_changed_cb(self, object_id, values):
- """Emit an object-state-changed GObject event when dbus event arrives
-
- GObject event has:
-
- object_id
- name
- percent
- icon
- preview
- activities
-
- From the ClipboardObject instance which is being described.
- """
- self.emit('object-state-changed', str(object_id), values[NAME_KEY],
- values[PERCENT_KEY], values[ICON_KEY], values[PREVIEW_KEY],
- values[ACTIVITIES_KEY])
-
- def add_object(self, name):
- """Add a new object to the path
-
- returns dbus path-name for the new object's cliboard service,
- this is used for all future references to the cliboard object.
-
- Note:
- That service is actually provided by the clipboard
- service object, not the ClipboardObject
- """
- return str(self._dbus_service.add_object(name))
-
- def add_object_format(self, object_id, formatType, data, on_disk):
- """Annotate given object on the clipboard with new information
-
- object_id -- dbus path as returned from add_object
- formatType -- XXX what should this be? mime type?
- data -- storage format for the clipped object?
- on_disk -- whether the data is on-disk (non-volatile) or in
- memory (volatile)
-
- Last three arguments are just passed directly to the
- clipboardobject.Format instance on the server side.
-
- returns None
- """
- self._dbus_service.add_object_format(dbus.ObjectPath(object_id),
- formatType,
- data,
- on_disk)
-
- def delete_object(self, object_id):
- """Remove the given object from the clipboard
-
- object_id -- dbus path as returned from add_object
- """
- self._dbus_service.delete_object(dbus.ObjectPath(object_id))
-
- def set_object_percent(self, object_id, percent):
- """Set the "percentage" for the given clipboard object
-
- object_id -- dbus path as returned from add_object
- percentage -- numeric value from 0 to 100 inclusive
-
- Object percentages which are set to 100% trigger "file-completed"
- operations, see the backend ClipboardService's
- _handle_file_completed method for details.
-
- returns None
- """
- self._dbus_service.set_object_percent(dbus.ObjectPath(object_id), percent)
-
- def get_object(self, object_id):
- """Retrieve the clipboard object structure for given object
-
- object_id -- dbus path as returned from add_object
-
- Retrieves the metadata description of a given object, but
- *not* the data for the object. Use get_object_data passing
- one of the values in the FORMATS_KEY value in order to
- retrieve the data.
-
- returns dictionary with
- NAME_KEY: str,
- PERCENT_KEY: number,
- ICON_KEY: str,
- PREVIEW_KEY: XXX what is it?,
- ACTIVITIES_KEY: activities that can open this object,
- FORMATS_KEY: list of XXX what is it?
- """
- return self._dbus_service.get_object(dbus.ObjectPath(object_id),)
-
- def get_object_data(self, object_id, formatType):
- """Retrieve object's data in the given formatType
-
- object_id -- dbus path as returned from add_object
- formatType -- format specifier XXX of what description
-
- returns dictionary with
- TYPE_KEY: str,
- DATA_KEY: str,
- ON_DISK_KEY: bool
- """
- return self._dbus_service.get_object_data(dbus.ObjectPath(object_id),
- formatType,
- byte_arrays=True)
-
-_clipboard_service = None
-def get_instance():
- """Retrieve this process's interface to the clipboard service"""
- global _clipboard_service
- if not _clipboard_service:
- _clipboard_service = ClipboardService()
- return _clipboard_service
diff --git a/sugar/datastore/Makefile.am b/sugar/datastore/Makefile.am
deleted file mode 100644
index a5f16b7..0000000
--- a/sugar/datastore/Makefile.am
+++ /dev/null
@@ -1,5 +0,0 @@
-sugardir = $(pythondir)/sugar/datastore
-sugar_PYTHON = \
- __init__.py \
- dbus_helpers.py \
- datastore.py
diff --git a/sugar/datastore/__init__.py b/sugar/datastore/__init__.py
deleted file mode 100644
index bdb658b..0000000
--- a/sugar/datastore/__init__.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# 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.
diff --git a/sugar/datastore/datastore.py b/sugar/datastore/datastore.py
deleted file mode 100644
index a865c30..0000000
--- a/sugar/datastore/datastore.py
+++ /dev/null
@@ -1,307 +0,0 @@
-# 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 logging
-import time
-from datetime import datetime
-import os
-
-import gobject
-
-from sugar.datastore import dbus_helpers
-from sugar import activity
-from sugar.activity.activityhandle import ActivityHandle
-from sugar.bundle.contentbundle import ContentBundle
-from sugar.bundle.activitybundle import ActivityBundle
-from sugar.bundle.contentbundle import ContentBundle
-from sugar import mime
-
-class DSMetadata(gobject.GObject):
- __gsignals__ = {
- 'updated': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([]))
- }
-
- def __init__(self, props=None):
- gobject.GObject.__init__(self)
- if not props:
- self._props = {}
- else:
- self._props = props
-
- default_keys = ['activity', 'activity_id',
- 'mime_type', 'title_set_by_user']
- for key in default_keys:
- if not self._props.has_key(key):
- self._props[key] = ''
-
- def __getitem__(self, key):
- return self._props[key]
-
- def __setitem__(self, key, value):
- if not self._props.has_key(key) or self._props[key] != value:
- self._props[key] = value
- self.emit('updated')
-
- def __delitem__(self, key):
- del self._props[key]
-
- def __contains__(self, key):
- return self._props.__contains__(key)
-
- def has_key(self, key):
- return self._props.has_key(key)
-
- def keys(self):
- return self._props.keys()
-
- def get_dictionary(self):
- return self._props
-
- def copy(self):
- return DSMetadata(self._props.copy())
-
- def get(self, key, default=None):
- if self._props.has_key(key):
- return self._props[key]
- else:
- return default
-
-class DSObject(object):
- def __init__(self, object_id, metadata=None, file_path=None):
- self.object_id = object_id
- self._metadata = metadata
- self._file_path = file_path
- self._destroyed = False
- self._owns_file = False
-
- def get_metadata(self):
- if self._metadata is None and not self.object_id is None:
- metadata = DSMetadata(dbus_helpers.get_properties(self.object_id))
- self._metadata = metadata
- return self._metadata
-
- def set_metadata(self, metadata):
- if self._metadata != metadata:
- self._metadata = metadata
-
- metadata = property(get_metadata, set_metadata)
-
- def get_file_path(self):
- if self._file_path is None and not self.object_id is None:
- self.set_file_path(dbus_helpers.get_filename(self.object_id))
- self._owns_file = True
- return self._file_path
-
- def set_file_path(self, file_path):
- if self._file_path != file_path:
- if self._file_path and self._owns_file:
- if os.path.isfile(self._file_path):
- os.remove(self._file_path)
- self._owns_file = False
- self._file_path = file_path
-
- file_path = property(get_file_path, set_file_path)
-
- def get_activities(self):
- activities = []
-
- if self.metadata['activity']:
- activity_info = activity.get_registry().get_activity(self.metadata['activity'])
- if activity_info:
- activities.append(activity_info)
-
- mime_type = self.metadata['mime_type']
- if mime_type:
- activities_info = activity.get_registry().get_activities_for_type(mime_type)
- for activity_info in activities_info:
- if activity_info.bundle_id != self.metadata['activity']:
- activities.append(activity_info)
-
- return activities
-
- def is_activity_bundle(self):
- return self.metadata['mime_type'] in \
- [ActivityBundle.MIME_TYPE, ActivityBundle.DEPRECATED_MIME_TYPE]
-
- def is_content_bundle(self):
- return self.metadata['mime_type'] == ContentBundle.MIME_TYPE
-
- def is_bundle(self):
- return self.is_activity_bundle() or self.is_content_bundle()
-
- def resume(self, bundle_id=None):
- from sugar.activity import activityfactory
-
- if self.is_activity_bundle():
- if bundle_id is not None:
- raise ValueError('Object is a bundle, cannot be resumed as an activity.')
-
- bundle = ActivityBundle(self.file_path)
- if not bundle.is_installed():
- bundle.install()
-
- activityfactory.create(bundle.get_bundle_id())
- else:
- if not self.get_activities() and bundle_id is None:
- logging.warning('No activity can open this object.')
- return
- if bundle_id is None:
- bundle_id = self.get_activities()[0].bundle_id
-
- activity_id = self.metadata['activity_id']
- object_id = self.object_id
-
- if activity_id:
- handle = ActivityHandle(object_id=object_id,
- activity_id=activity_id)
- activityfactory.create(bundle_id, handle)
- else:
- activityfactory.create_with_object_id(bundle_id, object_id)
-
- def destroy(self):
- if self._destroyed:
- logging.warning('This DSObject has already been destroyed!.')
- import traceback;traceback.print_stack()
- return
- self._destroyed = True
- if self._file_path and self._owns_file:
- if os.path.isfile(self._file_path):
- os.remove(self._file_path)
- self._owns_file = False
- self._file_path = None
-
- def __del__(self):
- if not self._destroyed:
- logging.warning('DSObject was deleted without cleaning up first. ' \
- '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)
-
- ds_object = DSObject(object_id, DSMetadata(metadata), None)
- # TODO: register the object for updates
- return ds_object
-
-def create():
- metadata = DSMetadata()
- metadata['mtime'] = datetime.now().isoformat()
- metadata['timestamp'] = int(time.time())
- return DSObject(object_id=None, metadata=metadata, file_path=None)
-
-def write(ds_object, update_mtime=True, transfer_ownership=False, reply_handler=None, error_handler=None, timeout=-1):
- logging.debug('datastore.write')
-
- properties = ds_object.metadata.get_dictionary().copy()
-
- if update_mtime:
- properties['mtime'] = datetime.now().isoformat()
- properties['timestamp'] = int(time.time())
-
- if ds_object._file_path is None:
- file_path = ''
- else:
- file_path = ds_object._file_path
-
- # FIXME: this func will be sync for creates regardless of the handlers
- # supplied. This is very bad API, need to decide what to do here.
- if ds_object.object_id:
- dbus_helpers.update(ds_object.object_id,
- properties,
- file_path,
- transfer_ownership,
- reply_handler=reply_handler,
- error_handler=error_handler,
- timeout=timeout)
- else:
- if reply_handler or error_handler:
- logging.warning('datastore.write() cannot currently be called async' \
- ' for creates, see https://dev.laptop.org/ticket/3071')
- ds_object.object_id = dbus_helpers.create(properties,
- file_path,
- transfer_ownership)
- # TODO: register the object for updates
- logging.debug('Written object %s to the datastore.' % ds_object.object_id)
-
-def delete(object_id):
- logging.debug('datastore.delete')
- dbus_helpers.delete(object_id)
-
-def find(query, sorting=None, limit=None, offset=None, properties=[],
- reply_handler=None, error_handler=None):
-
- query = query.copy()
-
- if sorting:
- query['order_by'] = sorting
- if limit:
- query['limit'] = limit
- if offset:
- query['offset'] = offset
-
- props_list, total_count = dbus_helpers.find(query, properties, reply_handler, error_handler)
-
- objects = []
- for props in props_list:
- object_id = props['uid']
- del props['uid']
-
- ds_object = DSObject(object_id, DSMetadata(props), None)
- objects.append(ds_object)
-
- return objects, total_count
-
-def copy(jobject, mount_point):
-
- new_jobject = jobject.copy()
- new_jobject.metadata['mountpoint'] = mount_point
-
- if jobject.metadata.has_key('title'):
- filename = jobject.metadata['title']
-
- if jobject.metadata.has_key('mime_type'):
- mime_type = jobject.metadata['mime_type']
- extension = mime.get_primary_extension(mime_type)
- if extension:
- filename += '.' + extension
-
- new_jobject.metadata['suggested_filename'] = filename
-
- # this will cause the file be retrieved from the DS
- new_jobject.file_path = jobject.file_path
-
- write(new_jobject)
-
-def mount(uri, options, timeout=-1):
- return dbus_helpers.mount(uri, options, timeout=timeout)
-
-def unmount(mount_point_id):
- dbus_helpers.unmount(mount_point_id)
-
-def mounts():
- return dbus_helpers.mounts()
-
-def complete_indexing():
- return dbus_helpers.complete_indexing()
-
-def get_unique_values(key):
- return dbus_helpers.get_unique_values(key)
diff --git a/sugar/datastore/dbus_helpers.py b/sugar/datastore/dbus_helpers.py
deleted file mode 100644
index a5ce9c8..0000000
--- a/sugar/datastore/dbus_helpers.py
+++ /dev/null
@@ -1,99 +0,0 @@
-# Copyright (C) 2006-2007 Red Hat, Inc.
-# 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 logging
-
-import dbus
-import dbus.glib
-import gobject
-
-from sugar import util
-
-DS_DBUS_SERVICE = "org.laptop.sugar.DataStore"
-DS_DBUS_INTERFACE = "org.laptop.sugar.DataStore"
-DS_DBUS_PATH = "/org/laptop/sugar/DataStore"
-
-_data_store = None
-
-def _get_data_store():
- global _data_store
-
- if not _data_store:
- _bus = dbus.SessionBus()
- _data_store = dbus.Interface(_bus.get_object(DS_DBUS_SERVICE,
- DS_DBUS_PATH),
- DS_DBUS_INTERFACE)
- return _data_store
-
-def create(properties, filename, transfer_ownership=False):
- object_id = _get_data_store().create(dbus.Dictionary(properties), filename,
- transfer_ownership)
- logging.debug('dbus_helpers.create: ' + object_id)
- return object_id
-
-def update(uid, properties, filename, transfer_ownership=False,
- reply_handler=None, error_handler=None, timeout=-1):
- debug_props = properties.copy()
- if debug_props.has_key("preview"):
- debug_props["preview"] = "<omitted>"
- logging.debug('dbus_helpers.update: %s, %s, %s, %s' % (uid, filename, debug_props, transfer_ownership))
- if reply_handler and error_handler:
- _get_data_store().update(uid, dbus.Dictionary(properties), filename,
- transfer_ownership,
- reply_handler=reply_handler,
- error_handler=error_handler,
- timeout=timeout)
- else:
- _get_data_store().update(uid, dbus.Dictionary(properties), filename, transfer_ownership)
-
-def delete(uid):
- logging.debug('dbus_helpers.delete: %r' % uid)
- _get_data_store().delete(uid)
-
-def get_properties(uid):
- logging.debug('dbus_helpers.get_properties: %s' % uid)
- return _get_data_store().get_properties(uid, byte_arrays=True)
-
-def get_filename(uid):
- filename = _get_data_store().get_filename(uid)
- logging.debug('dbus_helpers.get_filename: %s, %s' % (uid, filename))
- return filename
-
-def find(query, properties, reply_handler, error_handler):
- logging.debug('dbus_helpers.find: %r %r' % (query, properties))
- if reply_handler and error_handler:
- return _get_data_store().find(query, properties,
- reply_handler=reply_handler, error_handler=error_handler)
- else:
- return _get_data_store().find(query, properties)
-
-def mount(uri, options, timeout=-1):
- return _get_data_store().mount(uri, options, timeout=timeout)
-
-def unmount(mount_point_id):
- _get_data_store().unmount(mount_point_id)
-
-def mounts():
- return _get_data_store().mounts()
-
-def get_unique_values(key):
- return _get_data_store().get_uniquevaluesfor(key, dbus.Dictionary({}, signature='ss'))
-
-def complete_indexing():
- return _get_data_store().complete_indexing()
-
diff --git a/sugar/env.py b/sugar/env.py
deleted file mode 100644
index 65b8b0c..0000000
--- a/sugar/env.py
+++ /dev/null
@@ -1,93 +0,0 @@
-"""Calculates file-paths for the Sugar working environment"""
-# 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 os
-
-def _get_prefix_path(base, path=None):
- if os.environ.has_key('SUGAR_PREFIX'):
- prefix = os.environ['SUGAR_PREFIX']
- else:
- raise RuntimeError("The SUGAR_PREFIX environment variable is not set.")
-
- if path:
- return os.path.join(prefix, base, path)
- else:
- return os.path.join(prefix, base)
-
-def _get_sugar_path(base, path=None):
- if os.environ.has_key('SUGAR_PATH'):
- sugar_path = os.environ['SUGAR_PATH']
- else:
- raise RuntimeError("The SUGAR_PATH environment variable is not set.")
-
- if path:
- return os.path.join(sugar_path, base, path)
- else:
- return os.path.join(sugar_path, base)
-
-def is_emulator():
- if os.environ.has_key('SUGAR_EMULATOR'):
- if os.environ['SUGAR_EMULATOR'] == 'yes':
- return True
- return False
-
-def get_profile_path(path=None):
- if os.environ.has_key('SUGAR_PROFILE'):
- profile_id = os.environ['SUGAR_PROFILE']
- else:
- profile_id = 'default'
-
- base = os.path.join(os.path.expanduser('~/.sugar'), profile_id)
- if not os.path.isdir(base):
- try:
- os.makedirs(base)
- except OSError, exc:
- print "Could not create user directory."
-
- if path != None:
- return os.path.join(base, path)
- else:
- return base
-
-def get_logs_path(path=None):
- base = get_profile_path('logs')
- if path != None:
- return os.path.join(base, path)
- else:
- return base
-
-def get_user_activities_path():
- return os.path.expanduser('~/Activities')
-
-def get_user_library_path():
- return os.path.expanduser('~/Library')
-
-def get_locale_path(path=None):
- return _get_prefix_path('share/locale', path)
-
-def get_bin_path(path=None):
- return _get_sugar_path('bin', path)
-
-def get_service_path(name):
- return _get_sugar_path('services', name)
-
-def get_shell_path(path=None):
- return _get_sugar_path('shell', path)
-
-def get_data_path(path=None):
- return _get_sugar_path('data', path)
diff --git a/sugar/graphics/Makefile.am b/sugar/graphics/Makefile.am
deleted file mode 100644
index df2f472..0000000
--- a/sugar/graphics/Makefile.am
+++ /dev/null
@@ -1,26 +0,0 @@
-sugardir = $(pythondir)/sugar/graphics
-sugar_PYTHON = \
- __init__.py \
- alert.py \
- animator.py \
- combobox.py \
- entry.py \
- icon.py \
- iconentry.py \
- menuitem.py \
- notebook.py \
- objectchooser.py \
- radiotoolbutton.py \
- palette.py \
- palettegroup.py \
- panel.py \
- roundbox.py \
- spreadlayout.py \
- style.py \
- toggletoolbutton.py \
- toolbox.py \
- toolbutton.py \
- toolcombobox.py \
- tray.py \
- window.py \
- xocolor.py
diff --git a/sugar/graphics/__init__.py b/sugar/graphics/__init__.py
deleted file mode 100644
index 1e7e0f9..0000000
--- a/sugar/graphics/__init__.py
+++ /dev/null
@@ -1,18 +0,0 @@
-"""Graphics/controls for use in Sugar"""
-
-# 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.
diff --git a/sugar/graphics/alert.py b/sugar/graphics/alert.py
deleted file mode 100644
index ef93a5a..0000000
--- a/sugar/graphics/alert.py
+++ /dev/null
@@ -1,230 +0,0 @@
-# Copyright (C) 2007, One Laptop Per Child
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the
-# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-# Boston, MA 02111-1307, USA.
-
-from gettext import gettext as _
-
-import gtk
-import gobject
-import hippo
-import math
-
-from sugar.graphics import style
-from sugar.graphics.icon import Icon
-
-
-class Alert(gtk.EventBox, gobject.GObject):
- """UI interface for Alerts
-
- Alerts are used inside the activity window instead of being a
- separate popup window. They do not hide canvas content. You can
- use add_alert(widget) and remove_alert(widget) inside your activity
- to add and remove the alert. You can set the position (bottom=-1,
- top=0,1) for alerts global for the window by changing alert_position,
- default is bottom.
-
- Properties:
- 'title': the title of the alert,
- 'message': the message of the alert,
- 'icon': the icon that appears at the far left
- See __gproperties__
- """
-
- __gtype_name__ = 'SugarAlert'
-
- __gsignals__ = {
- 'response': (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([object]))
- }
-
- __gproperties__ = {
- 'title' : (str, None, None, None,
- gobject.PARAM_READWRITE),
- 'msg' : (str, None, None, None,
- gobject.PARAM_READWRITE),
- 'icon' : (object, None, None,
- gobject.PARAM_WRITABLE)
- }
-
- def __init__(self, **kwargs):
- gobject.GObject.__init__(self)
-
- self.set_visible_window(True)
- self._hbox = gtk.HBox()
- self.add(self._hbox)
-
- self._title = None
- self._msg = None
- self._icon = None
- self._timeout = 0
- self._buttons = {}
-
- self._msg_box = gtk.VBox()
- self._title_label = gtk.Label()
- size = style.zoom(style.GRID_CELL_SIZE * 0.5)
- self._title_label.set_alignment(0, 0.5)
- self._title_label.set_padding(style.DEFAULT_SPACING, 0)
- self._msg_box.pack_start(self._title_label, False)
- self._title_label.show()
-
- self._msg_label = gtk.Label()
- self._msg_label.set_alignment(0, 0.5)
- self._msg_label.set_padding(style.DEFAULT_SPACING, 0)
- self._msg_box.pack_start(self._msg_label, False)
- self._msg_label.show()
- self._hbox.pack_start(self._msg_box)
-
- self._buttons_box = gtk.HButtonBox()
- self._buttons_box.set_layout(gtk.BUTTONBOX_END)
- self._buttons_box.set_spacing(style.DEFAULT_SPACING)
- self._hbox.pack_start(self._buttons_box)
- self._buttons_box.show()
-
- self._msg_box.show()
-
- self._hbox.show()
- self.show()
-
- def do_set_property(self, pspec, value):
- if pspec.name == 'title':
- if self._title != value:
- self._title = value
- self._title_label.set_markup("<b>" + self._title + "</b>")
- elif pspec.name == 'msg':
- if self._msg != value:
- self._msg = value
- self._msg_label.set_markup(self._msg)
- elif pspec.name == 'icon':
- if self._icon != value:
- self._icon = value
- self._hbox.pack_start(self._icon)
- self._hbox.reorder_child(self._icon, 0)
-
- def do_get_property(self, pspec):
- if pspec.name == 'title':
- return self._title
- elif pspec.name == 'msg':
- return self._msg
-
- def add_button(self, response_id, label, icon=None, position=-1):
- """Add a button to the alert
-
- response_id: will be emitted with the response signal
- a response ID should one of the pre-defined
- GTK Response Type Constants or a positive number
- label: that will occure right to the buttom
- icon: this can be a SugarIcon or a gtk.Image
- position: the position of the button in the box (optional)
- """
- button = gtk.Button()
- self._buttons[response_id] = button
- if icon is not None:
- button.set_image(icon)
- button.set_label(label)
- self._buttons_box.pack_start(button)
- button.show()
- button.connect('clicked', self.__button_clicked_cb, response_id)
- if position != -1:
- self._buttons_box.reorder_child(button, position)
- return button
-
- def remove_button(self, response_id):
- """Remove a button from the alert by the given button id"""
- self._buttons_box.remove(self._buttons[id])
-
- def _response(self, id):
- """Emitting response when we have a result
-
- A result can be that a user has clicked a button or
- a timeout has occured, the id identifies the button
- that has been clicked and -1 for a timeout
- """
- self.emit('response', id)
-
- def __button_clicked_cb(self, button, response_id):
- self._response(response_id)
-
-
-class ConfirmationAlert(Alert):
- """This is a ready-made two button (Cancel,Ok) alert"""
-
- def __init__(self, **kwargs):
- Alert.__init__(self, **kwargs)
-
- icon = Icon(icon_name='dialog-cancel')
- cancel_button = self.add_button(gtk.RESPONSE_CANCEL, _('Cancel'), icon)
- icon.show()
-
- icon = Icon(icon_name='dialog-ok')
- ok_button = self.add_button(gtk.RESPONSE_OK, _('Ok'), icon)
- icon.show()
-
-
-class _TimeoutIcon(hippo.CanvasText, hippo.CanvasItem):
- __gtype_name__ = 'AlertTimeoutIcon'
-
- def __init__(self, **kwargs):
- hippo.CanvasText.__init__(self, **kwargs)
-
- self.props.orientation = hippo.ORIENTATION_HORIZONTAL
- self.props.border_left = style.DEFAULT_SPACING
- self.props.border_right = style.DEFAULT_SPACING
-
- def do_paint_background(self, cr, damaged_box):
- [width, height] = self.get_allocation()
-
- x = width * 0.5
- y = height * 0.5
- radius = min(width * 0.5, height * 0.5)
-
- hippo.cairo_set_source_rgba32(cr, self.props.background_color)
- cr.arc(x, y, radius, 0, 2*math.pi)
- cr.fill_preserve()
-
-
-class TimeoutAlert(Alert):
- """This is a ready-made two button (Cancel,Continue) alert
-
- It times out with a positive reponse after the given amount of seconds.
- """
-
- def __init__(self, timeout=5, **kwargs):
- Alert.__init__(self, **kwargs)
-
- self._timeout = timeout
-
- icon = Icon(icon_name='dialog-cancel')
- cancel_button = self.add_button(gtk.RESPONSE_CANCEL, _('Cancel'), icon)
- icon.show()
-
- self._timeout_text = _TimeoutIcon(
- text=self._timeout,
- color=style.COLOR_BUTTON_GREY.get_int(),
- background_color=style.COLOR_WHITE.get_int())
- canvas = hippo.Canvas()
- canvas.set_root(self._timeout_text)
- canvas.show()
- self.add_button(gtk.RESPONSE_OK, _('Continue'), canvas)
-
- gobject.timeout_add(1000, self.__timeout)
-
- def __timeout(self):
- self._timeout -= 1
- self._timeout_text.props.text = self._timeout
- if self._timeout == 0:
- self._response(gtk.RESPONSE_OK)
- return False
- return True
diff --git a/sugar/graphics/animator.py b/sugar/graphics/animator.py
deleted file mode 100644
index 459851b..0000000
--- a/sugar/graphics/animator.py
+++ /dev/null
@@ -1,94 +0,0 @@
-# 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 time
-
-import gobject
-
-EASE_OUT_EXPO = 0
-EASE_IN_EXPO = 1
-
-class Animator(gobject.GObject):
- __gsignals__ = {
- 'completed': (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([])),
- }
-
- def __init__(self, time, fps=20, easing=EASE_OUT_EXPO):
- gobject.GObject.__init__(self)
- self._animations = []
- self._time = time
- self._interval = 1.0 / fps
- self._easing = easing
- self._timeout_sid = 0
-
- def add(self, animation):
- self._animations.append(animation)
-
- def remove_all(self):
- self.stop()
- self._animations = []
-
- def start(self):
- if self._timeout_sid:
- self.stop()
-
- self._start_time = time.time()
- self._timeout_sid = gobject.timeout_add(
- int(self._interval * 1000), self._next_frame_cb)
-
- def stop(self):
- if self._timeout_sid:
- gobject.source_remove(self._timeout_sid)
- self._timeout_sid = 0
- self.emit('completed')
-
- def _next_frame_cb(self):
- current_time = min(self._time, time.time() - self._start_time)
- current_time = max(current_time, 0.0)
-
- for animation in self._animations:
- animation.do_frame(current_time, self._time, self._easing)
-
- if current_time == self._time:
- self.stop()
- return False
- else:
- return True
-
-class Animation(object):
- def __init__(self, start, end):
- self.start = start
- self.end = end
-
- def do_frame(self, time, duration, easing):
- start = self.start
- change = self.end - self.start
-
- if time == duration:
- # last frame
- frame = self.end
- else:
- if easing == EASE_OUT_EXPO:
- frame = change * (-pow(2, -10 * time/duration) + 1) + start;
- elif easing == EASE_IN_EXPO:
- frame = change * pow(2, 10 * (time / duration - 1)) + start;
-
- self.next_frame(frame)
-
- def next_frame(self, frame):
- pass
diff --git a/sugar/graphics/combobox.py b/sugar/graphics/combobox.py
deleted file mode 100644
index 5584267..0000000
--- a/sugar/graphics/combobox.py
+++ /dev/null
@@ -1,114 +0,0 @@
-# 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 sys
-import os
-import logging
-
-import gobject
-import gtk
-
-class ComboBox(gtk.ComboBox):
- __gtype_name__ = 'SugarComboBox'
-
- __gproperties__ = {
- 'value' : (object, None, None,
- gobject.PARAM_READABLE)
- }
- def __init__(self):
- gtk.ComboBox.__init__(self)
-
- self._text_renderer = None
- self._icon_renderer = None
-
- self._model = gtk.ListStore(gobject.TYPE_PYOBJECT,
- gobject.TYPE_STRING,
- gtk.gdk.Pixbuf,
- gobject.TYPE_BOOLEAN)
- self.set_model(self._model)
-
- self.set_row_separator_func(self._is_separator)
-
- def do_get_property(self, pspec):
- if pspec.name == 'value':
- row = self.get_active_item()
- if not row:
- return None
- return row[0]
- else:
- return gtk.ComboBox.do_get_property(self, pspec)
-
- def _get_real_name_from_theme(self, name, size):
- icon_theme = gtk.icon_theme_get_default()
- width, height = gtk.icon_size_lookup(size)
- info = icon_theme.lookup_icon(name, width, 0)
- if not info:
- raise ValueError("Icon '" + name + "' not found.")
- fname = info.get_filename()
- del info
- return fname
-
- 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()
- w, h = gtk.icon_size_lookup_for_settings(settings, gtk.ICON_SIZE_MENU)
- self._icon_renderer.props.stock_size = w
-
- self.pack_start(self._icon_renderer, False)
- self.add_attribute(self._icon_renderer, 'pixbuf', 2)
-
- if not self._text_renderer and text:
- self._text_renderer = gtk.CellRendererText()
- self.pack_end(self._text_renderer, True)
- self.add_attribute(self._text_renderer, 'text', 1)
-
- 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:
- 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
-
- self._model.append([action_id, text, pixbuf, False])
-
- def append_separator(self):
- self._model.append([0, None, None, True])
-
- def get_active_item(self):
- index = self.get_active()
- if index == -1:
- index = 0
-
- row = self._model.iter_nth_child(None, index)
- if not row:
- return None
- return self._model[row]
-
- def remove_all(self):
- self._model.clear()
-
- def _is_separator(self, model, row):
- action_id, text, icon_name, is_separator = model[row]
- return is_separator
diff --git a/sugar/graphics/entry.py b/sugar/graphics/entry.py
deleted file mode 100644
index 95510e5..0000000
--- a/sugar/graphics/entry.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# 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
-import hippo
-
-class CanvasEntry(hippo.CanvasEntry):
- def set_background(self, color_spec):
- color = gtk.gdk.color_parse(color_spec)
- self.props.widget.modify_bg(gtk.STATE_INSENSITIVE, color)
- self.props.widget.modify_base(gtk.STATE_INSENSITIVE, color)
diff --git a/sugar/graphics/icon.py b/sugar/graphics/icon.py
deleted file mode 100644
index cbff3f9..0000000
--- a/sugar/graphics/icon.py
+++ /dev/null
@@ -1,504 +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 os
-import re
-import math
-import time
-import logging
-
-import gobject
-import gtk
-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
-from sugar.util import LRU
-
-_BADGE_SIZE = 0.45
-
-class _SVGLoader(object):
- def __init__(self):
- self._cache = LRU(50)
-
- def load(self, file_name, entities, cache):
- if file_name in self._cache:
- icon = self._cache[file_name]
- else:
- icon_file = open(file_name, 'r')
- icon = icon_file.read()
- icon_file.close()
-
- if cache:
- self._cache[file_name] = icon
-
- for entity, value in entities.items():
- if isinstance(value, basestring):
- xml = '<!ENTITY %s "%s">' % (entity, value)
- icon = re.sub('<!ENTITY %s .*>' % entity, xml, icon)
- else:
- logging.error(
- 'Icon %s, entity %s is invalid.', file_name, entity)
-
- return rsvg.Handle(data=icon)
-
-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):
- _surface_cache = LRU(50)
- _loader = _SVGLoader()
-
- def __init__(self):
- 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
- self.cache = False
-
- 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._loader.load(file_name, entities, self.cache)
-
- 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._loader.load(badge_file_name, {}, self.cache)
- 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, padding):
- if self.width is not None and self.height is not None:
- width = self.width + padding
- height = self.height + padding
- else:
- width = icon_width + padding
- height = icon_height + padding
-
- 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_xo_color(self):
- if self.stroke_color and self.fill_color:
- return XoColor('%s,%s' % (self.stroke_color, self.fill_color))
- else:
- return None
-
- def _set_xo_color(self, xo_color):
- if xo_color:
- self.stroke_color = xo_color.get_stroke_color()
- self.fill_color = xo_color.get_fill_color()
- else:
- self.stroke_color = None
- self.fill_color = None
-
- def get_surface(self):
- cache_key = self._get_cache_key()
- if cache_key in self._surface_cache:
- 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)
-
- padding = badge_info.icon_padding
- width, height = self._get_size(icon_width, icon_height, padding)
- surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
-
- context = cairo.Context(surface)
- 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)
-
- self._surface_cache[cache_key] = surface
-
- return surface
-
- xo_color = property(_get_xo_color, _set_xo_color)
-
-class Icon(gtk.Image):
- __gtype_name__ = 'SugarIcon'
-
- __gproperties__ = {
- 'xo-color' : (object, None, None,
- gobject.PARAM_WRITABLE),
- '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, **kwargs):
- self._buffer = _IconBuffer()
-
- gobject.GObject.__init__(self, **kwargs)
-
- def _sync_image_properties(self):
- if self._buffer.icon_name != self.props.icon_name:
- self._buffer.icon_name = self.props.icon_name
-
- if self._buffer.file_name != self.props.file:
- self._buffer.file_name = self.props.file
-
- 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
-
- def _icon_size_changed_cb(self, image, pspec):
- self._buffer.icon_size = self.props.icon_size
-
- def _icon_name_changed_cb(self, image, pspec):
- self._buffer.icon_name = self.props.icon_name
-
- def _file_changed_cb(self, image, pspec):
- self._buffer.file_name = self.props.file
-
- def _update_buffer_size(self):
- width, height = gtk.icon_size_lookup(self.props.icon_size)
-
- self._buffer.width = width
- self._buffer.height = height
-
- def do_size_request(self, requisition):
- self._sync_image_properties()
- surface = self._buffer.get_surface()
- if surface:
- requisition[0] = surface.get_width()
- requisition[1] = surface.get_height()
- elif self._buffer.width and self._buffer.height:
- requisition[0] = self._buffer.width
- requisition[1] = self._buffer.width
- else:
- requisition[0] = requisition[1] = 0
-
- def do_expose_event(self, event):
- self._sync_image_properties()
- surface = self._buffer.get_surface()
- if surface is None:
- return
-
- xpad, ypad = self.get_padding()
- xalign, yalign = self.get_alignment()
- requisition = self.get_child_requisition()
- if self.get_direction != gtk.TEXT_DIR_LTR:
- xalign = 1.0 - xalign
-
- x = math.floor(self.allocation.x + xpad +
- (self.allocation.width - requisition[0]) * xalign)
- y = math.floor(self.allocation.y + ypad +
- (self.allocation.height - requisition[1]) * yalign)
-
- cr = self.window.cairo_create()
- cr.set_source_surface(surface, x, y)
- cr.paint()
-
- def do_set_property(self, pspec, value):
- if pspec.name == 'xo-color':
- if self._buffer.xo_color != value:
- self._buffer.xo_color = value
- self.queue_draw()
- elif pspec.name == 'fill-color':
- if self._buffer.fill_color != value:
- self._buffer.fill_color = value
- self.queue_draw()
- elif pspec.name == 'stroke-color':
- if self._buffer.stroke_color != value:
- self._buffer.stroke_color = value
- self.queue_draw()
- elif pspec.name == 'badge-name':
- if self._buffer.badge_name != value:
- self._buffer.badge_name = value
- self.queue_resize()
- else:
- gtk.Image.do_set_property(self, pspec, value)
-
- def do_get_property(self, pspec):
- if pspec.name == 'fill-color':
- return self._buffer.fill_color
- elif pspec.name == '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' : (bool, None, None, False,
- 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':
- if self._buffer.file_name != value:
- self._buffer.file_name = value
- self.emit_paint_needed(0, 0, -1, -1)
- elif pspec.name == 'icon-name':
- if self._buffer.icon_name != value:
- self._buffer.icon_name = value
- self.emit_paint_needed(0, 0, -1, -1)
- elif pspec.name == 'xo-color':
- if self._buffer.xo_color != value:
- self._buffer.xo_color = value
- self.emit_paint_needed(0, 0, -1, -1)
- elif pspec.name == 'fill-color':
- if self._buffer.fill_color != value:
- self._buffer.fill_color = value
- self.emit_paint_needed(0, 0, -1, -1)
- elif pspec.name == 'stroke-color':
- if self._buffer.stroke_color != value:
- self._buffer.stroke_color = value
- self.emit_paint_needed(0, 0, -1, -1)
- elif pspec.name == 'size':
- if self._buffer.width != value:
- self._buffer.width = value
- self._buffer.height = value
- self.emit_request_changed()
- elif pspec.name == 'scale':
- if self._buffer.scale != value:
- self._buffer.scale = value
- self.emit_request_changed()
- elif pspec.name == 'cache':
- self._buffer.cache = value
- elif pspec.name == 'badge-name':
- if self._buffer.badge_name != value:
- 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':
- return self._buffer.cache
- 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):
- if self._palette is not None:
- self._palette.props.invoker = None
- 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
diff --git a/sugar/graphics/iconentry.py b/sugar/graphics/iconentry.py
deleted file mode 100644
index 2f7584f..0000000
--- a/sugar/graphics/iconentry.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# 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 gtk
-
-from sugar import _sugaruiext
-
-ICON_ENTRY_PRIMARY = _sugaruiext.ICON_ENTRY_PRIMARY
-ICON_ENTRY_SECONDARY = _sugaruiext.ICON_ENTRY_SECONDARY
-
-class IconEntry(_sugaruiext.IconEntry):
- def set_icon_from_name(self, position, name):
- icon_theme = gtk.icon_theme_get_default()
- icon_info = icon_theme.lookup_icon(name,
- gtk.ICON_SIZE_SMALL_TOOLBAR,
- 0)
-
- pixbuf = gtk.gdk.pixbuf_new_from_file(icon_info.get_filename())
-
- image = gtk.Image()
- image.set_from_pixbuf(pixbuf)
- image.show()
-
- self.set_icon(position, image)
-
- def set_icon(self, position, image):
- if image.get_storage_type() not in [gtk.IMAGE_PIXBUF, gtk.IMAGE_STOCK]:
- raise ValueError('Image must have a storage type of pixbuf or ' +
- 'stock, not %r.' % image.get_storage_type())
- _sugaruiext.IconEntry.set_icon(self, position, image)
-
diff --git a/sugar/graphics/menuitem.py b/sugar/graphics/menuitem.py
deleted file mode 100644
index 5b457a5..0000000
--- a/sugar/graphics/menuitem.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright (C) 2007, Eduardo Silva <edsiper@gmail.com>
-#
-# 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 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_name, icon_size=gtk.ICON_SIZE_MENU)
- self.set_image(icon)
- icon.show()
-
diff --git a/sugar/graphics/notebook.py b/sugar/graphics/notebook.py
deleted file mode 100644
index 2d49b1f..0000000
--- a/sugar/graphics/notebook.py
+++ /dev/null
@@ -1,115 +0,0 @@
-"""Notebook class
-
-This class create a gtk.Notebook() widget supporting
-a close button in every tab when the 'can-close-tabs' gproperty
-is enabled (True)
-"""
-
-# Copyright (C) 2007, Eduardo Silva (edsiper@gmail.com)
-#
-# 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
-import gobject
-
-class Notebook(gtk.Notebook):
- __gtype_name__ = 'SugarNotebook'
-
- __gproperties__ = {
- 'can-close-tabs': (bool, None, None, False,
- gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT_ONLY)
- }
-
- def __init__(self, **kwargs):
- # Initialise the Widget
- #
- # Side effects:
- # Set the 'can-close-tabs' property using **kwargs
- # Set True the scrollable notebook property
-
- gobject.GObject.__init__(self, **kwargs)
- gtk.Notebook.__init__(self)
-
- self.set_scrollable(True)
- self.show()
-
- def do_set_property(self, pspec, value):
- if pspec.name == 'can-close-tabs':
- self._can_close_tabs = value
- else:
- raise AssertionError
-
- def _add_icon_to_button(self, button):
- icon_box = gtk.HBox()
- image = gtk.Image()
- image.set_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU)
- gtk.Button.set_relief(button, gtk.RELIEF_NONE)
-
- settings = gtk.Widget.get_settings(button)
- (w,h) = gtk.icon_size_lookup_for_settings(settings, gtk.ICON_SIZE_MENU)
- gtk.Widget.set_size_request(button, w + 4, h + 4)
- image.show()
- icon_box.pack_start(image, True, False, 0)
- button.add(icon_box)
- icon_box.show()
-
- def _create_custom_tab(self, text, child):
- event_box = gtk.EventBox()
-
- tab_box = gtk.HBox(False, 2)
- tab_label = gtk.Label(text)
-
- tab_button = gtk.Button()
- tab_button.connect('clicked', self._close_page, child)
-
- # Add a picture on a button
- self._add_icon_to_button(tab_button)
- icon_box = gtk.HBox(False, 0)
-
- event_box.show()
- tab_button.show()
- tab_label.show()
-
- tab_box.pack_start(tab_label, True)
- tab_box.pack_start(tab_button, True)
-
- tab_box.show_all()
- event_box.add(tab_box)
-
- return event_box
-
- def add_page(self, text_label, widget):
- # Add a new page to the notebook
- if self._can_close_tabs:
- eventbox = self._create_custom_tab(text_label, widget)
- self.append_page(widget, eventbox)
- else:
- self.append_page(widget, gtk.Label(text_label))
-
- pages = self.get_n_pages()
-
- # Set the new page
- self.set_current_page(pages - 1)
- self.show_all()
-
- return True
-
- def _close_page(self, button, child):
- # Remove a page from the notebook
- page = self.page_num(child)
-
- if page != -1:
- self.remove_page(page)
diff --git a/sugar/graphics/objectchooser.py b/sugar/graphics/objectchooser.py
deleted file mode 100644
index 114665f..0000000
--- a/sugar/graphics/objectchooser.py
+++ /dev/null
@@ -1,209 +0,0 @@
-# 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 logging
-import time
-from gettext import gettext as _
-
-import gtk
-import hippo
-
-from sugar.bundle.activitybundle import ActivityBundle
-from sugar.graphics import style
-from sugar.graphics.icon import CanvasIcon
-from sugar.graphics.xocolor import XoColor
-from sugar.graphics.roundbox import CanvasRoundBox
-from sugar.datastore import datastore
-from sugar import activity
-from sugar.objects import objecttype
-
-# TODO: Activities should request the Journal to open objectchooser dialogs. In
-# that way, we'll be able to reuse most of this code inside the Journal.
-
-class ObjectChooser(gtk.Dialog):
- def __init__(self, title=None, parent=None, flags=0):
- gtk.Dialog.__init__(self, title, parent, flags, (gtk.STOCK_CANCEL,
- gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
-
- self._jobjects = None
- self._query = {}
- self._selected_entry = False
-
- self._box = hippo.CanvasBox()
- self._box.props.background_color = style.COLOR_PANEL_GREY.get_int()
- self._box.props.spacing = style.DEFAULT_SPACING
- self._box.props.padding = style.DEFAULT_SPACING
-
- canvas = hippo.Canvas()
- canvas.set_root(self._box)
-
- scrolled_window = gtk.ScrolledWindow()
- scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
-
- scrolled_window.add_with_viewport(canvas)
- canvas.show()
-
- self.vbox.add(scrolled_window)
- scrolled_window.show()
-
- scrolled_window.props.shadow_type = gtk.SHADOW_NONE
- scrolled_window.get_child().props.shadow_type = gtk.SHADOW_NONE
-
- self.refresh()
-
- height = self.get_screen().get_height() * 3 / 4
- width = self.get_screen().get_width() * 3 / 4
- self.set_default_size(width, height)
-
- def update_with_query(self, query):
- self._query = query
- self.refresh()
-
- def refresh(self):
- logging.debug('ListView.refresh: %r' % self._query)
- self._jobjects, total_count = datastore.find(self._query, sorting=['-mtime'])
- self._update()
-
- def _update(self):
- self._box.remove_all()
- for jobject in self._jobjects:
- entry_view = CollapsedEntry(jobject)
- entry_view.connect('button-release-event',
- self._entry_view_button_release_event_cb)
- self._box.append(entry_view)
-
- def _entry_view_button_release_event_cb(self, entry_view, event):
- if self._selected_entry:
- self._selected_entry.set_selected(False)
- entry_view.set_selected(True)
- self._selected_entry = entry_view
-
- def get_selected_object(self):
- if self._selected_entry:
- return self._selected_entry.jobject
- else:
- return None
-
-class CollapsedEntry(CanvasRoundBox):
- _DATE_COL_WIDTH = style.zoom(100)
- _BUDDIES_COL_WIDTH = style.zoom(50)
-
- def __init__(self, jobject):
- CanvasRoundBox.__init__(self)
- self.props.box_height = style.zoom(75)
- self.props.spacing = style.DEFAULT_SPACING
- self.props.border_color = style.COLOR_BLACK.get_int()
- self.props.background_color = style.COLOR_PANEL_GREY.get_int()
-
- self.jobject = jobject
- self._icon_name = None
-
- date = hippo.CanvasText(text=self._format_date(),
- xalign=hippo.ALIGNMENT_START,
- font_desc=style.FONT_NORMAL.get_pango_desc(),
- box_width=self._DATE_COL_WIDTH)
- self.append(date)
-
- icon = CanvasIcon(icon_name=self._get_icon_name(),
- box_width=style.zoom(75))
-
- if self.jobject.metadata.has_key('icon-color'):
- icon.props.xo_color = XoColor(self.jobject.metadata['icon-color'])
-
- self.append(icon)
-
- title = hippo.CanvasText(text=self._format_title(),
- xalign=hippo.ALIGNMENT_START,
- font_desc=style.FONT_BOLD.get_pango_desc(),
- size_mode=hippo.CANVAS_SIZE_WRAP_WORD)
- self.append(title)
-
- def _get_icon_name(self):
- if self._icon_name:
- return self._icon_name
-
- if self.jobject.is_activity_bundle():
- bundle = ActivityBundle(self.jobject.file_path)
- self._icon_name = bundle.get_icon()
-
- if self.jobject.metadata['activity']:
- service_name = self.jobject.metadata['activity']
- activity_info = activity.get_registry().get_activity(service_name)
- if activity_info:
- self._icon_name = activity_info.icon
-
- mime_type = self.jobject.metadata['mime_type']
- if not self._icon_name and mime_type:
- type = objecttype.get_registry().get_type_for_mime(mime_type)
- if type:
- self._icon_name = type.icon
-
- if not self._icon_name:
- self._icon_name = 'image-missing'
-
- return self._icon_name
-
- def _format_date(self):
- """ Convert from a string in iso format to a more human-like format. """
- return _get_elapsed_string(self.jobject.metadata['mtime'])
-
- def _format_title(self):
- return '"%s"' % self.jobject.metadata['title']
-
- def set_selected(self, selected):
- if selected:
- self.props.border_color = style.COLOR_WHITE.get_int()
- self.props.background_color = style.COLOR_WHITE.get_int()
- else:
- self.props.border_color = style.COLOR_BLACK.get_int()
- self.props.background_color = style.COLOR_PANEL_GREY.get_int()
-
-def _get_elapsed_string(date_string, max_levels=2):
- ti = time.strptime(date_string, "%Y-%m-%dT%H:%M:%S")
-
- units = [[_('%d year'), _('%d years'), 356 * 24 * 60 * 60],
- [_('%d month'), _('%d months'), 30 * 24 * 60 * 60],
- [_('%d week'), _('%d weeks'), 7 * 24 * 60 * 60],
- [_('%d day'), _('%d days'), 24 * 60 * 60],
- [_('%d hour'), _('%d hours'), 60 * 60],
- [_('%d minute'), _('%d minutes'), 60],
- [_('%d second'), _('%d seconds'), 1]]
- levels = 0
- result = ''
- elapsed_seconds = int(time.time() - time.mktime(ti))
- for name_singular, name_plural, factor in units:
- elapsed_units = elapsed_seconds / factor
- if elapsed_units > 0:
-
- if levels > 0:
- if max_levels - levels == 1:
- result += _(' and ')
- else:
- result += _(', ')
-
- if elapsed_units == 1:
- result += name_singular % elapsed_units
- else:
- result += name_plural % elapsed_units
- elapsed_seconds -= elapsed_units * factor
- levels += 1
-
- if levels == max_levels:
- break
-
- return result
-
diff --git a/sugar/graphics/palette.py b/sugar/graphics/palette.py
deleted file mode 100644
index 70cf453..0000000
--- a/sugar/graphics/palette.py
+++ /dev/null
@@ -1,722 +0,0 @@
-# Copyright (C) 2007, Eduardo Silva <edsiper@gmail.com>
-#
-# 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 gtk
-import gobject
-import time
-import hippo
-
-from sugar.graphics import palettegroup
-from sugar.graphics import animator
-from sugar.graphics import style
-from sugar import _sugaruiext
-
-# Helper function to find the gap position and size of widget a
-def _calculate_gap(a, b):
- # Test for each side if the palette and invoker are
- # adjacent to each other.
- gap = True
-
- if a.y + a.height == b.y:
- gap_side = gtk.POS_BOTTOM
- elif a.x + a.width == b.x:
- gap_side = gtk.POS_RIGHT
- elif a.x == b.x + b.width:
- gap_side = gtk.POS_LEFT
- elif a.y == b.y + b.height:
- gap_side = gtk.POS_TOP
- else:
- gap = False
-
- if gap:
- if gap_side == gtk.POS_BOTTOM or gap_side == gtk.POS_TOP:
- gap_start = min(a.width, max(0, b.x - a.x))
- gap_size = max(0, min(a.width,
- (b.x + b.width) - a.x) - gap_start)
- elif gap_side == gtk.POS_RIGHT or gap_side == gtk.POS_LEFT:
- gap_start = min(a.height, max(0, b.y - a.y))
- gap_size = max(0, min(a.height,
- (b.y + b.height) - a.y) - gap_start)
-
- if gap and gap_size > 0:
- return (gap_side, gap_start, gap_size)
- else:
- return False
-
-class Palette(gtk.Window):
- PRIMARY = 0
- SECONDARY = 1
-
- __gtype_name__ = 'SugarPalette'
-
- __gproperties__ = {
- 'invoker' : (object, None, None,
- gobject.PARAM_READWRITE)
- }
-
- __gsignals__ = {
- 'popup' : (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([])),
- 'popdown' : (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([]))
- }
-
- def __init__(self, label, accel_path=None, menu_after_content=False):
- gtk.Window.__init__(self)
-
- self.set_decorated(False)
- self.set_resizable(False)
- # Just assume xthickness and ythickness are the same
- self.set_border_width(self.style.xthickness)
- self.connect('realize', self._realize_cb)
-
- self.palette_state = self.PRIMARY
-
- self._alignment = None
- self._old_alloc = None
- self._full_request = [0, 0]
- self._cursor_x = 0
- self._cursor_y = 0
- self._invoker = None
- self._group_id = None
- self._up = False
- self._palette_popup_sid = None
-
- self._popup_anim = animator.Animator(0.3, 10)
- self._popup_anim.add(_PopupAnimation(self))
-
- self._secondary_anim = animator.Animator(1.0, 10)
- self._secondary_anim.add(_SecondaryAnimation(self))
-
- self._popdown_anim = animator.Animator(0.6, 10)
- self._popdown_anim.add(_PopdownAnimation(self))
-
- vbox = gtk.VBox()
-
- self._label = gtk.Label()
- self._label.set_size_request(-1, style.zoom(style.GRID_CELL_SIZE))
- self._label.set_alignment(0, 0.5)
- self._label.set_padding(style.zoom(15), 0)
- vbox.pack_start(self._label, False)
-
- self._secondary_box = gtk.VBox()
- vbox.pack_start(self._secondary_box)
-
- self._separator = gtk.HSeparator()
- self._secondary_box.pack_start(self._separator)
-
- self._menu_content_separator = gtk.HSeparator()
-
- if menu_after_content:
- self._add_content()
- self._secondary_box.pack_start(self._menu_content_separator)
- self._add_menu()
- else:
- self._add_menu()
- self._secondary_box.pack_start(self._menu_content_separator)
- self._add_content()
-
- self.action_bar = PaletteActionBar()
- self._secondary_box.pack_start(self.action_bar)
- self.action_bar.show()
-
- self.add(vbox)
- vbox.show()
-
- # The menu is not shown here until an item is added
- self.menu = _Menu(self)
-
- self.connect('enter-notify-event',
- self._enter_notify_event_cb)
- self.connect('leave-notify-event',
- self._leave_notify_event_cb)
-
- self.set_primary_text(label, accel_path)
- self.set_group_id('default')
-
- def _add_menu(self):
- self._menu_box = gtk.VBox()
- self._secondary_box.pack_start(self._menu_box)
- self._menu_box.show()
-
- def _add_content(self):
- # The content is not shown until a widget is added
- self._content = gtk.VBox()
- self._content.set_border_width(style.zoom(15))
- self._secondary_box.pack_start(self._content)
-
- def do_style_set(self, previous_style):
- # Prevent a warning from pygtk
- if previous_style is not None:
- gtk.Window.do_style_set(self, previous_style)
- self.set_border_width(self.style.xthickness)
-
- def is_up(self):
- return self._up
-
- def get_rect(self):
- win_x, win_y = self.window.get_origin()
- rectangle = self.get_allocation()
-
- x = win_x + rectangle.x
- y = win_y + rectangle.y
- width = rectangle.width
- height = rectangle.height
-
- return gtk.gdk.Rectangle(x, y, width, height)
-
- def set_primary_text(self, label, accel_path=None):
- if label is not None:
- self._label.set_markup("<b>"+label+"</b>")
- self._label.show()
-
- def set_content(self, widget):
- if len(self._content.get_children()) > 0:
- self._content.remove(self._content.get_children()[0])
-
- if widget is not None:
- self._content.add(widget)
- self._content.show()
- else:
- self._content.hide()
-
- self._update_accept_focus()
- self._update_separators()
-
- def set_group_id(self, group_id):
- if self._group_id:
- group = palettegroup.get_group(self._group_id)
- group.remove(self)
- if group_id:
- self._group_id = group_id
- group = palettegroup.get_group(group_id)
- group.add(self)
-
- def do_set_property(self, pspec, value):
- if pspec.name == 'invoker':
- if self._invoker is not None:
- self._invoker.disconnect(self._enter_invoker_hid)
- self._invoker.disconnect(self._leave_invoker_hid)
-
- self._invoker = value
- if value is not None:
- self._enter_invoker_hid = self._invoker.connect(
- 'mouse-enter', self._invoker_mouse_enter_cb)
- self._leave_invoker_hid = self._invoker.connect(
- 'mouse-leave', self._invoker_mouse_leave_cb)
- else:
- raise AssertionError
-
- def do_get_property(self, pspec):
- if pspec.name == 'invoker':
- return self._invoker
- else:
- raise AssertionError
-
- def do_size_request(self, requisition):
- gtk.Window.do_size_request(self, requisition)
-
- requisition.width = max(requisition.width, self._full_request[0])
-
- # Minimum width
- requisition.width = max(requisition.width,
- style.zoom(style.GRID_CELL_SIZE*2))
-
- def do_size_allocate(self, allocation):
- gtk.Window.do_size_allocate(self, allocation)
-
- if self._old_alloc is None or \
- self._old_alloc.x != allocation.x or \
- self._old_alloc.y != allocation.y or \
- self._old_alloc.width != allocation.width or \
- self._old_alloc.height != allocation.height:
- self.queue_draw()
-
- # We need to store old allocation because when size_allocate
- # is called widget.allocation is already updated.
- # gtk.Window resizing is different from normal containers:
- # the X window is resized, widget.allocation is updated from
- # the configure request handler and finally size_allocate is called.
- self._old_alloc = allocation
-
- def do_expose_event(self, event):
- # We want to draw a border with a beautiful gap
- if self._invoker is not None and self._invoker.has_rectangle_gap():
- invoker = self._invoker.get_rect()
- palette = self.get_rect()
-
- gap = _calculate_gap(palette, invoker)
- else:
- gap = False
-
- if gap:
- self.style.paint_box_gap(event.window, gtk.STATE_PRELIGHT,
- gtk.SHADOW_IN, event.area, self, "palette",
- 0, 0,
- self.allocation.width,
- self.allocation.height,
- gap[0], gap[1], gap[2])
- else:
- self.style.paint_box(event.window, gtk.STATE_PRELIGHT,
- gtk.SHADOW_IN, event.area, self, "palette",
- 0, 0,
- self.allocation.width,
- self.allocation.height)
-
- # Fall trough to the container expose handler.
- # (Leaving out the window expose handler which redraws everything)
- gtk.Bin.do_expose_event(self, event)
-
- def _update_separators(self):
- visible = len(self.menu.get_children()) > 0 or \
- len(self._content.get_children()) > 0
- self._separator.props.visible = visible
-
- visible = len(self.menu.get_children()) > 0 and \
- len(self._content.get_children()) > 0
- self._menu_content_separator.props.visible = visible
-
- def _update_accept_focus(self):
- accept_focus = len(self._content.get_children())
- if self.window:
- self.window.set_accept_focus(accept_focus)
-
- def _realize_cb(self, widget):
- self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
- self._update_accept_focus()
-
- def _update_full_request(self):
- state = self.palette_state
-
- self._set_state(self.SECONDARY)
- self._full_request = self.size_request()
-
- self._set_state(state)
-
- def _update_position(self):
- invoker = self._invoker
- if invoker is None or self._alignment is None:
- logging.error('Cannot update the palette position.')
- return
-
- rect = self.size_request()
- position = invoker.get_position_for_alignment(self._alignment, rect)
- if position is None:
- position = invoker.get_position(rect)
-
- self.move(position.x, position.y)
-
- def _show(self):
- if self._up:
- return
-
- self._palette_popup_sid = _palette_observer.connect(
- 'popup', self._palette_observer_popup_cb)
-
- if self._invoker is not None:
- self._update_full_request()
- self._alignment = self._invoker.get_alignment(self._full_request)
- self._update_position()
-
- self.menu.set_active(True)
- self.show()
-
- self._invoker.notify_popup()
-
- self._up = True
- _palette_observer.emit('popup', self)
- self.emit('popup')
-
- def _hide(self):
- self._secondary_anim.stop()
-
- if not self._palette_popup_sid is None:
- _palette_observer.disconnect(self._palette_popup_sid)
- self._palette_popup_sid = None
-
- self.menu.set_active(False)
- self.hide()
-
- if self._invoker:
- self._invoker.notify_popdown()
-
- self._up = False
- self.emit('popdown')
-
- def popup(self, immediate=False):
- self._popdown_anim.stop()
-
- if not immediate:
- self._popup_anim.start()
- else:
- self._show()
-
- self._secondary_anim.start()
-
- def popdown(self, immediate=False):
- self._popup_anim.stop()
-
- if not immediate:
- self._popdown_anim.start()
- else:
- self._hide()
-
- def _set_state(self, state):
- if self.palette_state == state:
- return
-
- if state == self.PRIMARY:
- self.menu.unembed()
- self._secondary_box.hide()
- elif state == self.SECONDARY:
- self.menu.embed(self._menu_box)
- self._secondary_box.show()
-
- self.palette_state = state
-
- def _invoker_mouse_enter_cb(self, invoker):
- immediate = False
-
- if self.is_up():
- self._popdown_anim.stop()
- return
-
- if self._group_id:
- group = palettegroup.get_group(self._group_id)
- if group and group.is_up():
- self._set_state(group.get_state())
-
- immediate = True
- group.popdown()
-
- self.popup(immediate=immediate)
-
- def _invoker_mouse_leave_cb(self, invoker):
- self.popdown()
-
- def _enter_notify_event_cb(self, widget, event):
- if event.detail != gtk.gdk.NOTIFY_INFERIOR:
- self._popdown_anim.stop()
- self._secondary_anim.start()
-
- def _leave_notify_event_cb(self, widget, event):
- if event.detail != gtk.gdk.NOTIFY_INFERIOR:
- self.popdown()
-
- def _palette_observer_popup_cb(self, observer, palette):
- if self != palette:
- self._hide()
-
-class PaletteActionBar(gtk.HButtonBox):
- def add_action(label, icon_name=None):
- button = Button(label)
-
- if icon_name:
- icon = Icon(icon_name)
- button.set_image(icon)
- icon.show()
-
- self.pack_start(button)
- button.show()
-
-class _Menu(_sugaruiext.Menu):
- __gtype_name__ = 'SugarPaletteMenu'
-
- def __init__(self, palette):
- _sugaruiext.Menu.__init__(self)
- self._palette = palette
-
- def do_insert(self, item, position):
- _sugaruiext.Menu.do_insert(self, item, position)
- self._palette._update_separators()
- self.show()
-
- def do_expose_event(self, event):
- # Ignore the Menu expose, just do the MenuShell expose to prevent any
- # border from being drawn here. A border is drawn by the palette object
- # around everything.
- gtk.MenuShell.do_expose_event(self, event)
-
- def do_grab_notify(self, was_grabbed):
- # Ignore grab_notify as the menu would close otherwise
- pass
-
- def do_deactivate(self):
- self._palette._hide()
-
-class _PopupAnimation(animator.Animation):
- def __init__(self, palette):
- animator.Animation.__init__(self, 0.0, 1.0)
- self._palette = palette
-
- def next_frame(self, current):
- if current == 1.0:
- self._palette._set_state(Palette.PRIMARY)
- self._palette._show()
-
-class _SecondaryAnimation(animator.Animation):
- def __init__(self, palette):
- animator.Animation.__init__(self, 0.0, 1.0)
- self._palette = palette
-
- def next_frame(self, current):
- if current == 1.0:
- self._palette._set_state(Palette.SECONDARY)
- self._palette._update_position()
-
-class _PopdownAnimation(animator.Animation):
- def __init__(self, palette):
- animator.Animation.__init__(self, 0.0, 1.0)
- self._palette = palette
-
- def next_frame(self, current):
- if current == 1.0:
- self._palette._hide()
-
-class Invoker(gobject.GObject):
- __gtype_name__ = 'SugarPaletteInvoker'
-
- __gsignals__ = {
- 'mouse-enter': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
- 'mouse-leave': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
- 'focus-out': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([]))
- }
-
- ANCHORED = 0
- AT_CURSOR = 1
-
- BOTTOM = [(0.0, 0.0, 0.0, 1.0),
- (-1.0, 0.0, 1.0, 1.0)]
- RIGHT = [(0.0, 0.0, 1.0, 0.0),
- (0.0, -1.0, 1.0, 1.0)]
- TOP = [(0.0, -1.0, 0.0, 0.0),
- (-1.0, -1.0, 1.0, 0.0)]
- LEFT = [(-1.0, 0.0, 0.0, 0.0),
- (-1.0, -1.0, 0.0, 1.0)]
-
- def __init__(self):
- gobject.GObject.__init__(self)
-
- self._screen_area = gtk.gdk.Rectangle(0, 0, gtk.gdk.screen_width(),
- gtk.gdk.screen_height())
- self._position_hint = self.ANCHORED
- self._cursor_x = -1
- self._cursor_y = -1
-
- def _get_position_for_alignment(self, alignment, palette_dim):
- palette_halign = alignment[0]
- palette_valign = alignment[1]
- invoker_halign = alignment[2]
- invoker_valign = alignment[3]
-
- if self._cursor_x == -1 or self._cursor_y == -1:
- display = gtk.gdk.display_get_default()
- screen, x, y, mask = display.get_pointer()
- self._cursor_x = x
- self._cursor_y = y
-
- if self._position_hint is self.ANCHORED:
- rect = self.get_rect()
- else:
- dist = style.PALETTE_CURSOR_DISTANCE
- rect = gtk.gdk.Rectangle(self._cursor_x - dist,
- self._cursor_y - dist,
- dist * 2, dist * 2)
-
- palette_width, palette_height = palette_dim
-
- x = rect.x + rect.width * invoker_halign + \
- palette_width * palette_halign
-
- y = rect.y + rect.height * invoker_valign + \
- palette_height * palette_valign
-
- return gtk.gdk.Rectangle(int(x), int(y),
- palette_width, palette_height)
-
- def _in_screen(self, rect):
- return rect.x >= self._screen_area.x and \
- rect.y >= self._screen_area.y and \
- rect.x + rect.width <= self._screen_area.width and \
- rect.y + rect.height <= self._screen_area.height
-
- def _get_alignments(self):
- if self._position_hint is self.AT_CURSOR:
- return [(0.0, 0.0, 1.0, 1.0),
- (0.0, -1.0, 1.0, 0.0),
- (-1.0, -1.0, 0.0, 0.0),
- (-1.0, 0.0, 0.0, 1.0)]
- else:
- return self.BOTTOM + self.RIGHT + self.TOP + self.LEFT
-
- def get_position_for_alignment(self, alignment, palette_dim):
- rect = self._get_position_for_alignment(alignment, palette_dim)
- if self._in_screen(rect):
- return rect
- else:
- return None
-
- def get_position(self, palette_dim):
- for alignment in self._get_alignments():
- rect = self._get_position_for_alignment(alignment, palette_dim)
- if self._in_screen(rect):
- break
-
- return rect
-
- def get_alignment(self, palette_dim):
- for alignment in self._get_alignments():
- rect = self._get_position_for_alignment(alignment, palette_dim)
- if self._in_screen(rect):
- break
-
- return alignment
-
- def has_rectangle_gap(self):
- return False
-
- def draw_rectangle(self, event, palette):
- pass
-
- def notify_popup(self):
- pass
-
- def notify_popdown(self):
- self._cursor_x = -1
- self._cursor_y = -1
-
-class WidgetInvoker(Invoker):
- def __init__(self, widget):
- Invoker.__init__(self)
- self._widget = widget
-
- widget.connect('enter-notify-event', self._enter_notify_event_cb)
- widget.connect('leave-notify-event', self._leave_notify_event_cb)
-
- def get_rect(self):
- win_x, win_y = self._widget.window.get_origin()
- rectangle = self._widget.get_allocation()
-
- x = win_x + rectangle.x
- y = win_y + rectangle.y
- width = rectangle.width
- height = rectangle.height
-
- return gtk.gdk.Rectangle(x, y, width, height)
-
- def has_rectangle_gap(self):
- return True
-
- def draw_rectangle(self, event, palette):
- style = self._widget.style
- gap = _calculate_gap(self.get_rect(), palette.get_rect())
- if gap:
- style.paint_box_gap(event.window, gtk.STATE_PRELIGHT,
- gtk.SHADOW_IN, event.area, self._widget,
- "palette-invoker",
- self._widget.allocation.x,
- self._widget.allocation.y,
- self._widget.allocation.width,
- self._widget.allocation.height,
- gap[0], gap[1], gap[2])
- else:
- style.paint_box(event.window, gtk.STATE_PRELIGHT,
- gtk.SHADOW_IN, event.area, self._widget,
- "palette-invoker",
- self._widget.allocation.x,
- self._widget.allocation.y,
- self._widget.allocation.width,
- self._widget.allocation.height)
-
- def _enter_notify_event_cb(self, widget, event):
- self.emit('mouse-enter')
-
- def _leave_notify_event_cb(self, widget, event):
- self.emit('mouse-leave')
-
- def get_toplevel(self):
- return self._widget.get_toplevel()
-
- def notify_popup(self):
- Invoker.notify_popup(self)
- self._widget.queue_draw()
-
- def notify_popdown(self):
- Invoker.notify_popdown(self)
- self._widget.queue_draw()
-
-class CanvasInvoker(Invoker):
- def __init__(self, item):
- Invoker.__init__(self)
-
- self._item = item
- self._position_hint = self.AT_CURSOR
-
- item.connect('motion-notify-event',
- self._motion_notify_event_cb)
-
- def get_default_position(self):
- return self.AT_CURSOR
-
- def get_rect(self):
- context = self._item.get_context()
- if context:
- x, y = context.translate_to_screen(self._item)
- width, height = self._item.get_allocation()
- return gtk.gdk.Rectangle(x, y, width, height)
- else:
- return gtk.gdk.Rectangle()
-
- def _motion_notify_event_cb(self, button, event):
- if event.detail == hippo.MOTION_DETAIL_ENTER:
- context = self._item.get_context()
- self.emit('mouse-enter')
- elif event.detail == hippo.MOTION_DETAIL_LEAVE:
- self.emit('mouse-leave')
-
- return False
-
- def get_toplevel(self):
- return hippo.get_canvas_for_item(self._item).get_toplevel()
-
-class ToolInvoker(WidgetInvoker):
- def __init__(self, widget):
- WidgetInvoker.__init__(self, widget.child)
-
- def _get_alignments(self):
- parent = self._widget.get_parent()
- if parent is None:
- return WidgetInvoker.get_alignments()
-
- if parent.get_orientation() is gtk.ORIENTATION_HORIZONTAL:
- return self.BOTTOM + self.TOP
- else:
- return self.LEFT + self.RIGHT
-
-class _PaletteObserver(gobject.GObject):
- __gtype_name__ = 'SugarPaletteObserver'
-
- __gsignals__ = {
- 'popup': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([object]))
- }
-
- def __init__(self):
- gobject.GObject.__init__(self)
-
-_palette_observer = _PaletteObserver()
diff --git a/sugar/graphics/palettegroup.py b/sugar/graphics/palettegroup.py
deleted file mode 100644
index 40d4ca2..0000000
--- a/sugar/graphics/palettegroup.py
+++ /dev/null
@@ -1,90 +0,0 @@
-# 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 gobject
-
-_groups = {}
-
-def get_group(group_id):
- if _groups.has_key(group_id):
- group = _groups[group_id]
- else:
- group = Group()
- _groups[group_id] = group
-
- return group
-
-class Group(gobject.GObject):
- __gsignals__ = {
- 'popup' : (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([])),
- 'popdown' : (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([]))
- }
- def __init__(self):
- gobject.GObject.__init__(self)
- self._up = False
- self._palettes = []
- self._sig_ids = {}
-
- def is_up(self):
- return self._up
-
- def get_state(self):
- for palette in self._palettes:
- if palette.is_up():
- return palette.palette_state
-
- return None
-
- def add(self, palette):
- self._palettes.append(palette)
-
- self._sig_ids[palette] = []
-
- sid = palette.connect('popup', self._palette_popup_cb)
- self._sig_ids[palette].append(sid)
-
- sid = palette.connect('popdown', self._palette_popdown_cb)
- self._sig_ids[palette].append(sid)
-
- def remove(self, palette):
- sig_ids = self._sig_ids[palette]
- for sid in sig_ids:
- palette.disconnect(sid)
-
- self._palettes.remove(palette)
-
- def popdown(self):
- for palette in self._palettes:
- if palette.is_up():
- palette.popdown(immediate=True)
-
- def _palette_popup_cb(self, palette):
- if not self._up:
- self.emit('popup')
- self._up = True
-
- def _palette_popdown_cb(self, palette):
- down = True
- for palette in self._palettes:
- if palette.is_up():
- down = False
-
- if down:
- self._up = False
- self.emit('popdown')
diff --git a/sugar/graphics/panel.py b/sugar/graphics/panel.py
deleted file mode 100644
index bf3ed24..0000000
--- a/sugar/graphics/panel.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# 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/radiotoolbutton.py b/sugar/graphics/radiotoolbutton.py
deleted file mode 100644
index cb4ae25..0000000
--- a/sugar/graphics/radiotoolbutton.py
+++ /dev/null
@@ -1,67 +0,0 @@
-# Copyright (C) 2007, Red Hat, Inc.
-# 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 gtk
-
-from sugar.graphics.icon import Icon
-from sugar.graphics.palette import Palette, ToolInvoker
-
-class RadioToolButton(gtk.RadioToolButton):
- __gtype_name__ = "SugarRadioToolButton"
-
- def __init__(self, named_icon=None, group=None, xo_color=None):
- gtk.RadioToolButton.__init__(self, group=group)
- self._palette = None
- self._xo_color = xo_color
- self.set_named_icon(named_icon)
-
- def set_named_icon(self, 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)
- icon.show()
-
- def get_palette(self):
- return self._palette
-
- def set_palette(self, palette):
- if self._palette is not None:
- self._palette.props.invoker = None
- self._palette = palette
- self._palette.props.invoker = ToolInvoker(self)
-
- def set_tooltip(self, text):
- self.set_palette(Palette(text))
-
- def do_expose_event(self, event):
- if self._palette and self._palette.is_up():
- invoker = self._palette.props.invoker
- invoker.draw_rectangle(event, self._palette)
- elif self.child.state == gtk.STATE_PRELIGHT:
- self.child.style.paint_box(event.window, gtk.STATE_PRELIGHT,
- gtk.SHADOW_NONE, event.area,
- self.child, "toolbutton-prelight",
- self.allocation.x,
- self.allocation.y,
- self.allocation.width,
- self.allocation.height)
-
- gtk.RadioToolButton.do_expose_event(self, event)
-
- palette = property(get_palette, set_palette)
diff --git a/sugar/graphics/roundbox.py b/sugar/graphics/roundbox.py
deleted file mode 100644
index 51b9e7d..0000000
--- a/sugar/graphics/roundbox.py
+++ /dev/null
@@ -1,66 +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 math
-
-import hippo
-
-from sugar.graphics import style
-
-class CanvasRoundBox(hippo.CanvasBox, hippo.CanvasItem):
- __gtype_name__ = 'SugarRoundBox'
-
- _BORDER_DEFAULT = style.LINE_WIDTH
-
- def __init__(self, **kwargs):
- hippo.CanvasBox.__init__(self, **kwargs)
-
- # TODO: we should calculate this value depending on the height of the box.
- self._radius = style.zoom(10)
-
- self.props.orientation = hippo.ORIENTATION_HORIZONTAL
- self.props.border = self._BORDER_DEFAULT
- self.props.border_left = self._radius
- self.props.border_right = self._radius
- self.props.border_color = style.COLOR_BLACK.get_int()
-
- def do_paint_background(self, cr, damaged_box):
- [width, height] = self.get_allocation()
-
- x = self._BORDER_DEFAULT / 2
- y = self._BORDER_DEFAULT / 2
- width -= self._BORDER_DEFAULT
- height -= self._BORDER_DEFAULT
-
- cr.move_to(x + self._radius, y);
- cr.arc(x + width - self._radius, y + self._radius,
- self._radius, math.pi * 1.5, math.pi * 2);
- cr.arc(x + width - self._radius, x + height - self._radius,
- self._radius, 0, math.pi * 0.5);
- cr.arc(x + self._radius, y + height - self._radius,
- self._radius, math.pi * 0.5, math.pi);
- cr.arc(x + self._radius, y + self._radius, self._radius,
- math.pi, math.pi * 1.5);
-
- hippo.cairo_set_source_rgba32(cr, self.props.background_color)
- cr.fill_preserve();
-
- # TODO: we should be more consistent here with the border properties.
- if self.props.border_color:
- hippo.cairo_set_source_rgba32(cr, self.props.border_color)
- cr.set_line_width(self.props.border_top)
- cr.stroke()
diff --git a/sugar/graphics/spreadlayout.py b/sugar/graphics/spreadlayout.py
deleted file mode 100644
index 7bd1ff1..0000000
--- a/sugar/graphics/spreadlayout.py
+++ /dev/null
@@ -1,239 +0,0 @@
-# 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.
-
-from numpy import array
-from random import random
-
-import hippo
-import gobject
-import gtk
-
-_PLACE_TRIALS = 20
-_MAX_WEIGHT = 255
-_CELL_SIZE = 4
-
-class _Grid(gobject.GObject):
- __gsignals__ = {
- 'child-changed' : (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT]))
- }
- def __init__(self, width, height):
- gobject.GObject.__init__(self)
-
- self.width = width
- self.height = height
- self._children = []
- self._collisions = []
- self._collisions_sid = 0
-
- self._array = array([0], dtype='b')
- self._array.resize(width * height)
-
- def add(self, child, width, height):
- trials = _PLACE_TRIALS
- weight = _MAX_WEIGHT
- while trials > 0 and weight:
- x = int(random() * (self.width - width))
- y = int(random() * (self.height - height))
-
- rect = gtk.gdk.Rectangle(x, y, width, height)
- new_weight = self._compute_weight(rect)
- if weight > new_weight:
- weight = new_weight
-
- trials -= 1
-
- child.grid_rect = rect
- child.locked = False
-
- self._add_child(child)
-
- if weight > 0:
- self._detect_collisions(child)
-
- def remove(self, child):
- self._children.remove(child)
- self._remove_weight(child.grid_rect)
- child.grid_rect = None
-
- def _add_child(self, child):
- self._children.append(child)
- self.add_weight(child.grid_rect)
-
- def _move_child(self, child, new_rect):
- self._remove_weight(child.grid_rect)
- self.add_weight(new_rect)
-
- child.grid_rect = new_rect
-
- self.emit('child-changed', child)
-
- def _shift_child(self, child):
- rect = child.grid_rect
- weight = self._compute_weight(rect)
- new_rects = []
-
- if (rect.x + rect.width < self.width - 1):
- new_rects.append(gtk.gdk.Rectangle(rect.x + 1, rect.y,
- rect.width, rect.height))
-
- if (rect.x - 1 > 0):
- new_rects.append(gtk.gdk.Rectangle(rect.x - 1, rect.y,
- rect.width, rect.height))
-
- if (rect.y + rect.height < self.height - 1):
- new_rects.append(gtk.gdk.Rectangle(rect.x, rect.y + 1,
- rect.width, rect.height))
-
- if (rect.y - 1 > 0):
- new_rects.append(gtk.gdk.Rectangle(rect.x, rect.y - 1,
- rect.width, rect.height))
-
- best_rect = None
- for new_rect in new_rects:
- new_weight = self._compute_weight(new_rect)
- if new_weight < weight:
- best_rect = new_rect
- weight = new_weight
-
- if best_rect:
- self._move_child(child, best_rect)
-
- return weight
-
-
- def _solve_collisions(self):
- for collision in self._collisions[:]:
- weight = self._shift_child(collision)
- if not weight:
- self._collisions.remove(collision)
-
- return (len(self._collisions) > 0)
-
- def _detect_collisions(self, child):
- collision_found = False
- for c in self._children:
- intersection = child.grid_rect.intersect(c.grid_rect)
- if c != child and intersection.width > 0:
- if c not in self._collisions:
- collision_found = True
- self._collisions.append(c)
-
- if collision_found:
- if child not in self._collisions:
- self._collisions.append(child)
-
-# if len(self._collisions) and not self._collisions_sid:
-# self._collisions_sid = gobject.idle_add(self._solve_collisions)
-
- def add_weight(self, rect):
- for i in range(rect.x, rect.x + rect.width):
- for j in range(rect.y, rect.y + rect.height):
- self[j, i] += 1
-
- def _remove_weight(self, rect):
- for i in range(rect.x, rect.x + rect.width):
- for j in range(rect.y, rect.y + rect.height):
- self[j, i] -= 1
-
- def _compute_weight(self, rect):
- weight = 0
-
- for i in range(rect.x, rect.x + rect.width):
- for j in range(rect.y, rect.y + rect.height):
- weight += self[j, i]
-
- return weight
-
- def __getitem__(self, (row, col)):
- return self._array[col + row * self.width]
-
- def __setitem__(self, (row, col), value):
- self._array[col + row * self.width] = value
-
-
-class SpreadLayout(gobject.GObject,hippo.CanvasLayout):
- __gtype_name__ = 'SugarSpreadLayout'
- def __init__(self):
- gobject.GObject.__init__(self)
-
- min_width, width = self.do_get_width_request()
- min_height, height = self.do_get_height_request(width)
-
- self._grid = _Grid(width / _CELL_SIZE, height / _CELL_SIZE)
- self._grid.connect('child-changed', self._grid_child_changed_cb)
-
- def add_center(self, child):
- self._box.append(child)
-
- width, height = self._get_child_grid_size(child)
- rect = gtk.gdk.Rectangle(int((self._grid.width - width) / 2),
- int((self._grid.height - height) / 2),
- width + 1, height + 1)
- self._grid.add_weight(rect)
-
- box_child = self._box.find_box_child(child)
- box_child.grid_rect = None
-
- def add(self, child):
- self._box.append(child)
-
- width, height = self._get_child_grid_size(child)
- box_child = self._box.find_box_child(child)
- self._grid.add(box_child, width, height)
-
- def remove(self, child):
- box_child = self._box.find_box_child(child)
- self._grid.remove(box_child)
-
- self._box.remove(child)
-
- def do_set_box(self, box):
- self._box = box
-
- def do_get_height_request(self, for_width):
- return 0, gtk.gdk.screen_height()
-
- def do_get_width_request(self):
- return 0, gtk.gdk.screen_width()
-
- def do_allocate(self, x, y, width, height,
- req_width, req_height, origin_changed):
- for child in self._box.get_layout_children():
- rect = child.grid_rect
- if child.grid_rect:
- child.allocate(rect.x * _CELL_SIZE,
- rect.y * _CELL_SIZE,
- rect.width * _CELL_SIZE,
- rect.height * _CELL_SIZE,
- origin_changed)
- else:
- min_w, child_width = child.get_width_request()
- min_h, child_height = child.get_height_request(child_width)
- child.allocate(x + (width - child_width) / 2,
- y + (height - child_height) / 2,
- child_width, child_height, origin_changed)
-
- def _get_child_grid_size(self, child):
- min_width, width = child.get_width_request()
- min_height, height = child.get_height_request(width)
-
- return int(width / _CELL_SIZE), int(height / _CELL_SIZE)
-
- def _grid_child_changed_cb(self, grid, box_child):
- box_child.item.emit_request_changed()
diff --git a/sugar/graphics/style.py b/sugar/graphics/style.py
deleted file mode 100644
index c9e4f68..0000000
--- a/sugar/graphics/style.py
+++ /dev/null
@@ -1,147 +0,0 @@
-# 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.
-
-"""
-All the constants are expressed in pixels. They are defined for the XO screen
-and are usually adapted to different resolution by applying a zoom factor. The
-factor for traditional 96 dpi screen is currently 0.72 which is the inverse
-of the one we are using to adapt web pages to the XO screen. It should be
-considered a reference value rather then a scale constant which has to be
-automatically applied and always respected.
-"""
-
-import os
-
-import gtk
-import pango
-
-_XO_DPI = 200.0
-
-_FOCUS_LINE_WIDTH = 2
-_TAB_CURVATURE = 1
-
-def _get_screen_dpi():
- xft_dpi = gtk.settings_get_default().get_property('gtk-xft-dpi')
- return float(xft_dpi / 1024)
-
-def _compute_zoom_factor():
- if _get_screen_dpi() == 96.0:
- if not os.environ.has_key('SUGAR_XO_STYLE') or \
- not os.environ['SUGAR_XO_STYLE'] == 'yes':
- return 0.72
-
- return 1.0
-
-def _compute_font_height(font):
- widget = gtk.Label('')
-
- context = widget.get_pango_context()
- pango_font = context.load_font(font.get_pango_desc())
- metrics = pango_font.get_metrics()
-
- return pango.PIXELS(metrics.get_ascent() + metrics.get_descent())
-
-class Font(object):
- def __init__(self, desc):
- self._desc = desc
-
- def __str__(self):
- return self._desc
-
- def get_pango_desc(self):
- return pango.FontDescription(self._desc)
-
-class Color(object):
- def __init__(self, color, alpha=1.0):
- self._r, self._g, self._b = self._html_to_rgb(color)
- self._a = alpha
-
- def get_rgba(self):
- return (self._r, self._g, self._b, self._a)
-
- def get_int(self):
- return int(self._a * 255) + (int(self._b * 255) << 8) + \
- (int(self._g * 255) << 16) + (int(self._r * 255) << 24)
-
- def get_gdk_color(self):
- return gtk.gdk.Color(int(self._r * 65535), int(self._g * 65535),
- int(self._b * 65535))
-
- def get_html(self):
- return '#%02x%02x%02x' % (self._r * 255, self._g * 255, self._b * 255)
-
- def _html_to_rgb(self, html_color):
- """ #RRGGBB -> (r, g, b) tuple (in float format) """
-
- html_color = html_color.strip()
- if html_color[0] == '#':
- html_color = html_color[1:]
- if len(html_color) != 6:
- raise ValueError, "input #%s is not in #RRGGBB format" % html_color
-
- r, g, b = html_color[:2], html_color[2:4], html_color[4:]
- r, g, b = [int(n, 16) for n in (r, g, b)]
- r, g, b = (r / 255.0, g / 255.0, b / 255.0)
-
- return (r, g, b)
-
- def get_svg(self):
- if self._a == 0.0:
- return 'none'
- else:
- return self.get_html()
-
-def zoom(units):
- return int(ZOOM_FACTOR * units)
-
-ZOOM_FACTOR = _compute_zoom_factor()
-
-DEFAULT_SPACING = zoom(8)
-DEFAULT_PADDING = zoom(6)
-GRID_CELL_SIZE = zoom(75)
-LINE_WIDTH = zoom(2)
-
-STANDARD_ICON_SIZE = zoom(55)
-SMALL_ICON_SIZE = zoom(55 * 0.5)
-MEDIUM_ICON_SIZE = zoom(55 * 1.5)
-LARGE_ICON_SIZE = zoom(55 * 2.0)
-XLARGE_ICON_SIZE = zoom(55 * 2.75)
-
-FONT_SIZE = zoom(7 * _XO_DPI / _get_screen_dpi())
-FONT_NORMAL = Font('Bitstream Vera Sans %d' % FONT_SIZE)
-FONT_BOLD = Font('Bitstream Vera Sans bold %d' % FONT_SIZE)
-FONT_NORMAL_H = _compute_font_height(FONT_NORMAL)
-FONT_BOLD_H = _compute_font_height(FONT_BOLD)
-
-TOOLBOX_SEPARATOR_HEIGHT = zoom(9)
-TOOLBOX_HORIZONTAL_PADDING = zoom(75)
-TOOLBOX_TAB_VBORDER = int((zoom(36) - FONT_NORMAL_H - _FOCUS_LINE_WIDTH) / 2)
-TOOLBOX_TAB_HBORDER = zoom(15) - _FOCUS_LINE_WIDTH - _TAB_CURVATURE
-TOOLBOX_TAB_LABEL_WIDTH = zoom(150 - 15 * 2)
-
-COLOR_BLACK = Color('#000000')
-COLOR_WHITE = Color('#FFFFFF')
-COLOR_TRANSPARENT = Color('#FFFFFF', alpha=0.0)
-COLOR_PANEL_GREY = Color('#C0C0C0')
-COLOR_SELECTION_GREY = Color('#A6A6A6')
-COLOR_TOOLBAR_GREY = Color('#404040')
-COLOR_BUTTON_GREY = Color('#808080')
-COLOR_INACTIVE_FILL = Color('#9D9FA1')
-COLOR_INACTIVE_STROKE = Color('#757575')
-COLOR_TEXT_FIELD_GREY = Color('#E5E5E5')
-
-PALETTE_CURSOR_DISTANCE = zoom(10)
diff --git a/sugar/graphics/toggletoolbutton.py b/sugar/graphics/toggletoolbutton.py
deleted file mode 100644
index 3d05cc0..0000000
--- a/sugar/graphics/toggletoolbutton.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# 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
-from sugar.graphics.palette import Palette, ToolInvoker
-
-class ToggleToolButton(gtk.ToggleToolButton):
- __gtype_name__ = "SugarToggleToolButton"
-
- def __init__(self, named_icon=None):
- gtk.ToggleToolButton.__init__(self)
- self._palette = None
- self.set_named_icon(named_icon)
-
- def set_named_icon(self, named_icon):
- icon = Icon(icon_name=named_icon)
- self.set_icon_widget(icon)
- icon.show()
-
- def get_palette(self):
- return self._palette
-
- def set_palette(self, palette):
- if self._palette is not None:
- self._palette.props.invoker = None
- self._palette = palette
- self._palette.props.invoker = ToolInvoker(self)
-
- def set_tooltip(self, text):
- self.set_palette(Palette(text))
-
- def do_expose_event(self, event):
- if self._palette and self._palette.is_up():
- invoker = self._palette.props.invoker
- invoker.draw_rectangle(event, self._palette)
- elif self.child.state == gtk.STATE_PRELIGHT:
- self.child.style.paint_box(event.window, gtk.STATE_PRELIGHT,
- gtk.SHADOW_NONE, event.area,
- self.child, "toolbutton-prelight",
- self.allocation.x,
- self.allocation.y,
- self.allocation.width,
- self.allocation.height)
-
- gtk.ToggleToolButton.do_expose_event(self, event)
-
- palette = property(get_palette, set_palette)
diff --git a/sugar/graphics/toolbox.py b/sugar/graphics/toolbox.py
deleted file mode 100644
index e4e831a..0000000
--- a/sugar/graphics/toolbox.py
+++ /dev/null
@@ -1,91 +0,0 @@
-# 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
-import gobject
-import hippo
-
-from sugar.graphics.toolbutton import ToolButton
-from sugar.graphics import style
-
-class Toolbox(gtk.VBox):
- __gtype_name__ = 'SugarToolbox'
-
- __gsignals__ = {
- 'current-toolbar-changed': (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE,
- ([int]))
- }
-
- def __init__(self):
- gtk.VBox.__init__(self)
-
- self._notebook = gtk.Notebook()
- self._notebook.set_tab_pos(gtk.POS_BOTTOM)
- self._notebook.set_show_border(False)
- self._notebook.set_show_tabs(False)
- self._notebook.props.tab_vborder = style.TOOLBOX_TAB_VBORDER
- self._notebook.props.tab_hborder = style.TOOLBOX_TAB_HBORDER
- self.pack_start(self._notebook)
- self._notebook.show()
-
- # FIXME improve gtk.Notebook and do this in the theme
- self._separator = hippo.Canvas()
- box = hippo.CanvasBox(
- border_color=style.COLOR_BUTTON_GREY.get_int(),
- background_color=style.COLOR_PANEL_GREY.get_int(),
- box_height=style.TOOLBOX_SEPARATOR_HEIGHT,
- border_bottom=style.LINE_WIDTH)
- self._separator.set_root(box)
- self.pack_start(self._separator, False)
-
- self._notebook.connect('notify::page', self._notify_page_cb)
-
- def _notify_page_cb(self, notebook, pspec):
- self.emit('current-toolbar-changed', notebook.props.page)
-
- def add_toolbar(self, name, toolbar):
- label = gtk.Label(name)
- label.set_size_request(style.TOOLBOX_TAB_LABEL_WIDTH, -1)
- label.set_alignment(0.0, 0.5)
-
- event_box = gtk.EventBox()
-
- alignment = gtk.Alignment(0.0, 0.0, 1.0, 1.0)
- alignment.set_padding(0, 0, style.TOOLBOX_HORIZONTAL_PADDING,
- style.TOOLBOX_HORIZONTAL_PADDING)
-
- alignment.add(toolbar)
- event_box.add(alignment)
- alignment.show()
- event_box.show()
-
- self._notebook.append_page(event_box, label)
-
- if self._notebook.get_n_pages() > 1:
- self._notebook.set_show_tabs(True)
- self._separator.show()
-
- def remove_toolbar(self, index):
- self._notebook.remove_page(index)
-
- if self._notebook.get_n_pages() < 2:
- self._notebook.set_show_tabs(False)
- self._separator.hide()
-
- def set_current_toolbar(self, index):
- self._notebook.set_current_page(index)
diff --git a/sugar/graphics/toolbutton.py b/sugar/graphics/toolbutton.py
deleted file mode 100644
index b4c8eb3..0000000
--- a/sugar/graphics/toolbutton.py
+++ /dev/null
@@ -1,71 +0,0 @@
-# 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
-import gobject
-import time
-
-from sugar.graphics.icon import Icon
-from sugar.graphics.palette import Palette, ToolInvoker
-
-class ToolButton(gtk.ToolButton):
- __gtype_name__ = "SugarToolButton"
-
- def __init__(self, icon_name=None):
- gtk.ToolButton.__init__(self)
- self._palette = None
- if icon_name:
- self.set_icon(icon_name)
- self.connect('clicked', self._button_clicked_cb)
-
- def set_icon(self, icon_name):
- icon = Icon(icon_name=icon_name)
- self.set_icon_widget(icon)
- icon.show()
-
- def get_palette(self):
- return self._palette
-
- def set_palette(self, palette):
- if self._palette is not None:
- self._palette.props.invoker = None
- self._palette = palette
- self._palette.props.invoker = ToolInvoker(self)
-
- def set_tooltip(self, text):
- self.set_palette(Palette(text))
-
- def do_expose_event(self, event):
- if self._palette and self._palette.is_up():
- invoker = self._palette.props.invoker
- invoker.draw_rectangle(event, self._palette)
- elif self.child.state == gtk.STATE_PRELIGHT:
- self.child.style.paint_box(event.window, gtk.STATE_PRELIGHT,
- gtk.SHADOW_NONE, event.area,
- self.child, "toolbutton-prelight",
- self.allocation.x,
- self.allocation.y,
- self.allocation.width,
- self.allocation.height)
-
- gtk.ToolButton.do_expose_event(self, event)
-
- def _button_clicked_cb(self, widget):
- if self._palette:
- self._palette.popdown(True)
-
- palette = property(get_palette, set_palette)
diff --git a/sugar/graphics/toolcombobox.py b/sugar/graphics/toolcombobox.py
deleted file mode 100644
index 460dcee..0000000
--- a/sugar/graphics/toolcombobox.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# 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
-import gobject
-
-from sugar.graphics.combobox import ComboBox
-from sugar.graphics import style
-
-class ToolComboBox(gtk.ToolItem):
- __gproperties__ = {
- 'label-text' : (str, None, None, None,
- gobject.PARAM_WRITABLE),
- }
-
- def __init__(self, combo=None, **kwargs):
- self.label = None
- self._label_text = ''
-
- gobject.GObject.__init__(self, **kwargs)
-
- self.set_border_width(style.DEFAULT_PADDING)
-
- hbox = gtk.HBox(False, style.DEFAULT_SPACING)
-
- self.label = gtk.Label(self._label_text)
- hbox.pack_start(self.label, False)
- self.label.show()
-
- if combo:
- self.combo = combo
- else:
- self.combo = ComboBox()
-
- hbox.pack_start(self.combo)
- self.combo.show()
-
- self.add(hbox)
- hbox.show()
-
- def do_set_property(self, pspec, value):
- if pspec.name == 'label-text':
- self._label_text = value
- if self.label:
- self.label.set_text(self._label_text)
diff --git a/sugar/graphics/tray.py b/sugar/graphics/tray.py
deleted file mode 100644
index b779ac9..0000000
--- a/sugar/graphics/tray.py
+++ /dev/null
@@ -1,241 +0,0 @@
-# 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 import style
-from sugar.graphics.palette import Palette, ToolInvoker
-from sugar.graphics.toolbutton import ToolButton
-from sugar.graphics.icon import Icon
-
-_PREVIOUS_PAGE = 0
-_NEXT_PAGE = 1
-
-class _TrayViewport(gtk.Viewport):
- __gproperties__ = {
- 'can-scroll' : (bool, None, None, False,
- gobject.PARAM_READABLE),
- }
-
- def __init__(self, orientation):
- self.orientation = orientation
- self._can_scroll = False
-
- gobject.GObject.__init__(self)
-
- self.set_shadow_type(gtk.SHADOW_NONE)
-
- self.traybar = gtk.Toolbar()
- self.traybar.set_orientation(orientation)
- self.traybar.set_show_arrow(False)
- self.add(self.traybar)
- self.traybar.show()
-
- self.connect('size_allocate', self._size_allocate_cb)
-
- def scroll(self, direction):
- if direction == _PREVIOUS_PAGE:
- self._scroll_previous()
- elif direction == _NEXT_PAGE:
- self._scroll_next()
-
- def _scroll_next(self):
- if self.orientation == gtk.ORIENTATION_HORIZONTAL:
- adj = self.get_hadjustment()
- new_value = adj.value + self.allocation.width
- adj.value = min(new_value, adj.upper - self.allocation.width)
- else:
- adj = self.get_vadjustment()
- new_value = adj.value + self.allocation.height
- adj.value = min(new_value, adj.upper - self.allocation.height)
-
- def _scroll_previous(self):
- if self.orientation == gtk.ORIENTATION_HORIZONTAL:
- adj = self.get_hadjustment()
- new_value = adj.value - self.allocation.width
- adj.value = max(adj.lower, new_value)
- else:
- adj = self.get_vadjustment()
- new_value = adj.value - self.allocation.height
- adj.value = max(adj.lower, new_value)
-
- def do_size_request(self, requisition):
- child_requisition = self.child.size_request()
- if self.orientation == gtk.ORIENTATION_HORIZONTAL:
- requisition[0] = 0
- requisition[1] = child_requisition[1]
- else:
- requisition[0] = child_requisition[0]
- requisition[1] = 0
-
- def do_get_property(self, pspec):
- if pspec.name == 'can-scroll':
- return self._can_scroll
-
- def _size_allocate_cb(self, viewport, allocation):
- bar_requisition = self.traybar.get_child_requisition()
- if self.orientation == gtk.ORIENTATION_HORIZONTAL:
- can_scroll = bar_requisition[0] > allocation.width
- else:
- can_scroll = bar_requisition[1] > allocation.height
-
- if can_scroll != self._can_scroll:
- self._can_scroll = can_scroll
- self.notify('can-scroll')
-
-class _TrayScrollButton(gtk.Button):
- def __init__(self, icon_name, scroll_direction):
- gobject.GObject.__init__(self)
-
- self._viewport = None
-
- self._scroll_direction = scroll_direction
-
- self.set_relief(gtk.RELIEF_NONE)
- self.set_size_request(style.GRID_CELL_SIZE, style.GRID_CELL_SIZE)
-
- icon = Icon(icon_name = icon_name,
- icon_size=gtk.ICON_SIZE_SMALL_TOOLBAR)
- self.set_image(icon)
- icon.show()
-
- self.connect('clicked', self._clicked_cb)
-
- def set_viewport(self, viewport):
- self._viewport = viewport
- self._viewport.connect('notify::can-scroll',
- self._viewport_can_scroll_changed_cb)
-
- def _viewport_can_scroll_changed_cb(self, viewport, pspec):
- self.props.visible = self._viewport.props.can_scroll
-
- def _clicked_cb(self, button):
- self._viewport.scroll(self._scroll_direction)
-
- viewport = property(fset=set_viewport)
-
-class HTray(gtk.HBox):
- def __init__(self, **kwargs):
- gobject.GObject.__init__(self, **kwargs)
-
- scroll_left = _TrayScrollButton('go-left', _PREVIOUS_PAGE)
- self.pack_start(scroll_left, False)
-
- self._viewport = _TrayViewport(gtk.ORIENTATION_HORIZONTAL)
- self.pack_start(self._viewport)
- self._viewport.show()
-
- scroll_right = _TrayScrollButton('go-right', _NEXT_PAGE)
- self.pack_start(scroll_right, False)
-
- scroll_left.viewport = self._viewport
- scroll_right.viewport = self._viewport
-
- def get_children(self):
- return self._viewport.traybar.get_children()
-
- def add_item(self, item, index=-1):
- self._viewport.traybar.insert(item, index)
-
- def remove_item(self, item):
- self._viewport.traybar.remove(item)
-
- def get_item_index(self, item):
- return self._viewport.traybar.get_item_index(item)
-
-class VTray(gtk.VBox):
- def __init__(self, **kwargs):
- gobject.GObject.__init__(self, **kwargs)
-
- # FIXME we need a go-up icon
- scroll_left = _TrayScrollButton('go-left', _PREVIOUS_PAGE)
- self.pack_start(scroll_left, False)
-
- self._viewport = _TrayViewport(gtk.ORIENTATION_VERTICAL)
- self.pack_start(self._viewport)
- self._viewport.show()
-
- # FIXME we need a go-down icon
- scroll_right = _TrayScrollButton('go-right', _NEXT_PAGE)
- self.pack_start(scroll_right, False)
-
- scroll_left.viewport = self._viewport
- scroll_right.viewport = self._viewport
-
- def get_children(self):
- return self._viewport.traybar.get_children()
-
- def add_item(self, item, index=-1):
- self._viewport.traybar.insert(item, index)
-
- def remove_item(self, item):
- self._viewport.traybar.remove(item)
-
- def get_item_index(self, item):
- return self._viewport.traybar.get_item_index(item)
-
-class TrayButton(ToolButton):
- def __init__(self, **kwargs):
- ToolButton.__init__(self, **kwargs)
-
-class _IconWidget(gtk.EventBox):
- __gtype_name__ = "SugarTrayIconWidget"
-
- def __init__(self, icon_name=None, xo_color=None):
- gtk.EventBox.__init__(self)
-
- self._palette = None
-
- self.set_app_paintable(True)
-
- icon = Icon(icon_name=icon_name, xo_color=xo_color,
- icon_size=gtk.ICON_SIZE_LARGE_TOOLBAR)
- self.add(icon)
- icon.show()
-
- def do_expose_event(self, event):
- if self._palette and self._palette.is_up():
- invoker = self._palette.props.invoker
- invoker.draw_rectangle(event, self._palette)
-
- gtk.EventBox.do_expose_event(self, event)
-
- def set_palette(self, palette):
- if self._palette is not None:
- self._palette.props.invoker = None
- self._palette = palette
- self._palette.props.invoker = ToolInvoker(self)
-
-class TrayIcon(gtk.ToolItem):
- __gtype_name__ = "SugarTrayIcon"
-
- def __init__(self, icon_name=None, xo_color=None):
- gtk.ToolItem.__init__(self)
-
- self._icon_widget = _IconWidget(icon_name, xo_color)
- self.add(self._icon_widget)
- self._icon_widget.show()
-
- self.set_size_request(style.GRID_CELL_SIZE, style.GRID_CELL_SIZE)
-
- def set_palette(self, palette):
- self._icon_widget.set_palette(palette)
-
- def set_tooltip(self, text):
- self.set_palette(Palette(text))
-
diff --git a/sugar/graphics/window.py b/sugar/graphics/window.py
deleted file mode 100644
index e6081fe..0000000
--- a/sugar/graphics/window.py
+++ /dev/null
@@ -1,84 +0,0 @@
-# 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
-import hippo
-
-class Window(gtk.Window):
- def __init__(self):
- gtk.Window.__init__(self)
-
- self.connect('realize', self._window_realize_cb)
-
- self.toolbox = None
- self._alerts = []
- self.alert_position = -1
- self.canvas = None
-
- self._vbox = gtk.VBox()
- self.add(self._vbox)
- self._vbox.show()
-
- def set_canvas(self, canvas):
- if self.canvas:
- self._vbox.remove(self.canvas)
-
- self._vbox.pack_start(canvas)
- self._vbox.reorder_child(canvas, -1)
-
- self.canvas = canvas
-
- def set_toolbox(self, toolbox):
- if self.toolbox:
- self._vbox.remove(self.toolbox)
-
- self._vbox.pack_start(toolbox, False)
- self._vbox.reorder_child(toolbox, 0)
-
- self.toolbox = toolbox
-
- def add_alert(self, alert):
- self._alerts.append(alert)
- if len(self._alerts) == 1:
- self._vbox.pack_start(alert, False)
- self._vbox.reorder_child(alert, self.alert_position)
-
- def remove_alert(self, alert):
- if alert in self._alerts:
- self._alerts.remove(alert)
- self._vbox.remove(alert)
- if len(self._alerts) >= 1:
- self._vbox.pack_start(self._alerts[0], False)
- self._vbox.reorder_child(self._alerts[0], self.alert_position)
-
- def _window_realize_cb(self, window):
- group = gtk.Window()
- group.realize()
- window.window.set_group(group.window)
-
- def get_canvas_screenshot(self):
- if not self.canvas:
- return None
-
- window = self.canvas.window
- width, height = window.get_size()
-
- screenshot = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, has_alpha=False,
- bits_per_sample=8, width=width, height=height)
- screenshot.get_from_drawable(window, window.get_colormap(), 0, 0, 0, 0,
- width, height)
- return screenshot
diff --git a/sugar/graphics/xocolor.py b/sugar/graphics/xocolor.py
deleted file mode 100644
index d37eab1..0000000
--- a/sugar/graphics/xocolor.py
+++ /dev/null
@@ -1,255 +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 random
-
-_colors = [
-['#B20008', '#FF2B34'], \
-['#FF2B34', '#B20008'], \
-['#E6000A', '#FF2B34'], \
-['#FF2B34', '#E6000A'], \
-['#FFADCE', '#FF2B34'], \
-['#9A5200', '#FF2B34'], \
-['#FF2B34', '#9A5200'], \
-['#FF8F00', '#FF2B34'], \
-['#FF2B34', '#FF8F00'], \
-['#FFC169', '#FF2B34'], \
-['#807500', '#FF2B34'], \
-['#FF2B34', '#807500'], \
-['#BE9E00', '#FF2B34'], \
-['#FF2B34', '#BE9E00'], \
-['#F8E800', '#FF2B34'], \
-['#008009', '#FF2B34'], \
-['#FF2B34', '#008009'], \
-['#00B20D', '#FF2B34'], \
-['#FF2B34', '#00B20D'], \
-['#8BFF7A', '#FF2B34'], \
-['#00588C', '#FF2B34'], \
-['#FF2B34', '#00588C'], \
-['#005FE4', '#FF2B34'], \
-['#FF2B34', '#005FE4'], \
-['#BCCDFF', '#FF2B34'], \
-['#5E008C', '#FF2B34'], \
-['#FF2B34', '#5E008C'], \
-['#7F00BF', '#FF2B34'], \
-['#FF2B34', '#7F00BF'], \
-['#D1A3FF', '#FF2B34'], \
-['#9A5200', '#FF8F00'], \
-['#FF8F00', '#9A5200'], \
-['#C97E00', '#FF8F00'], \
-['#FF8F00', '#C97E00'], \
-['#FFC169', '#FF8F00'], \
-['#807500', '#FF8F00'], \
-['#FF8F00', '#807500'], \
-['#BE9E00', '#FF8F00'], \
-['#FF8F00', '#BE9E00'], \
-['#F8E800', '#FF8F00'], \
-['#008009', '#FF8F00'], \
-['#FF8F00', '#008009'], \
-['#00B20D', '#FF8F00'], \
-['#FF8F00', '#00B20D'], \
-['#8BFF7A', '#FF8F00'], \
-['#00588C', '#FF8F00'], \
-['#FF8F00', '#00588C'], \
-['#005FE4', '#FF8F00'], \
-['#FF8F00', '#005FE4'], \
-['#BCCDFF', '#FF8F00'], \
-['#5E008C', '#FF8F00'], \
-['#FF8F00', '#5E008C'], \
-['#A700FF', '#FF8F00'], \
-['#FF8F00', '#A700FF'], \
-['#D1A3FF', '#FF8F00'], \
-['#B20008', '#FF8F00'], \
-['#FF8F00', '#B20008'], \
-['#FF2B34', '#FF8F00'], \
-['#FF8F00', '#FF2B34'], \
-['#FFADCE', '#FF8F00'], \
-['#807500', '#F8E800'], \
-['#F8E800', '#807500'], \
-['#BE9E00', '#F8E800'], \
-['#F8E800', '#BE9E00'], \
-['#FFFA00', '#EDDE00'], \
-['#008009', '#F8E800'], \
-['#F8E800', '#008009'], \
-['#00EA11', '#F8E800'], \
-['#F8E800', '#00EA11'], \
-['#8BFF7A', '#F8E800'], \
-['#00588C', '#F8E800'], \
-['#F8E800', '#00588C'], \
-['#00A0FF', '#F8E800'], \
-['#F8E800', '#00A0FF'], \
-['#BCCEFF', '#F8E800'], \
-['#5E008C', '#F8E800'], \
-['#F8E800', '#5E008C'], \
-['#AC32FF', '#F8E800'], \
-['#F8E800', '#AC32FF'], \
-['#D1A3FF', '#F8E800'], \
-['#B20008', '#F8E800'], \
-['#F8E800', '#B20008'], \
-['#FF2B34', '#F8E800'], \
-['#F8E800', '#FF2B34'], \
-['#FFADCE', '#F8E800'], \
-['#9A5200', '#F8E800'], \
-['#F8E800', '#9A5200'], \
-['#FF8F00', '#F8E800'], \
-['#F8E800', '#FF8F00'], \
-['#FFC169', '#F8E800'], \
-['#008009', '#00EA11'], \
-['#00EA11', '#008009'], \
-['#00B20D', '#00EA11'], \
-['#00EA11', '#00B20D'], \
-['#8BFF7A', '#00EA11'], \
-['#00588C', '#00EA11'], \
-['#00EA11', '#00588C'], \
-['#005FE4', '#00EA11'], \
-['#00EA11', '#005FE4'], \
-['#BCCDFF', '#00EA11'], \
-['#5E008C', '#00EA11'], \
-['#00EA11', '#5E008C'], \
-['#7F00BF', '#00EA11'], \
-['#00EA11', '#7F00BF'], \
-['#D1A3FF', '#00EA11'], \
-['#B20008', '#00EA11'], \
-['#00EA11', '#B20008'], \
-['#FF2B34', '#00EA11'], \
-['#00EA11', '#FF2B34'], \
-['#FFADCE', '#00EA11'], \
-['#9A5200', '#00EA11'], \
-['#00EA11', '#9A5200'], \
-['#FF8F00', '#00EA11'], \
-['#00EA11', '#FF8F00'], \
-['#FFC169', '#00EA11'], \
-['#807500', '#00EA11'], \
-['#00EA11', '#807500'], \
-['#BE9E00', '#00EA11'], \
-['#00EA11', '#BE9E00'], \
-['#F8E800', '#00EA11'], \
-['#00588C', '#00A0FF'], \
-['#00A0FF', '#00588C'], \
-['#005FE4', '#00A0FF'], \
-['#00A0FF', '#005FE4'], \
-['#BCCDFF', '#00A0FF'], \
-['#5E008C', '#00A0FF'], \
-['#00A0FF', '#5E008C'], \
-['#9900E6', '#00A0FF'], \
-['#00A0FF', '#9900E6'], \
-['#D1A3FF', '#00A0FF'], \
-['#B20008', '#00A0FF'], \
-['#00A0FF', '#B20008'], \
-['#FF2B34', '#00A0FF'], \
-['#00A0FF', '#FF2B34'], \
-['#FFADCE', '#00A0FF'], \
-['#9A5200', '#00A0FF'], \
-['#00A0FF', '#9A5200'], \
-['#FF8F00', '#00A0FF'], \
-['#00A0FF', '#FF8F00'], \
-['#FFC169', '#00A0FF'], \
-['#807500', '#00A0FF'], \
-['#00A0FF', '#807500'], \
-['#BE9E00', '#00A0FF'], \
-['#00A0FF', '#BE9E00'], \
-['#F8E800', '#00A0FF'], \
-['#008009', '#00A0FF'], \
-['#00A0FF', '#008009'], \
-['#00B20D', '#00A0FF'], \
-['#00A0FF', '#00B20D'], \
-['#8BFF7A', '#00A0FF'], \
-['#5E008C', '#AC32FF'], \
-['#AC32FF', '#5E008C'], \
-['#7F00BF', '#AC32FF'], \
-['#AC32FF', '#7F00BF'], \
-['#D1A3FF', '#AC32FF'], \
-['#B20008', '#AC32FF'], \
-['#AC32FF', '#B20008'], \
-['#FF2B34', '#AC32FF'], \
-['#AC32FF', '#FF2B34'], \
-['#FFADCE', '#AC32FF'], \
-['#9A5200', '#AC32FF'], \
-['#AC32FF', '#9A5200'], \
-['#FF8F00', '#AC32FF'], \
-['#AC32FF', '#FF8F00'], \
-['#FFC169', '#AC32FF'], \
-['#807500', '#AC32FF'], \
-['#AC32FF', '#807500'], \
-['#BE9E00', '#AC32FF'], \
-['#AC32FF', '#BE9E00'], \
-['#F8E800', '#AC32FF'], \
-['#008009', '#AC32FF'], \
-['#AC32FF', '#008009'], \
-['#00B20D', '#AC32FF'], \
-['#AC32FF', '#00B20D'], \
-['#8BFF7A', '#AC32FF'], \
-['#00588C', '#AC32FF'], \
-['#AC32FF', '#00588C'], \
-['#005FE4', '#AC32FF'], \
-['#AC32FF', '#005FE4'], \
-['#BCCDFF', '#AC32FF'], \
-]
-
-def _parse_string(color_string):
- if color_string == 'white':
- return ['#ffffff', '#414141']
- elif color_string == 'insensitive':
- return ['#ffffff', '#e2e2e2']
-
- splitted = color_string.split(',')
- if len(splitted) == 2:
- return [splitted[0], splitted[1]]
- else:
- return None
-
-def is_valid(color_string):
- return (_parse_string(color_string) != None)
-
-class XoColor:
- def __init__(self, color_string=None):
- if color_string == None or not is_valid(color_string):
- n = int(random.random() * (len(_colors) - 1))
- [self._stroke, self._fill] = _colors[n]
- else:
- [self._stroke, self._fill] = _parse_string(color_string)
-
- def __cmp__(self, other):
- if isinstance(other, XoColor):
- if self._stroke == other._stroke and self._fill == other._fill:
- return 0
- return -1
-
- def get_stroke_color(self):
- return self._stroke
-
- def get_fill_color(self):
- return self._fill
-
- def to_string(self):
- return '%s,%s' % (self._stroke, self._fill)
-
-if __name__ == "__main__":
- import sys
- import re
-
- f = open(sys.argv[1], 'r')
-
- print '_colors = ['
-
- for line in f.readlines():
- match = re.match(r'fill: ([A-Z0-9]*) stroke: ([A-Z0-9]*)', line)
- print "['#%s', '#%s'], \\" % (match.group(2), match.group(1))
-
- print ']'
-
- f.close()
diff --git a/sugar/network.py b/sugar/network.py
deleted file mode 100644
index 49d4882..0000000
--- a/sugar/network.py
+++ /dev/null
@@ -1,575 +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.
-
-# pylint: disable-msg = W0221
-
-import socket
-import os
-import threading
-import traceback
-import xmlrpclib
-import sys
-import httplib
-import urllib
-import fcntl
-import tempfile
-
-import gobject
-import SimpleXMLRPCServer
-import SimpleHTTPServer
-import SocketServer
-
-
-__authinfos = {}
-
-def _add_authinfo(authinfo):
- __authinfos[threading.currentThread()] = authinfo
-
-def get_authinfo():
- return __authinfos.get(threading.currentThread())
-
-def _del_authinfo():
- del __authinfos[threading.currentThread()]
-
-
-class GlibTCPServer(SocketServer.TCPServer):
- """GlibTCPServer
-
- Integrate socket accept into glib mainloop.
- """
-
- allow_reuse_address = True
- request_queue_size = 20
-
- def __init__(self, server_address, RequestHandlerClass):
- SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass)
- self.socket.setblocking(0) # Set nonblocking
-
- # Watch the listener socket for data
- gobject.io_add_watch(self.socket, gobject.IO_IN, self._handle_accept)
-
- def _handle_accept(self, source, condition):
- """Process incoming data on the server's socket by doing an accept()
- via handle_request()."""
- if not (condition & gobject.IO_IN):
- return True
- self.handle_request()
- return True
-
- def close_request(self, request):
- """Called to clean up an individual request."""
- # let the request be closed by the request handler when its done
- pass
-
-
-class ChunkedGlibHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
- """RequestHandler class that integrates with Glib mainloop. It writes
- the specified file to the client in chunks, returning control to the
- mainloop between chunks.
- """
-
- CHUNK_SIZE = 4096
-
- def __init__(self, request, client_address, server):
- self._file = None
- self._srcid = 0
- SimpleHTTPServer.SimpleHTTPRequestHandler.__init__(self, request, client_address, server)
-
- def log_request(self, code='-', size='-'):
- pass
-
- def do_GET(self):
- """Serve a GET request."""
- self._file = self.send_head()
- if self._file:
- self._srcid = gobject.io_add_watch(self.wfile, gobject.IO_OUT | gobject.IO_ERR, self._send_next_chunk)
- else:
- self._file.close()
- self._cleanup()
-
- def _send_next_chunk(self, source, condition):
- if condition & gobject.IO_ERR:
- self._cleanup()
- return False
- if not (condition & gobject.IO_OUT):
- self._cleanup()
- return False
- data = self._file.read(self.CHUNK_SIZE)
- count = os.write(self.wfile.fileno(), data)
- if count != len(data) or len(data) != self.CHUNK_SIZE:
- self._cleanup()
- return False
- return True
-
- def _cleanup(self):
- if self._file:
- self._file.close()
- self._file = None
- if self._srcid > 0:
- gobject.source_remove(self._srcid)
- self._srcid = 0
- if not self.wfile.closed:
- self.wfile.flush()
- self.wfile.close()
- self.rfile.close()
-
- def finish(self):
- """Close the sockets when we're done, not before"""
- pass
-
- def send_head(self):
- """Common code for GET and HEAD commands.
-
- This sends the response code and MIME headers.
-
- Return value is either a file object (which has to be copied
- to the outputfile by the caller unless the command was HEAD,
- and must be closed by the caller under all circumstances), or
- None, in which case the caller has nothing further to do.
-
- ** [dcbw] modified to send Content-disposition filename too
- """
- path = self.translate_path(self.path)
- if not path or not os.path.exists(path):
- self.send_error(404, "File not found")
- return None
-
- f = None
- if os.path.isdir(path):
- for index in "index.html", "index.htm":
- index = os.path.join(path, index)
- if os.path.exists(index):
- path = index
- break
- else:
- return self.list_directory(path)
- ctype = self.guess_type(path)
- try:
- # Always read in binary mode. Opening files in text mode may cause
- # newline translations, making the actual size of the content
- # transmitted *less* than the content-length!
- f = open(path, 'rb')
- except IOError:
- self.send_error(404, "File not found")
- return None
- self.send_response(200)
- self.send_header("Content-type", ctype)
- self.send_header("Content-Length", str(os.fstat(f.fileno())[6]))
- self.send_header("Content-Disposition", 'attachment; filename="%s"' % os.path.basename(path))
- self.end_headers()
- return f
-
-class GlibURLDownloader(gobject.GObject):
- """Grabs a URL in chunks, returning to the mainloop after each chunk"""
-
- __gsignals__ = {
- 'finished': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT])),
- 'error': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'progress': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT]))
- }
-
- CHUNK_SIZE = 4096
-
- def __init__(self, url, destdir=None):
- self._url = url
- if not destdir:
- destdir = tempfile.gettempdir()
- self._destdir = destdir
- self._srcid = 0
- self._fname = None
- self._outf = None
- self._written = 0
- gobject.GObject.__init__(self)
-
- def start(self, destfile=None, destfd=None):
- self._info = urllib.urlopen(self._url)
- self._outf = None
- self._fname = None
- if destfd and not destfile:
- raise ValueError("Must provide destination file too when specifying file descriptor")
- if destfile:
- self._suggested_fname = os.path.basename(destfile)
- self._fname = os.path.abspath(os.path.expanduser(destfile))
- if destfd:
- # Use the user-supplied destination file descriptor
- self._outf = destfd
- else:
- self._outf = os.open(self._fname, os.O_RDWR | os.O_TRUNC | os.O_CREAT, 0644)
- else:
- self._suggested_fname = self._get_filename_from_headers(self._info.headers)
- garbage, path = urllib.splittype(self._url)
- garbage, path = urllib.splithost(path or "")
- path, garbage = urllib.splitquery(path or "")
- path, garbage = urllib.splitattr(path or "")
- suffix = os.path.splitext(path)[1]
- (self._outf, self._fname) = tempfile.mkstemp(suffix=suffix, dir=self._destdir)
-
- fcntl.fcntl(self._info.fp.fileno(), fcntl.F_SETFD, os.O_NDELAY)
- self._srcid = gobject.io_add_watch(self._info.fp.fileno(),
- gobject.IO_IN | gobject.IO_ERR,
- self._read_next_chunk)
-
- def cancel(self):
- if self._srcid == 0:
- raise RuntimeError("Download already canceled or stopped")
- self.cleanup(remove=True)
-
- def _get_filename_from_headers(self, headers):
- if not headers.has_key("Content-Disposition"):
- return None
-
- ftag = "filename="
- data = headers["Content-Disposition"]
- fidx = data.find(ftag)
- if fidx < 0:
- return None
- fname = data[fidx+len(ftag):]
- if fname[0] == '"' or fname[0] == "'":
- fname = fname[1:]
- if fname[len(fname)-1] == '"' or fname[len(fname)-1] == "'":
- fname = fname[:len(fname)-1]
- return fname
-
- def _read_next_chunk(self, source, condition):
- if condition & gobject.IO_ERR:
- self.cleanup(remove=True)
- self.emit("error", "Error downloading file.")
- return False
- elif not (condition & gobject.IO_IN):
- # shouldn't get here, but...
- return True
-
- try:
- data = self._info.fp.read(self.CHUNK_SIZE)
- count = os.write(self._outf, data)
- self._written += len(data)
-
- # error writing data to file?
- if count < len(data):
- self.cleanup(remove=True)
- self.emit("error", "Error writing to download file.")
- return False
-
- self.emit("progress", self._written)
-
- # done?
- if len(data) < self.CHUNK_SIZE:
- self.cleanup()
- self.emit("finished", self._fname, self._suggested_fname)
- return False
- except Exception, err:
- self.cleanup(remove=True)
- self.emit("error", "Error downloading file: %s" % err)
- return False
- return True
-
- def cleanup(self, remove=False):
- if self._srcid > 0:
- gobject.source_remove(self._srcid)
- self._srcid = 0
- del self._info
- self._info = None
- os.close(self._outf)
- if remove:
- os.remove(self._fname)
- self._outf = None
-
-
-class GlibXMLRPCRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
- """ GlibXMLRPCRequestHandler
-
- The stock SimpleXMLRPCRequestHandler and server don't allow any way to pass
- the client's address and/or SSL certificate into the function that actually
- _processes_ the request. So we have to store it in a thread-indexed dict.
- """
-
- def do_POST(self):
- _add_authinfo(self.client_address)
- try:
- SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.do_POST(self)
- except socket.timeout:
- pass
- except socket.error, e:
- print "Error (%s): socket error - '%s'" % (self.client_address, e)
- except:
- print "Error while processing POST:"
- traceback.print_exc()
- _del_authinfo()
-
-class GlibXMLRPCServer(GlibTCPServer, SimpleXMLRPCServer.SimpleXMLRPCDispatcher):
- """GlibXMLRPCServer
-
- Use nonblocking sockets and handle the accept via glib rather than
- blocking on accept().
- """
-
- def __init__(self, addr, requestHandler=GlibXMLRPCRequestHandler,
- logRequests=0, allow_none=False):
- self.logRequests = logRequests
- if sys.version_info[:3] >= (2, 5, 0):
- SimpleXMLRPCServer.SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding="utf-8")
- else:
- SimpleXMLRPCServer.SimpleXMLRPCDispatcher.__init__(self)
- GlibTCPServer.__init__(self, addr, requestHandler)
-
- def _marshaled_dispatch(self, data, dispatch_method = None):
- """Dispatches an XML-RPC method from marshalled (XML) data.
-
- XML-RPC methods are dispatched from the marshalled (XML) data
- using the _dispatch method and the result is returned as
- marshalled data. For backwards compatibility, a dispatch
- function can be provided as an argument (see comment in
- SimpleXMLRPCRequestHandler.do_POST) but overriding the
- existing method through subclassing is the prefered means
- of changing method dispatch behavior.
- """
-
- params, method = xmlrpclib.loads(data)
-
- # generate response
- try:
- if dispatch_method is not None:
- response = dispatch_method(method, params)
- else:
- response = self._dispatch(method, params)
- # wrap response in a singleton tuple
- response = (response,)
- response = xmlrpclib.dumps(response, methodresponse=1)
- except xmlrpclib.Fault, fault:
- response = xmlrpclib.dumps(fault)
- except:
- print "Exception while processing request:"
- traceback.print_exc()
-
- # report exception back to server
- response = xmlrpclib.dumps(
- xmlrpclib.Fault(1, "%s:%s" % (sys.exc_type, sys.exc_value))
- )
-
- return response
-
-
-class GlibHTTP(httplib.HTTP):
- """Subclass HTTP so we can return it's connection class' socket."""
- def connect(self, host=None, port=None):
- httplib.HTTP.connect(self, host, port)
- self._conn.sock.setblocking(0)
-
-class GlibXMLRPCTransport(xmlrpclib.Transport):
- """Integrate the request with the glib mainloop rather than blocking."""
- ##
- # Connect to server.
- #
- # @param host Target host.
- # @return A connection handle.
-
- def __init__(self, use_datetime=0):
- if sys.version_info[:3] >= (2, 5, 0):
- xmlrpclib.Transport.__init__(self, use_datetime)
-
- def make_connection(self, host):
- """Use our own connection object so we can get its socket."""
- # create a HTTP connection object from a host descriptor
- host, extra_headers, x509 = self.get_host_info(host)
- return GlibHTTP(host)
-
- ##
- # Send a complete request, and parse the response.
- #
- # @param host Target host.
- # @param handler Target PRC handler.
- # @param request_body XML-RPC request body.
- # @param verbose Debugging flag.
- # @return Parsed response.
-
- def start_request(self, host, handler, request_body, verbose=0, reply_handler=None, error_handler=None, user_data=None):
- """Do the first half of the request by sending data to the remote
- server. The bottom half bits get run when the remote server's response
- actually comes back."""
- # issue XML-RPC request
-
- h = self.make_connection(host)
- if verbose:
- h.set_debuglevel(1)
-
- self.send_request(h, handler, request_body)
- self.send_host(h, host)
- self.send_user_agent(h)
- self.send_content(h, request_body)
-
- # Schedule a GIOWatch so we don't block waiting for the response
- gobject.io_add_watch(h._conn.sock, gobject.IO_IN, self._finish_request,
- h, host, handler, verbose, reply_handler, error_handler, user_data)
-
- def _finish_request(self, source, condition, h, host, handler, verbose, reply_handler=None, error_handler=None, user_data=None):
- """Parse and return response when the remote server actually returns it."""
- if not (condition & gobject.IO_IN):
- return True
-
- try:
- errcode, errmsg, headers = h.getreply()
- except socket.error, err:
- if err[0] != 104:
- raise socket.error(err)
- else:
- if error_handler:
- gobject.idle_add(error_handler, err, user_data)
- return False
-
- if errcode != 200:
- raise xmlrpclib.ProtocolError(host + handler, errcode, errmsg, headers)
- self.verbose = verbose
- response = self._parse_response(h.getfile(), h._conn.sock)
- if reply_handler:
- # Coerce to a list so we can append user data
- response = response[0]
- if not isinstance(response, list):
- response = [response]
- response.append(user_data)
- gobject.idle_add(reply_handler, *response)
- return False
-
-class _Method:
- """Right, so python people thought it would be funny to make this
- class private to xmlrpclib.py..."""
- # some magic to bind an XML-RPC method to an RPC server.
- # supports "nested" methods (e.g. examples.getStateName)
- def __init__(self, send, name):
- self.__send = send
- self.__name = name
- def __getattr__(self, name):
- return _Method(self.__send, "%s.%s" % (self.__name, name))
- def __call__(self, *args, **kwargs):
- return self.__send(self.__name, *args, **kwargs)
-
-
-class GlibServerProxy(xmlrpclib.ServerProxy):
- """Subclass xmlrpclib.ServerProxy so we can run the XML-RPC request
- in two parts, integrated with the glib mainloop, such that we don't
- block anywhere.
-
- Using this object is somewhat special; it requires more arguments to each
- XML-RPC request call than the normal xmlrpclib.ServerProxy object:
-
- client = GlibServerProxy("http://127.0.0.1:8888")
- user_data = "bar"
- xmlrpc_arg1 = "test"
- xmlrpc_arg2 = "foo"
- client.test(xmlrpc_test_cb, user_data, xmlrpc_arg1, xmlrpc_arg2)
-
- Here, 'xmlrpc_test_cb' is the callback function, which has the following
- signature:
-
- def xmlrpc_test_cb(result_status, response, user_data=None):
- ...
- """
- def __init__(self, uri, encoding=None, verbose=0, allow_none=0):
- self._transport = GlibXMLRPCTransport()
- self._encoding = encoding
- self._verbose = verbose
- self._allow_none = allow_none
- xmlrpclib.ServerProxy.__init__(self, uri, self._transport, encoding, verbose, allow_none)
-
- # get the url
- import urllib
- urltype, uri = urllib.splittype(uri)
- if urltype not in ("http", "https"):
- raise IOError, "unsupported XML-RPC protocol"
- self._host, self._handler = urllib.splithost(uri)
- if not self._handler:
- self._handler = "/RPC2"
-
- def __request(self, methodname, *args, **kwargs):
- """Call the method on the remote server. We just start the request here
- and the transport itself takes care of scheduling the response callback
- when the remote server returns the response. We don't want to block anywhere."""
-
- request = xmlrpclib.dumps(args, methodname, encoding=self._encoding,
- allow_none=self._allow_none)
-
- reply_hdl = kwargs.get("reply_handler")
- err_hdl = kwargs.get("error_handler")
- udata = kwargs.get("user_data")
- try:
- response = self._transport.start_request(
- self._host,
- self._handler,
- request,
- verbose=self._verbose,
- reply_handler=reply_hdl,
- error_handler=err_hdl,
- user_data=udata
- )
- except socket.error, exc:
- if err_hdl:
- gobject.idle_add(err_hdl, exc, udata)
-
- def __getattr__(self, name):
- # magic method dispatcher
- return _Method(self.__request, name)
-
-
-class Test(object):
- def test(self, arg1, arg2):
- print "Request got %s, %s" % (arg1, arg2)
- return "success", "bork"
-
-def xmlrpc_success_cb(response, resp2, loop):
- print "Response was %s %s" % (response, resp2)
- loop.quit()
-
-def xmlrpc_error_cb(err, loop):
- print "Error: %s" % err
- loop.quit()
-
-def xmlrpc_test(loop):
- client = GlibServerProxy("http://127.0.0.1:8888")
- client.test("bar", "baz",
- reply_handler=xmlrpc_success_cb,
- error_handler=xmlrpc_error_cb,
- user_data=loop)
-
-def start_xmlrpc():
- server = GlibXMLRPCServer(("", 8888))
- inst = Test()
- server.register_instance(inst)
- gobject.idle_add(xmlrpc_test, loop)
-
-class TestReqHandler(ChunkedGlibHTTPRequestHandler):
- def translate_path(self, path):
- return "/tmp/foo"
-
-def start_http():
- server = GlibTCPServer(("", 8890), TestReqHandler)
-
-def main():
- loop = gobject.MainLoop()
-# start_xmlrpc()
- start_http()
- try:
- loop.run()
- except KeyboardInterrupt:
- print 'Ctrl+C pressed, exiting...'
- print "Done."
-
-if __name__ == "__main__":
- main()
-
-
diff --git a/sugar/objects/Makefile.am b/sugar/objects/Makefile.am
deleted file mode 100644
index 0f89830..0000000
--- a/sugar/objects/Makefile.am
+++ /dev/null
@@ -1,5 +0,0 @@
-sugardir = $(pythondir)/sugar/objects
-sugar_PYTHON = \
- __init__.py \
- objecttype.py
-
diff --git a/sugar/objects/__init__.py b/sugar/objects/__init__.py
deleted file mode 100644
index 85ebced..0000000
--- a/sugar/objects/__init__.py
+++ /dev/null
@@ -1,16 +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.
diff --git a/sugar/objects/objecttype.py b/sugar/objects/objecttype.py
deleted file mode 100644
index a819216..0000000
--- a/sugar/objects/objecttype.py
+++ /dev/null
@@ -1,79 +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 dbus
-
-_SERVICE = "org.laptop.ObjectTypeRegistry"
-_PATH = "/org/laptop/ObjectTypeRegistry"
-_IFACE = "org.laptop.ObjectTypeRegistry"
-
-def _object_type_from_dict(info_dict):
- if info_dict:
- return ObjectType(info_dict['type_id'],
- info_dict['name'],
- info_dict['icon'],
- info_dict['mime_types'])
- else:
- return None
-
-class ObjectType(object):
- def __init__(self, type_id, name, icon, mime_types):
- self.type_id = type_id
- self.name = name
- self.icon = icon
- self.mime_types = mime_types
-
- self._type_id_to_type = {}
- self._mime_type_to_type = {}
-
-class ObjectTypeRegistry(object):
- def __init__(self):
- bus = dbus.SessionBus()
- bus_object = bus.get_object(_SERVICE, _PATH)
- self._registry = dbus.Interface(bus_object, _IFACE)
-
- # Two caches fo saving some travel across dbus.
- self._type_id_to_type = {}
- self._mime_type_to_type = {}
-
- def get_type(self, type_id):
- if self._type_id_to_type.has_key(type_id):
- return self._type_id_to_type[type_id]
-
- type_dict = self._registry.GetType(type_id)
- object_type = _object_type_from_dict(type_dict)
-
- self._type_id_to_type[type_id] = object_type
- return object_type
-
- def get_type_for_mime(self, mime_type):
- if self._mime_type_to_type.has_key(mime_type):
- return self._mime_type_to_type[mime_type]
-
- type_dict = self._registry.GetTypeForMIME(mime_type)
- object_type = _object_type_from_dict(type_dict)
-
- self._mime_type_to_type[mime_type] = object_type
- return object_type
-
-_registry = None
-
-def get_registry():
- global _registry
- if not _registry:
- _registry = ObjectTypeRegistry()
- return _registry
diff --git a/sugar/presence/Makefile.am b/sugar/presence/Makefile.am
deleted file mode 100644
index cb52a41..0000000
--- a/sugar/presence/Makefile.am
+++ /dev/null
@@ -1,8 +0,0 @@
-sugardir = $(pythondir)/sugar/presence
-sugar_PYTHON = \
- __init__.py \
- activity.py \
- buddy.py \
- tubeconn.py \
- presenceservice.py
-
diff --git a/sugar/presence/__init__.py b/sugar/presence/__init__.py
deleted file mode 100644
index 3834ab2..0000000
--- a/sugar/presence/__init__.py
+++ /dev/null
@@ -1,24 +0,0 @@
-"""Client-code's interface to the PresenceService
-
-Provides a simplified API for accessing the dbus service
-which coordinates native network presence and sharing
-information. This includes both "buddies" and "shared
-activities".
-"""
-
-# 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.
diff --git a/sugar/presence/activity.py b/sugar/presence/activity.py
deleted file mode 100644
index c37b63a..0000000
--- a/sugar/presence/activity.py
+++ /dev/null
@@ -1,290 +0,0 @@
-"""UI interface to an activity in the presence service"""
-# 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 logging
-
-import gobject
-import dbus
-
-_logger = logging.getLogger('sugar.presence.activity')
-
-class Activity(gobject.GObject):
- """UI interface for an Activity in the presence service
-
- Activities in the presence service represent your and other user's
- shared activities.
-
- Properties:
- id
- color
- name
- type
- joined
- """
- __gsignals__ = {
- 'buddy-joined': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'buddy-left': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'new-channel': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'joined': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT])),
- }
-
- __gproperties__ = {
- 'id' : (str, None, None, None, gobject.PARAM_READABLE),
- 'name' : (str, None, None, None, gobject.PARAM_READWRITE),
- 'tags' : (str, None, None, None, gobject.PARAM_READWRITE),
- 'color' : (str, None, None, None, gobject.PARAM_READWRITE),
- 'type' : (str, None, None, None, gobject.PARAM_READABLE),
- 'private' : (bool, None, None, True, gobject.PARAM_READWRITE),
- 'joined' : (bool, None, None, False, gobject.PARAM_READABLE),
- }
-
- _PRESENCE_SERVICE = "org.laptop.Sugar.Presence"
- _ACTIVITY_DBUS_INTERFACE = "org.laptop.Sugar.Presence.Activity"
-
- def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
- """Initialse the activity interface, connecting to service"""
- gobject.GObject.__init__(self)
- self._object_path = object_path
- self._ps_new_object = new_obj_cb
- self._ps_del_object = del_obj_cb
- bobj = bus.get_object(self._PRESENCE_SERVICE, object_path)
- self._activity = dbus.Interface(bobj, self._ACTIVITY_DBUS_INTERFACE)
- self._activity.connect_to_signal('BuddyHandleJoined',
- self._buddy_handle_joined_cb)
- self._activity.connect_to_signal('BuddyLeft',
- self._buddy_left_cb)
- self._activity.connect_to_signal('NewChannel', self._new_channel_cb)
- self._activity.connect_to_signal('PropertiesChanged',
- self._properties_changed_cb,
- utf8_strings=True)
- # FIXME: this *would* just use a normal proxy call, but I want the
- # pending call object so I can block on it, and normal proxy methods
- # don't return those as of dbus-python 0.82.1; so do it the hard way
- self._get_properties_call = bus.call_async(self._PRESENCE_SERVICE,
- object_path, self._ACTIVITY_DBUS_INTERFACE, 'GetProperties',
- '', (), self._get_properties_reply_cb,
- self._get_properties_error_cb, utf8_strings=True)
-
- self._id = None
- self._color = None
- self._name = None
- self._type = None
- self._tags = None
- self._private = True
- self._joined = False
- # Cache for get_buddy_by_handle, maps handles to buddy object paths
- self._handle_to_buddy_path = {}
- self._buddy_path_to_handle = {}
-
- def _get_properties_reply_cb(self, new_props):
- self._properties_changed_cb(new_props)
- self._get_properties_call = None
-
- def _get_properties_error_cb(self, e):
- self._get_properties_call = None
- # FIXME: do something with the error
- _logger.warning('Error doing initial GetProperties: %s', e)
-
- def _properties_changed_cb(self, new_props):
- _logger.debug('Activity properties changed to %r', new_props)
- val = new_props.get('name', self._name)
- if isinstance(val, str) and val != self._name:
- self._name = val
- self.notify('name')
- val = new_props.get('tags', self._tags)
- if isinstance(val, str) and val != self._tags:
- self._tags = val
- self.notify('tags')
- val = new_props.get('color', self._color)
- if isinstance(val, str) and val != self._color:
- self._color = val
- self.notify('color')
- val = bool(new_props.get('private', self._private))
- if val != self._private:
- self._private = val
- self.notify('private')
- val = new_props.get('id', self._id)
- if isinstance(val, str) and self._id is None:
- self._id = val
- self.notify('id')
- val = new_props.get('type', self._type)
- if isinstance(val, str) and self._type is None:
- self._type = val
- self.notify('type')
-
- def object_path(self):
- """Get our dbus object path"""
- return self._object_path
-
- def do_get_property(self, pspec):
- """Retrieve a particular property from our property dictionary"""
- _logger.debug('Looking up property %s', pspec.name)
-
- if pspec.name == "joined":
- return self._joined
-
- if self._get_properties_call is not None:
- _logger.debug('Blocking on GetProperties() because someone wants '
- 'property %s', pspec.name)
- self._get_properties_call.block()
-
- if pspec.name == "id":
- return self._id
- elif pspec.name == "name":
- return self._name
- elif pspec.name == "color":
- return self._color
- elif pspec.name == "type":
- return self._type
- elif pspec.name == "tags":
- return self._tags
- elif pspec.name == "private":
- return self._private
-
- # FIXME: need an asynchronous API to set these properties, particularly
- # 'private'
- def do_set_property(self, pspec, val):
- """Set a particular property in our property dictionary"""
- if pspec.name == "name":
- self._activity.SetProperties({'name': val})
- self._name = val
- elif pspec.name == "color":
- self._activity.SetProperties({'color': val})
- self._color = val
- elif pspec.name == "tags":
- self._activity.SetProperties({'tags': val})
- self._tags = val
- elif pspec.name == "private":
- self._activity.SetProperties({'private': val})
- self._private = val
-
- def _emit_buddy_joined_signal(self, object_path):
- """Generate buddy-joined GObject signal with presence Buddy object"""
- self.emit('buddy-joined', self._ps_new_object(object_path))
- return False
-
- def _buddy_handle_joined_cb(self, object_path, handle):
- gobject.idle_add(self._emit_buddy_joined_signal, object_path)
- self._handle_to_buddy_path[handle] = object_path
- self._buddy_path_to_handle[object_path] = handle
-
- def _emit_buddy_left_signal(self, object_path):
- """Generate buddy-left GObject signal with presence Buddy object
-
- XXX note use of _ps_new_object instead of _ps_del_object here
- """
- self.emit('buddy-left', self._ps_new_object(object_path))
- return False
-
- def _buddy_left_cb(self, object_path):
- gobject.idle_add(self._emit_buddy_left_signal, object_path)
- handle = self._buddy_path_to_handle.pop(object_path)
- self._handle_to_buddy_path.pop(handle, None)
-
- def _emit_new_channel_signal(self, object_path):
- """Generate new-channel GObject signal with channel object path
-
- New telepathy-python communications channel has been opened
- """
- self.emit('new-channel', object_path)
- return False
-
- def _new_channel_cb(self, object_path):
- gobject.idle_add(self._emit_new_channel_signal, object_path)
-
- def get_joined_buddies(self):
- """Retrieve the set of Buddy objects attached to this activity
-
- returns list of presence Buddy objects
- """
- resp = self._activity.GetJoinedBuddies()
- buddies = []
- for item in resp:
- buddies.append(self._ps_new_object(item))
- return buddies
-
- def get_buddy_by_handle(self, handle):
- """Retrieve the Buddy object given a telepathy handle.
-
- buddy object paths are cached in self._handle_to_buddy_path,
- so we can get the buddy without calling PS.
- """
- object_path = self._handle_to_buddy_path.get(handle, None)
- if object_path:
- buddy = self._ps_new_object(object_path)
- return buddy
- return None
-
- def invite(self, buddy, message, response_cb):
- """Invite the given buddy to join this activity.
-
- The callback will be called with one parameter: None on success,
- or an exception on failure.
- """
- self._activity.Invite(buddy.object_path(), message,
- reply_handler=lambda: response_cb(None),
- error_handler=response_cb)
-
- def _join_cb(self):
- self._joined = True
- self.emit("joined", True, None)
-
- def _join_error_cb(self, err):
- self.emit("joined", False, str(err))
-
- def join(self):
- """Join this activity
-
- XXX if these are all activities, can I join my own activity?
- """
- if self._joined:
- self.emit("joined", True, None)
- return
- self._activity.Join(reply_handler=self._join_cb, error_handler=self._join_error_cb)
-
- def get_channels(self):
- """Retrieve communications channel descriptions for the activity
-
- Returns a tuple containing:
- - the D-Bus well-known service name of the connection
- (FIXME: this is redundant; in Telepathy it can be derived
- from that of the connection)
- - the D-Bus object path of the connection
- - a list of D-Bus object paths representing the channels
- associated with this activity
- """
- (bus_name, connection, channels) = self._activity.GetChannels()
- return bus_name, connection, channels
-
- def _leave_cb(self):
- """Callback for async action of leaving shared activity."""
- self.emit("joined", False, "left activity")
-
- def _leave_error_cb(self, err):
- """Callback for error in async leaving of shared activity."""
- _logger.debug('Failed to leave activity: %s', err)
-
- def leave(self):
- """Leave this shared activity"""
- self._joined = False
- self._activity.Leave(reply_handler=self._leave_cb,
- error_handler=self._leave_error_cb)
diff --git a/sugar/presence/buddy.py b/sugar/presence/buddy.py
deleted file mode 100644
index 2748299..0000000
--- a/sugar/presence/buddy.py
+++ /dev/null
@@ -1,225 +0,0 @@
-"""UI interface to a buddy in the presence service"""
-# 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 gobject
-import gtk
-import dbus
-
-
-class Buddy(gobject.GObject):
- """UI interface for a Buddy in the presence service
-
- Each buddy interface tracks a set of activities and properties
- that can be queried to provide UI controls for manipulating
- the presence interface.
-
- Properties Dictionary:
- 'key': public key,
- 'nick': nickname ,
- 'color': color (XXX what format),
- 'current-activity': (XXX dbus path?),
- 'owner': (XXX dbus path?),
- 'icon': (XXX pixel data for an icon?)
- See __gproperties__
- """
- __gsignals__ = {
- 'icon-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([])),
- 'joined-activity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'left-activity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'property-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- }
-
- __gproperties__ = {
- 'key' : (str, None, None, None, gobject.PARAM_READABLE),
- 'icon' : (str, None, None, None, gobject.PARAM_READABLE),
- 'nick' : (str, None, None, None, gobject.PARAM_READABLE),
- 'color' : (str, None, None, None, gobject.PARAM_READABLE),
- 'current-activity' : (object, None, None, gobject.PARAM_READABLE),
- 'owner' : (bool, None, None, False, gobject.PARAM_READABLE),
- 'ip4-address' : (str, None, None, None, gobject.PARAM_READABLE)
- }
-
- _PRESENCE_SERVICE = "org.laptop.Sugar.Presence"
- _BUDDY_DBUS_INTERFACE = "org.laptop.Sugar.Presence.Buddy"
-
- def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
- """Initialise the reference to the buddy
-
- bus -- dbus bus object
- new_obj_cb -- callback to call when this buddy joins an activity
- del_obj_cb -- callback to call when this buddy leaves an activity
- object_path -- path to the buddy object
- """
- gobject.GObject.__init__(self)
- self._object_path = object_path
- self._ps_new_object = new_obj_cb
- self._ps_del_object = del_obj_cb
- self._properties = {}
- self._activities = {}
-
- bobj = bus.get_object(self._PRESENCE_SERVICE, object_path)
- self._buddy = dbus.Interface(bobj, self._BUDDY_DBUS_INTERFACE)
- self._buddy.connect_to_signal('IconChanged', self._icon_changed_cb,
- byte_arrays=True)
- self._buddy.connect_to_signal('JoinedActivity', self._joined_activity_cb)
- self._buddy.connect_to_signal('LeftActivity', self._left_activity_cb)
- self._buddy.connect_to_signal('PropertyChanged', self._property_changed_cb)
- self._properties = self._get_properties_helper()
-
- activities = self._buddy.GetJoinedActivities()
- for op in activities:
- self._activities[op] = self._ps_new_object(op)
- self._icon = None
-
- def _get_properties_helper(self):
- """Retrieve the Buddy's property dictionary from the service object
- """
- props = self._buddy.GetProperties(byte_arrays=True)
- if not props:
- return {}
- return props
-
- def do_get_property(self, pspec):
- """Retrieve a particular property from our property dictionary
-
- pspec -- XXX some sort of GTK specifier object with attributes
- including 'name', 'active' and 'icon-name'
- """
- if pspec.name == "key":
- return self._properties["key"]
- elif pspec.name == "nick":
- return self._properties["nick"]
- elif pspec.name == "color":
- return self._properties["color"]
- elif pspec.name == "current-activity":
- if not self._properties.has_key("current-activity"):
- return None
- curact = self._properties["current-activity"]
- if not len(curact):
- return None
- for activity in self._activities.values():
- if activity.props.id == curact:
- return activity
- return None
- elif pspec.name == "owner":
- return self._properties["owner"]
- elif pspec.name == "icon":
- if not self._icon:
- self._icon = str(self._buddy.GetIcon(byte_arrays=True))
- return self._icon
- elif pspec.name == "ip4-address":
- # IPv4 address will go away quite soon
- if not self._properties.has_key("ip4-address"):
- return None
- return self._properties["ip4-address"]
-
- def object_path(self):
- """Retrieve our dbus object path"""
- return self._object_path
-
- def _emit_icon_changed_signal(self, bytes):
- """Emit GObject signal when icon has changed"""
- self._icon = str(bytes)
- self.emit('icon-changed')
- return False
-
- def _icon_changed_cb(self, icon_data):
- """Handle dbus signal by emitting a GObject signal"""
- gobject.idle_add(self._emit_icon_changed_signal, icon_data)
-
- def _emit_joined_activity_signal(self, object_path):
- """Emit activity joined signal with Activity object"""
- self.emit('joined-activity', self._ps_new_object(object_path))
- return False
-
- def _joined_activity_cb(self, object_path):
- """Handle dbus signal by emitting a GObject signal
-
- Stores the activity in activities dictionary as well
- """
- if not self._activities.has_key(object_path):
- self._activities[object_path] = self._ps_new_object(object_path)
- gobject.idle_add(self._emit_joined_activity_signal, object_path)
-
- def _emit_left_activity_signal(self, object_path):
- """Emit activity left signal with Activity object
-
- XXX this calls self._ps_new_object instead of self._ps_del_object,
- which would seem to be the incorrect callback?
- """
- self.emit('left-activity', self._ps_new_object(object_path))
- return False
-
- def _left_activity_cb(self, object_path):
- """Handle dbus signal by emitting a GObject signal
-
- Also removes from the activities dictionary
- """
- if self._activities.has_key(object_path):
- del self._activities[object_path]
- gobject.idle_add(self._emit_left_activity_signal, object_path)
-
- def _handle_property_changed_signal(self, prop_list):
- """Emit property-changed signal with property dictionary
-
- Generates a property-changed signal with the results of
- _get_properties_helper()
- """
- self._properties = self._get_properties_helper()
- # FIXME: don't leak unexposed property names
- self.emit('property-changed', prop_list)
- return False
-
- def _property_changed_cb(self, prop_list):
- """Handle dbus signal by emitting a GObject signal"""
- gobject.idle_add(self._handle_property_changed_signal, prop_list)
-
- def get_icon_pixbuf(self):
- """Retrieve Buddy's icon as a GTK pixel buffer
-
- XXX Why aren't the icons coming in as SVG?
- """
- if self.props.icon and len(self.props.icon):
- pbl = gtk.gdk.PixbufLoader()
- pbl.write(self.props.icon)
- pbl.close()
- return pbl.get_pixbuf()
- else:
- return None
-
- def get_joined_activities(self):
- """Retrieve the set of all activities which this buddy has joined
-
- Uses the GetJoinedActivities method on the service
- object to produce object paths, wraps each in an
- Activity object.
-
- returns list of presence Activity objects
- """
- try:
- resp = self._buddy.GetJoinedActivities()
- except dbus.exceptions.DBusException:
- return []
- acts = []
- for item in resp:
- acts.append(self._ps_new_object(item))
- return acts
diff --git a/sugar/presence/presenceservice.py b/sugar/presence/presenceservice.py
deleted file mode 100644
index e652f42..0000000
--- a/sugar/presence/presenceservice.py
+++ /dev/null
@@ -1,570 +0,0 @@
-"""UI class to access system-level presence object"""
-# 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 logging
-
-import dbus
-import dbus.exceptions
-import dbus.glib
-import gobject
-
-from sugar.presence.buddy import Buddy
-from sugar.presence.activity import Activity
-
-
-DBUS_SERVICE = "org.laptop.Sugar.Presence"
-DBUS_INTERFACE = "org.laptop.Sugar.Presence"
-DBUS_PATH = "/org/laptop/Sugar/Presence"
-
-_logger = logging.getLogger('sugar.presence.presenceservice')
-
-
-class PresenceService(gobject.GObject):
- """UI-side interface to the dbus presence service
-
- This class provides UI programmers with simplified access
- to the dbus service of the same name. It allows for observing
- various events from the presence service as GObject events,
- as well as some basic introspection queries.
- """
- __gsignals__ = {
- 'buddy-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'buddy-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- # parameters: (activity: Activity, inviter: Buddy, message: unicode)
- 'activity-invitation': (gobject.SIGNAL_RUN_FIRST, None, ([object]*3)),
- 'private-invitation': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT,
- gobject.TYPE_PYOBJECT])),
- 'activity-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'activity-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'activity-shared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT,
- gobject.TYPE_PYOBJECT]))
- }
-
- _PS_BUDDY_OP = DBUS_PATH + "/Buddies/"
- _PS_ACTIVITY_OP = DBUS_PATH + "/Activities/"
-
-
- def __init__(self, allow_offline_iface=True):
- """Initialise the service and attempt to connect to events
- """
- gobject.GObject.__init__(self)
- self._objcache = {}
-
- # Get a connection to the session bus
- self._bus = dbus.SessionBus()
- self._bus.add_signal_receiver(self._name_owner_changed_cb,
- signal_name="NameOwnerChanged",
- dbus_interface="org.freedesktop.DBus")
-
- # attempt to load the interface to the service...
- self._allow_offline_iface = allow_offline_iface
- self._get_ps()
-
- def _name_owner_changed_cb(self, name, old, new):
- if name != DBUS_SERVICE:
- return
- if (old and len(old)) and (not new and not len(new)):
- # PS went away, clear out PS dbus service wrapper
- self._ps_ = None
- elif (not old and not len(old)) and (new and len(new)):
- # PS started up
- self._get_ps()
-
- _ps_ = None
- def _get_ps(self):
- """Retrieve dbus interface to PresenceService
-
- Also registers for updates from various dbus events on the
- interface.
-
- If unable to retrieve the interface, we will temporarily
- return an _OfflineInterface object to allow the calling
- code to continue functioning as though it had accessed a
- real presence service.
-
- If successful, caches the presence service interface
- for use by other methods and returns that interface
- """
- if not self._ps_:
- try:
- # NOTE: We need to follow_name_owner_changes here
- # because we can not connect to a signal unless
- # we follow the changes or we start the service
- # before we connect. Starting the service here
- # causes a major bottleneck during startup
- ps = dbus.Interface(
- self._bus.get_object(DBUS_SERVICE,
- DBUS_PATH,
- follow_name_owner_changes=True),
- DBUS_INTERFACE
- )
- except dbus.exceptions.DBusException, err:
- _logger.error(
- """Failure retrieving %r interface from the D-BUS service %r %r: %s""",
- DBUS_INTERFACE, DBUS_SERVICE, DBUS_PATH, err
- )
- if self._allow_offline_iface:
- return _OfflineInterface()
- raise RuntimeError("Failed to connect to the presence service.")
- else:
- self._ps_ = ps
- ps.connect_to_signal('BuddyAppeared', self._buddy_appeared_cb)
- ps.connect_to_signal('BuddyDisappeared', self._buddy_disappeared_cb)
- ps.connect_to_signal('ActivityAppeared', self._activity_appeared_cb)
- ps.connect_to_signal('ActivityDisappeared', self._activity_disappeared_cb)
- ps.connect_to_signal('ActivityInvitation', self._activity_invitation_cb)
- ps.connect_to_signal('PrivateInvitation', self._private_invitation_cb)
- return self._ps_
-
- _ps = property(
- _get_ps, None, None,
- """DBUS interface to the PresenceService (services/presence/presenceservice)"""
- )
-
- def _new_object(self, object_path):
- """Turn new object path into (cached) Buddy/Activity instance
-
- object_path -- full dbus path of the new object, must be
- prefixed with either of _PS_BUDDY_OP or _PS_ACTIVITY_OP
-
- Note that this method is called throughout the class whenever
- the representation of the object is required, it is not only
- called when the object is first discovered. The point is to only have
- _one_ Python object for any D-Bus object represented by an object path,
- effectively wrapping the D-Bus object in a single Python GObject.
-
- returns presence Buddy or Activity representation
- """
- obj = None
- try:
- obj = self._objcache[object_path]
- except KeyError:
- if object_path.startswith(self._PS_BUDDY_OP):
- obj = Buddy(self._bus, self._new_object,
- self._del_object, object_path)
- elif object_path.startswith(self._PS_ACTIVITY_OP):
- obj = Activity(self._bus, self._new_object,
- self._del_object, object_path)
- try:
- # Pre-fill the activity's ID
- foo = obj.props.id
- except dbus.exceptions.DBusException, err:
- pass
- else:
- raise RuntimeError("Unknown object type")
- self._objcache[object_path] = obj
- return obj
-
- def _have_object(self, object_path):
- return object_path in self._objcache.keys()
-
- def _del_object(self, object_path):
- """Fully remove an object from the object cache when it's no longer needed.
- """
- del self._objcache[object_path]
-
- def _emit_buddy_appeared_signal(self, object_path):
- """Emit GObject event with presence.buddy.Buddy object"""
- self.emit('buddy-appeared', self._new_object(object_path))
- return False
-
- def _buddy_appeared_cb(self, op):
- """Callback for dbus event (forwards to method to emit GObject event)"""
- gobject.idle_add(self._emit_buddy_appeared_signal, op)
-
- def _emit_buddy_disappeared_signal(self, object_path):
- """Emit GObject event with presence.buddy.Buddy object"""
- # Don't try to create a new object here if needed; it will probably
- # fail anyway because the object has already been destroyed in the PS
- if self._have_object(object_path):
- self.emit('buddy-disappeared', self._new_object(object_path))
- return False
-
- def _buddy_disappeared_cb(self, object_path):
- """Callback for dbus event (forwards to method to emit GObject event)"""
- gobject.idle_add(self._emit_buddy_disappeared_signal, object_path)
-
- def _emit_activity_invitation_signal(self, activity_path, buddy_path,
- message):
- """Emit GObject event with presence.activity.Activity object"""
- self.emit('activity-invitation', self._new_object(activity_path),
- self._new_object(buddy_path), unicode(message))
- return False
-
- def _activity_invitation_cb(self, activity_path, buddy_path, message):
- """Callback for dbus event (forwards to method to emit GObject event)"""
- gobject.idle_add(self._emit_activity_invitation_signal, activity_path,
- buddy_path, message)
-
- def _emit_private_invitation_signal(self, bus_name, connection, channel):
- """Emit GObject event with bus_name, connection and channel"""
- self.emit('private-invitation', bus_name, connection, channel)
- return False
-
- def _private_invitation_cb(self, bus_name, connection, channel):
- """Callback for dbus event (forwards to method to emit GObject event)"""
- gobject.idle_add(self._emit_service_disappeared_signal, bus_name,
- connection, channel)
-
- def _emit_activity_appeared_signal(self, object_path):
- """Emit GObject event with presence.activity.Activity object"""
- self.emit('activity-appeared', self._new_object(object_path))
- return False
-
- def _activity_appeared_cb(self, object_path):
- """Callback for dbus event (forwards to method to emit GObject event)"""
- gobject.idle_add(self._emit_activity_appeared_signal, object_path)
-
- def _emit_activity_disappeared_signal(self, object_path):
- """Emit GObject event with presence.activity.Activity object"""
- self.emit('activity-disappeared', self._new_object(object_path))
- return False
-
- def _activity_disappeared_cb(self, object_path):
- """Callback for dbus event (forwards to method to emit GObject event)"""
- gobject.idle_add(self._emit_activity_disappeared_signal, object_path)
-
- def get(self, object_path):
- """Return the Buddy or Activity object corresponding to the given
- D-Bus object path.
- """
- return self._new_object(object_path)
-
- def get_activities(self):
- """Retrieve set of all activities from service
-
- returns list of Activity objects for all object paths
- the service reports exist (using GetActivities)
- """
- try:
- resp = self._ps.GetActivities()
- except dbus.exceptions.DBusException, err:
- _logger.warn(
- """Unable to retrieve activity list from presence service: %s"""
- % err
- )
- return []
- else:
- acts = []
- for item in resp:
- acts.append(self._new_object(item))
- return acts
-
- def _get_activities_cb(self, reply_handler, resp):
- acts = []
- for item in resp:
- acts.append(self._new_object(item))
-
- reply_handler(acts)
-
- def _get_activities_error_cb(self, error_handler, e):
- if error_handler:
- error_handler(e)
- else:
- _logger.warn(
- """Unable to retrieve activity-list from presence service: %s"""
- % e
- )
-
- def get_activities_async(self, reply_handler=None, error_handler=None):
- """Retrieve set of all activities from service asyncronously
- """
-
- if not reply_handler:
- logging.error('Function get_activities_async called without a reply handler. Can not run.')
- return
-
- self._ps.GetActivities(
- reply_handler=lambda resp:self._get_activities_cb(reply_handler, resp),
- error_handler=lambda e:self._get_activities_error_cb(error_handler, e))
-
-
- def get_activity(self, activity_id):
- """Retrieve single Activity object for the given unique id
-
- activity_id -- unique ID for the activity
-
- returns single Activity object or None if the activity
- is not found using GetActivityById on the service
- """
- try:
- act_op = self._ps.GetActivityById(activity_id)
- except dbus.exceptions.DBusException, err:
- _logger.warn(
- """Unable to retrieve activity handle for %r from presence service: %s"""
- % (activity_id, err)
- )
- return None
- return self._new_object(act_op)
-
- def get_buddies(self):
- """Retrieve set of all buddies from service
-
- returns list of Buddy objects for all object paths
- the service reports exist (using GetBuddies)
- """
- try:
- resp = self._ps.GetBuddies()
- except dbus.exceptions.DBusException, err:
- _logger.warn(
- """Unable to retrieve buddy-list from presence service: %s"""
- % err
- )
- return []
- else:
- buddies = []
- for item in resp:
- buddies.append(self._new_object(item))
- return buddies
-
- def _get_buddies_cb(self, reply_handler, resp):
- buddies = []
- for item in resp:
- buddies.append(self._new_object(item))
-
- reply_handler(buddies)
-
- def _get_buddies_error_cb(self, error_handler, e):
- if error_handler:
- error_handler(e)
- else:
- _logger.warn(
- """Unable to retrieve buddy-list from presence service: %s"""
- % e
- )
-
- def get_buddies_async(self, reply_handler=None, error_handler=None):
- """Retrieve set of all buddies from service asyncronously
- """
-
- if not reply_handler:
- logging.error('Function get_buddies_async called without a reply handler. Can not run.')
- return
-
- self._ps.GetBuddies(
- reply_handler=lambda resp:self._get_buddies_cb(reply_handler, resp),
- error_handler=lambda e:self._get_buddies_error_cb(error_handler, e))
-
- def get_buddy(self, key):
- """Retrieve single Buddy object for the given public key
-
- key -- buddy's public encryption key
-
- returns single Buddy object or None if the activity
- is not found using GetBuddyByPublicKey on the
- service
- """
- try:
- buddy_op = self._ps.GetBuddyByPublicKey(dbus.ByteArray(key))
- except dbus.exceptions.DBusException, err:
- _logger.warn(
- """Unable to retrieve buddy handle for %r from presence service: %s"""
- % key, err
- )
- return None
- return self._new_object(buddy_op)
-
- def get_buddy_by_telepathy_handle(self, tp_conn_name, tp_conn_path,
- handle):
- """Retrieve single Buddy object for the given public key
-
- :Parameters:
- `tp_conn_name` : str
- The well-known bus name of a Telepathy connection
- `tp_conn_path` : dbus.ObjectPath
- The object path of the Telepathy connection
- `handle` : int or long
- The handle of a Telepathy contact on that connection,
- of type HANDLE_TYPE_CONTACT. This may not be a
- channel-specific handle.
- :Returns: the Buddy object, or None if the buddy is not found
- """
- try:
- buddy_op = self._ps.GetBuddyByTelepathyHandle(tp_conn_name,
- tp_conn_path,
- handle)
- except dbus.exceptions.DBusException, err:
- _logger.warn('Unable to retrieve buddy handle for handle %u at '
- 'conn %s:%s from presence service: %s',
- handle, tp_conn_name, tp_conn_path, err)
- return None
- return self._new_object(buddy_op)
-
- def get_owner(self):
- """Retrieves the laptop "owner" Buddy object."""
- try:
- owner_op = self._ps.GetOwner()
- except dbus.exceptions.DBusException, err:
- _logger.warn(
- """Unable to retrieve local user/owner from presence service: %s"""
- % err
- )
- raise RuntimeError("Could not get owner object from presence service.")
- return self._new_object(owner_op)
-
- def _share_activity_cb(self, activity, psact):
- """Notify with GObject event of successful sharing of activity
- """
- psact._joined = True
- self.emit("activity-shared", True, psact, None)
-
- def _share_activity_privacy_cb(self, activity, private, op):
- psact = self._new_object(op)
- # FIXME: this should be done asynchronously (more API needed)
- try:
- psact.props.private = private
- except Exception, e:
- self._share_activity_error_cb(activity, e)
- else:
- self._share_activity_cb(activity, psact)
-
- def _share_activity_error_cb(self, activity, err):
- """Notify with GObject event of unsuccessful sharing of activity"""
- _logger.debug("Error sharing activity %s: %s" % (activity.get_id(), err))
- self.emit("activity-shared", False, None, err)
-
- def share_activity(self, activity, properties={}, private=True):
- """Ask presence service to ask the activity to share itself publicly.
-
- Uses the AdvertiseActivity method on the service to ask for the
- sharing of the given activity. Arranges to emit activity-shared
- event with:
-
- (success, Activity, err)
-
- on success/failure.
-
- returns None
- """
- actid = activity.get_id()
-
- # 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)
-
- atype = activity.get_bundle_id()
- name = activity.props.title
- self._ps.ShareActivity(actid, atype, name, properties,
- reply_handler=lambda op: \
- self._share_activity_privacy_cb(activity, private, op),
- error_handler=lambda e: \
- self._share_activity_error_cb(activity, e))
-
- def get_preferred_connection(self):
- """Gets the preferred telepathy connection object that an activity
- should use when talking directly to telepathy
-
- returns the bus name and the object path of the Telepathy connection"""
-
- try:
- bus_name, object_path = self._ps.GetPreferredConnection()
- except dbus.exceptions.DBusException:
- return None
-
- return bus_name, object_path
-
-class _OfflineInterface( object ):
- """Offline-presence-service interface
-
- Used to mimic the behaviour of a real PresenceService sufficiently
- to avoid crashing client code that expects the given interface.
-
- XXX we could likely return a "MockOwner" object reasonably
- easily, but would it be worth it?
- """
- def raiseException( self, *args, **named ):
- """Raise dbus.exceptions.DBusException"""
- raise dbus.exceptions.DBusException(
- """PresenceService Interface not available"""
- )
- GetActivities = raiseException
- GetActivityById = raiseException
- GetBuddies = raiseException
- GetBuddyByPublicKey = raiseException
- GetOwner = raiseException
- GetPreferredConnection = raiseException
- def ShareActivity(
- self, actid, atype, name, properties,
- reply_handler, error_handler,
- ):
- """Pretend to share and fail..."""
- exc = IOError(
- """Unable to share activity as PresenceService is not currenly available"""
- )
- return error_handler( exc )
-
-class _MockPresenceService(gobject.GObject):
- """Test fixture allowing testing of items that use PresenceService
-
- See PresenceService for usage and purpose
- """
- __gsignals__ = {
- 'buddy-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'buddy-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'activity-invitation': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'private-invitation': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT,
- gobject.TYPE_PYOBJECT])),
- 'activity-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'activity-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT]))
- }
-
- def __init__(self):
- gobject.GObject.__init__(self)
-
- def get_activities(self):
- return []
-
- def get_activity(self, activity_id):
- return None
-
- def get_buddies(self):
- return []
-
- def get_buddy(self, key):
- return None
-
- def get_owner(self):
- return None
-
- def share_activity(self, activity, properties={}):
- return None
-
-_ps = None
-def get_instance(allow_offline_iface=False):
- """Retrieve this process' view of the PresenceService"""
- global _ps
- if not _ps:
- _ps = PresenceService(allow_offline_iface)
- return _ps
-
diff --git a/sugar/presence/test_presence.txt b/sugar/presence/test_presence.txt
deleted file mode 100644
index d0736a9..0000000
--- a/sugar/presence/test_presence.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-This is a test of presence.
-
-To test this service we will start up a mock dbus library:
-
- >>> from sugar.testing import mockdbus
- >>> import dbus
- >>> pres_service = mockdbus.MockService(
- ... 'org.laptop.Presence', '/org/laptop/Presence', name='pres')
- >>> pres_service.install()
- >>> pres_interface = dbus.Interface(pres_service, 'org.laptop.Presence')
-
-Then we import the library (second, to make sure it connects to our
-mocked system, though the lazy instantiation in get_instance() should
-handle it):
-
- >>> from sugar.presence import PresenceService
- >>> ps = PresenceService.get_instance()
- >>> pres_interface.make_response('getServices', [])
- >>> ps.get_services()
- Called pres.org.laptop.Presence:getServices()
- []
- >>> pres_interface.make_response('getBuddies', [])
- >>> ps.get_buddies()
- Called pres.org.laptop.Presence:getBuddies()
- []
-
diff --git a/sugar/presence/tubeconn.py b/sugar/presence/tubeconn.py
deleted file mode 100644
index b487391..0000000
--- a/sugar/presence/tubeconn.py
+++ /dev/null
@@ -1,107 +0,0 @@
-# This should eventually land in telepathy-python, so has the same license:
-
-# Copyright (C) 2007 Collabora Ltd. <http://www.collabora.co.uk/>
-#
-# This program 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.1 of the License, or
-# (at your option) any later version.
-#
-# This program 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 program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-
-__all__ = ('TubeConnection',)
-__docformat__ = 'reStructuredText'
-
-
-import logging
-
-from dbus.connection import Connection
-
-
-logger = logging.getLogger('telepathy.tubeconn')
-
-
-class TubeConnection(Connection):
-
- def __new__(cls, conn, tubes_iface, tube_id, address=None,
- group_iface=None, mainloop=None):
- if address is None:
- address = tubes_iface.GetDBusTubeAddress(tube_id)
- self = super(TubeConnection, cls).__new__(cls, address,
- mainloop=mainloop)
-
- self._tubes_iface = tubes_iface
- self.tube_id = tube_id
- self.participants = {}
- self.bus_name_to_handle = {}
- self._mapping_watches = []
-
- if group_iface is None:
- method = conn.GetSelfHandle
- else:
- method = group_iface.GetSelfHandle
- method(reply_handler=self._on_get_self_handle_reply,
- error_handler=self._on_get_self_handle_error)
-
- return self
-
- def _on_get_self_handle_reply(self, handle):
- self.self_handle = handle
- match = self._tubes_iface.connect_to_signal('DBusNamesChanged',
- self._on_dbus_names_changed)
- self._tubes_iface.GetDBusNames(self.tube_id,
- reply_handler=self._on_get_dbus_names_reply,
- error_handler=self._on_get_dbus_names_error)
- self._dbus_names_changed_match = match
-
- def _on_get_self_handle_error(self, e):
- logging.basicConfig()
- logger.error('GetSelfHandle failed: %s', e)
-
- def close(self):
- self._dbus_names_changed_match.remove()
- self._on_dbus_names_changed(self.tube_id, (), self.participants.keys())
- super(TubeConnection, self).close()
-
- def _on_get_dbus_names_reply(self, names):
- self._on_dbus_names_changed(self.tube_id, names, ())
-
- def _on_get_dbus_names_error(self, e):
- logging.basicConfig()
- logger.error('GetDBusNames failed: %s', e)
-
- def _on_dbus_names_changed(self, tube_id, added, removed):
- if tube_id == self.tube_id:
- for handle, bus_name in added:
- if handle == self.self_handle:
- # I've just joined - set my unique name
- self.set_unique_name(bus_name)
- self.participants[handle] = bus_name
- self.bus_name_to_handle[bus_name] = handle
-
- # call the callback while the removed people are still in
- # participants, so their bus names are available
- for callback in self._mapping_watches:
- callback(added, removed)
-
- for handle in removed:
- bus_name = self.participants.pop(handle, None)
- self.bus_name_to_handle.pop(bus_name, None)
-
- def watch_participants(self, callback):
- self._mapping_watches.append(callback)
- if self.participants:
- # GetDBusNames already returned: fake a participant add event
- # immediately
- added = []
- for k, v in self.participants.iteritems():
- added.append((k, v))
- callback(added, [])
diff --git a/sugar/profile.py b/sugar/profile.py
deleted file mode 100644
index 10a2b6c..0000000
--- a/sugar/profile.py
+++ /dev/null
@@ -1,199 +0,0 @@
-"""User settings/configuration loading"""
-# 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 os
-import logging
-from ConfigParser import ConfigParser
-
-from sugar import env
-from sugar import util
-from sugar.graphics.xocolor import XoColor
-
-DEFAULT_JABBER_SERVER = 'olpc.collabora.co.uk'
-DEFAULT_VOLUME = 81
-
-_profile = None
-
-def _set_key(cp, section, key, value):
- if not cp.has_section(section):
- cp.add_section(section)
- cp.set(section, key, value)
-
-class Profile(object):
- """Local user's current options/profile information
-
- User settings are stored in an INI-style configuration
- file. This object uses the ConfigParser module to load
- the settings. (We only very rarely set keys, so we don't
- keep the ConfigParser around between calls.)
-
- The profile is also responsible for loading the user's
- public and private ssh keys from disk.
-
- Attributes:
-
- name -- child's name
- color -- XoColor for the child's icon
- server -- school server with which the child is
- associated
- server_registered -- whether the child has registered
- with the school server or not
- backup1 -- temporary backup info key for Trial-2
-
- pubkey -- public ssh key
- privkey_hash -- SHA has of the child's public key
- """
- def __init__(self, path):
- self.nick_name = None
- self.color = None
- self.pubkey = None
- self.privkey_hash = None
- self.jabber_server = DEFAULT_JABBER_SERVER
- self.jabber_registered = False
- self.backup1 = None
-
- self._config_path = path
-
- self._load_config()
- self._load_pubkey()
- self._hash_private_key()
-
- def is_valid(self):
- return self.nick_name is not None and \
- self.color is not None and \
- self.pubkey is not None and \
- self.privkey_hash is not None
-
- def is_registered(self):
- return self.backup1 is not None
-
- def save(self):
- cp = ConfigParser()
- parsed = cp.read([self._config_path])
-
- if self.nick_name:
- _set_key(cp, 'Buddy', 'NickName', self.nick_name)
- if self.color:
- _set_key(cp, 'Buddy', 'Color', self.color.to_string())
- if self.backup1:
- _set_key(cp, 'Server', 'Backup1', self.backup1)
- if self.jabber_server:
- _set_key(cp, 'Jabber', 'Server', self.jabber_server)
-
- _set_key(cp, 'Jabber', 'Registered', self.jabber_registered)
-
- _set_key(cp, 'Sound', 'Volume', self.sound_volume)
-
- f = open(self._config_path, 'w')
- cp.write(f)
- f.close()
-
- def _load_config(self):
- cp = ConfigParser()
- parsed = cp.read([self._config_path])
-
- if cp.has_option('Buddy', 'NickName'):
- name = cp.get('Buddy', 'NickName')
- # decode nickname from ascii-safe chars to unicode
- self.nick_name = name.decode("utf-8")
- if cp.has_option('Buddy', 'Color'):
- self.color = XoColor(cp.get('Buddy', 'Color'))
- if cp.has_option('Jabber', 'Server'):
- self.jabber_server = cp.get('Jabber', 'Server')
- if cp.has_option('Jabber', 'Registered'):
- registered = cp.get('Jabber', 'Registered')
- if registered.lower() == "true":
- self.jabber_registered = True
- if cp.has_option('Server', 'Backup1'):
- self.backup1 = cp.get('Server', 'Backup1')
- if cp.has_option('Sound', 'Volume'):
- self.sound_volume = float(cp.get('Sound', 'Volume'))
- else:
- self.sound_volume = DEFAULT_VOLUME
-
- del cp
-
- def _load_pubkey(self):
- self.pubkey = None
-
- key_path = os.path.join(env.get_profile_path(), 'owner.key.pub')
- try:
- f = open(key_path, "r")
- lines = f.readlines()
- f.close()
- except IOError, e:
- self.valid = False
- logging.error("Error reading public key: %s" % e)
- return
-
- magic = "ssh-dss "
- for l in lines:
- l = l.strip()
- if not l.startswith(magic):
- continue
- self.pubkey = l[len(magic):]
- break
- if not self.pubkey:
- logging.error("Error parsing public key.")
-
- def _hash_private_key(self):
- self.privkey_hash = None
-
- key_path = os.path.join(env.get_profile_path(), 'owner.key')
- try:
- f = open(key_path, "r")
- lines = f.readlines()
- f.close()
- except IOError, e:
- logging.error("Error reading private key: %s" % e)
- return
-
- key = ""
- for l in lines:
- l = l.strip()
- if l.startswith("-----BEGIN DSA PRIVATE KEY-----"):
- continue
- if l.startswith("-----END DSA PRIVATE KEY-----"):
- continue
- key += l
- if not len(key):
- logging.error("Error parsing public key.")
-
- # hash it
- key_hash = util._sha_data(key)
- self.privkey_hash = util.printable_hash(key_hash)
-
-def get_profile():
- global _profile
-
- if not _profile:
- path = os.path.join(env.get_profile_path(), 'config')
- _profile = Profile(path)
-
- return _profile
-
-# Convenience methods for frequently used properties
-
-def get_nick_name():
- return get_profile().nick_name
-
-def get_color():
- return get_profile().color
-
-def get_pubkey():
- return get_profile().pubkey
diff --git a/sugar/util.py b/sugar/util.py
deleted file mode 100644
index 8a3fb4a..0000000
--- a/sugar/util.py
+++ /dev/null
@@ -1,175 +0,0 @@
-"""Various utility functions"""
-# 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 time
-import sha
-import random
-import binascii
-import string
-import os
-import logging
-
-from ConfigParser import ConfigParser
-from ConfigParser import NoOptionError
-
-def printable_hash(in_hash):
- """Convert binary hash data into printable characters."""
- printable = ""
- for char in in_hash:
- printable = printable + binascii.b2a_hex(char)
- return printable
-
-def _sha_data(data):
- """sha1 hash some bytes."""
- sha_hash = sha.new()
- sha_hash.update(data)
- return sha_hash.digest()
-
-def unique_id(data = ''):
- """Generate a likely-unique ID for whatever purpose
-
- data -- suffix appended to working data before hashing
-
- Returns a 40-character string with hexidecimal digits
- representing an SHA hash of the time, a random digit
- within a constrained range and the data passed.
-
- Note: these are *not* crypotographically secure or
- globally unique identifiers. While they are likely
- to be unique-enough, no attempt is made to make
- perfectly unique values.
- """
- data_string = "%s%s%s" % (time.time(), random.randint(10000, 100000), data)
- return printable_hash(_sha_data(data_string))
-
-
-ACTIVITY_ID_LEN = 40
-
-def is_hex(s):
- return s.strip(string.hexdigits) == ''
-
-def validate_activity_id(actid):
- """Validate an activity ID."""
- if not isinstance(actid, (str,unicode)):
- return False
- if len(actid) != ACTIVITY_ID_LEN:
- return False
- if not is_hex(actid):
- return False
- return True
-
-def set_proc_title(title):
- """Sets the process title so ps and top show more
- descriptive names. This does not modify argv[0]
- and only the first 15 characters will be shown.
-
- title -- the title you wish to change the process
- title to
-
- Returns True on success. We don't raise exceptions
- because if something goes wrong here it is not a big
- deal as this is intended as a nice thing to have for
- debugging
- """
- try:
- import ctypes
- libc = ctypes.CDLL('libc.so.6')
- libc.prctl(15, str(title), 0, 0, 0)
-
- return True
- except:
- return False
-
-class Node(object):
- __slots__ = ['prev', 'next', 'me']
- def __init__(self, prev, me):
- self.prev = prev
- self.me = me
- self.next = None
-
-class LRU:
- """
- Implementation of a length-limited O(1) LRU queue.
- Built for and used by PyPE:
- http://pype.sourceforge.net
- Copyright 2003 Josiah Carlson.
- """
- def __init__(self, count, pairs=[]):
- self.count = max(count, 1)
- self.d = {}
- self.first = None
- self.last = None
- for key, value in pairs:
- self[key] = value
- def __contains__(self, obj):
- return obj in self.d
- def __getitem__(self, obj):
- a = self.d[obj].me
- self[a[0]] = a[1]
- return a[1]
- def __setitem__(self, obj, val):
- if obj in self.d:
- del self[obj]
- nobj = Node(self.last, (obj, val))
- if self.first is None:
- self.first = nobj
- if self.last:
- self.last.next = nobj
- self.last = nobj
- self.d[obj] = nobj
- if len(self.d) > self.count:
- if self.first == self.last:
- self.first = None
- self.last = None
- return
- a = self.first
- a.next.prev = None
- self.first = a.next
- a.next = None
- del self.d[a.me[0]]
- del a
- def __delitem__(self, obj):
- nobj = self.d[obj]
- if nobj.prev:
- nobj.prev.next = nobj.next
- else:
- self.first = nobj.next
- if nobj.next:
- nobj.next.prev = nobj.prev
- else:
- self.last = nobj.prev
- del self.d[obj]
- def __iter__(self):
- cur = self.first
- while cur != None:
- cur2 = cur.next
- yield cur.me[1]
- cur = cur2
- def iteritems(self):
- cur = self.first
- while cur != None:
- cur2 = cur.next
- yield cur.me
- cur = cur2
- def iterkeys(self):
- return iter(self.d)
- def itervalues(self):
- for i,j in self.iteritems():
- yield j
- def keys(self):
- return self.d.keys()
diff --git a/sugar/wm.py b/sugar/wm.py
deleted file mode 100644
index 999e07a..0000000
--- a/sugar/wm.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# 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
-
-import _sugaruiext
-
-def get_activity_id(wnck_window):
- window = gtk.gdk.window_foreign_new(wnck_window.get_xid())
- return _sugaruiext.x11_get_string_property(
- window, '_SUGAR_ACTIVITY_ID')
-
-def get_bundle_id(wnck_window):
- window = gtk.gdk.window_foreign_new(wnck_window.get_xid())
- return _sugaruiext.x11_get_string_property(
- window, '_SUGAR_BUNDLE_ID')
-
-def set_activity_id(window, activity_id):
- _sugaruiext.x11_set_string_property(
- window, '_SUGAR_ACTIVITY_ID', activity_id)
-
-def set_bundle_id(window, bundle_id):
- _sugaruiext.x11_set_string_property(
- window, '_SUGAR_BUNDLE_ID', bundle_id)