Merge branch 'master' of git+ssh://dev.laptop.org/git/sugar
This commit is contained in:
commit
cd12b59967
4
.gitignore
vendored
4
.gitignore
vendored
@ -10,6 +10,7 @@ Makefile.in
|
|||||||
*.lo
|
*.lo
|
||||||
*.loT
|
*.loT
|
||||||
.*.sw?
|
.*.sw?
|
||||||
|
*.service
|
||||||
|
|
||||||
# Absolute
|
# Absolute
|
||||||
|
|
||||||
@ -51,9 +52,6 @@ browser/sugar-marshal.c
|
|||||||
browser/sugar-marshal.h
|
browser/sugar-marshal.h
|
||||||
browser/stamp-sugar-marshal.c
|
browser/stamp-sugar-marshal.c
|
||||||
browser/stamp-sugar-marshal.h
|
browser/stamp-sugar-marshal.h
|
||||||
services/clipboard/org.laptop.Clipboard.service
|
|
||||||
services/console/org.laptop.sugar.Console.service
|
|
||||||
services/presence/org.laptop.Sugar.Presence.service
|
|
||||||
bin/sugar
|
bin/sugar
|
||||||
shell/extensions/_extensions.c
|
shell/extensions/_extensions.c
|
||||||
data/sugar.gtkrc
|
data/sugar.gtkrc
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
VERSION=0.63
|
VERSION=0.64
|
||||||
DATE=`date +%Y%m%d`
|
ALPHATAG=`git-show-ref --hash=10 refs/heads/master`
|
||||||
RELEASE=2.87
|
TARBALL=sugar-$VERSION-git$ALPHATAG.tar.bz2
|
||||||
TARBALL=sugar-$VERSION-$RELEASE.${DATE}git.tar.bz2
|
|
||||||
|
|
||||||
rm sugar-$VERSION.tar.bz2
|
rm sugar-$VERSION.tar.bz2
|
||||||
|
|
||||||
XUL_SDK=/home/marco/sugar-jhbuild/build/lib/xulrunner-1.9a5pre-dev
|
make distcheck
|
||||||
DISTCHECK_CONFIGURE_FLAGS="--with-libxul-sdk=$XUL_SDK" make distcheck
|
|
||||||
|
|
||||||
mv sugar-$VERSION.tar.bz2 $TARBALL
|
mv sugar-$VERSION.tar.bz2 $TARBALL
|
||||||
scp $TARBALL mpg@devserv.devel.redhat.com:~
|
scp $TARBALL mpg@devserv.devel.redhat.com:~
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
AC_INIT([Sugar],[0.63],[],[sugar])
|
AC_INIT([Sugar],[0.64],[],[sugar])
|
||||||
|
|
||||||
AC_PREREQ([2.59])
|
AC_PREREQ([2.59])
|
||||||
|
|
||||||
|
@ -1,17 +1,22 @@
|
|||||||
servicedir = $(datadir)/dbus-1/services
|
servicedir = $(datadir)/dbus-1/services
|
||||||
service_in_files = org.laptop.Clipboard.service.in
|
|
||||||
|
service_in_files = \
|
||||||
|
org.laptop.Clipboard.service.in \
|
||||||
|
org.laptop.ObjectTypeRegistry.service.in
|
||||||
|
|
||||||
service_DATA = $(service_in_files:.service.in=.service)
|
service_DATA = $(service_in_files:.service.in=.service)
|
||||||
|
|
||||||
$(service_DATA): $(service_in_files) Makefile
|
$(service_DATA): $(service_in_files) Makefile
|
||||||
@sed -e "s|\@bindir\@|$(bindir)|" $< > $@
|
@sed -e "s|\@bindir\@|$(bindir)|" $< > $@
|
||||||
|
|
||||||
sugardir = $(pkgdatadir)/services/clipboard
|
sugardir = $(pkgdatadir)/services/clipboard
|
||||||
sugar_PYTHON = \
|
|
||||||
__init__.py \
|
|
||||||
clipboardobject.py \
|
|
||||||
clipboardservice.py \
|
|
||||||
typeregistry.py
|
|
||||||
|
|
||||||
|
sugar_PYTHON = \
|
||||||
|
__init__.py \
|
||||||
|
clipboardobject.py \
|
||||||
|
clipboardservice.py \
|
||||||
|
objecttypeservice.py \
|
||||||
|
typeregistry.py
|
||||||
|
|
||||||
bin_SCRIPTS = sugar-clipboard
|
bin_SCRIPTS = sugar-clipboard
|
||||||
|
|
||||||
|
62
services/clipboard/objecttypeservice.py
Normal file
62
services/clipboard/objecttypeservice.py
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# Copyright (C) 2007, Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 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 General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
import dbus
|
||||||
|
import dbus.service
|
||||||
|
|
||||||
|
from sugar.objects.objecttype import ObjectType
|
||||||
|
|
||||||
|
_REGISTRY_IFACE = "org.laptop.ObjectTypeRegistry"
|
||||||
|
_REGISTRY_PATH = "/org/laptop/ObjectTypeRegistry"
|
||||||
|
|
||||||
|
class ObjectTypeRegistry(dbus.service.Object):
|
||||||
|
def __init__(self):
|
||||||
|
bus = dbus.SessionBus()
|
||||||
|
bus_name = dbus.service.BusName(self._REGISTRY_IFACE, bus=bus)
|
||||||
|
dbus.service.Object.__init__(self, bus_name, self._REGISTRY_PATH)
|
||||||
|
|
||||||
|
self._types = {}
|
||||||
|
|
||||||
|
self._add_primitive('Text', _('Text'), 'object-text',
|
||||||
|
[ 'text/rtf' ])
|
||||||
|
self._add_primitive('Image', _('Image'), 'object-image',
|
||||||
|
[ 'image/png' ])
|
||||||
|
|
||||||
|
def _add_primitive(self, type_id, name, icon, mime_types):
|
||||||
|
object_type = ObjectType(type_id, name, icon, mime_types)
|
||||||
|
self._types.add(object_type)
|
||||||
|
|
||||||
|
def _get_type_for_mime(self, mime_type):
|
||||||
|
for object_type in self._types.values():
|
||||||
|
if mime_type in object_type.mime_types:
|
||||||
|
return object_type
|
||||||
|
|
||||||
|
@dbus.service.method(_CLIPBOARD_DBUS_INTERFACE,
|
||||||
|
in_signature="s", out_signature="a{sv}")
|
||||||
|
def GetType(self, type_id):
|
||||||
|
if self._types.has_key(type_id):
|
||||||
|
return self._types[type_id].to_dict()
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
|
||||||
|
@dbus.service.method(_CLIPBOARD_DBUS_INTERFACE,
|
||||||
|
in_signature="s", out_signature="a{sv}")
|
||||||
|
def GetTypeForMIME(self, mime_type):
|
||||||
|
object_type = self._get_type_for_mime(mime_type)
|
||||||
|
if object_type:
|
||||||
|
return object_type.to_dict()
|
||||||
|
else:
|
||||||
|
return []
|
@ -0,0 +1,4 @@
|
|||||||
|
[D-BUS Service]
|
||||||
|
Name = org.laptop.ObjectTypeRegistry
|
||||||
|
Exec = @bindir@/sugar-clipboard
|
||||||
|
|
@ -42,14 +42,14 @@ class ActivityToolbar(gtk.Toolbar):
|
|||||||
activity.connect('shared', self._activity_shared_cb)
|
activity.connect('shared', self._activity_shared_cb)
|
||||||
activity.connect('joined', self._activity_shared_cb)
|
activity.connect('joined', self._activity_shared_cb)
|
||||||
|
|
||||||
if activity.jobject:
|
if activity.metadata:
|
||||||
self.title = gtk.Entry()
|
self.title = gtk.Entry()
|
||||||
self.title.set_size_request(int(gtk.gdk.screen_width() / 6), -1)
|
self.title.set_size_request(int(gtk.gdk.screen_width() / 6), -1)
|
||||||
self.title.set_text(activity.jobject['title'])
|
self.title.set_text(activity.metadata['title'])
|
||||||
self.title.connect('focus-out-event', self._title_focus_out_event_cb)
|
self.title.connect('focus-out-event', self._title_focus_out_event_cb)
|
||||||
self._add_widget(self.title)
|
self._add_widget(self.title)
|
||||||
|
|
||||||
activity.jobject.connect('updated', self._jobject_updated_cb)
|
activity.metadata.connect('updated', self._jobject_updated_cb)
|
||||||
|
|
||||||
separator = gtk.SeparatorToolItem()
|
separator = gtk.SeparatorToolItem()
|
||||||
separator.props.draw = False
|
separator.props.draw = False
|
||||||
@ -84,8 +84,8 @@ class ActivityToolbar(gtk.Toolbar):
|
|||||||
self.title.set_text(jobject['title'])
|
self.title.set_text(jobject['title'])
|
||||||
|
|
||||||
def _title_focus_out_event_cb(self, entry, event):
|
def _title_focus_out_event_cb(self, entry, event):
|
||||||
if self._activity.jobject['title'] != self.title.get_text():
|
if self._activity.metadata['title'] != self.title.get_text():
|
||||||
self._activity.jobject['title'] = self.title.get_text()
|
self._activity.metadata['title'] = self.title.get_text()
|
||||||
self._activity.save()
|
self._activity.save()
|
||||||
|
|
||||||
def _add_widget(self, widget, expand=False):
|
def _add_widget(self, widget, expand=False):
|
||||||
@ -199,54 +199,62 @@ class Activity(Window, gtk.Container):
|
|||||||
self._bus = ActivityService(self)
|
self._bus = ActivityService(self)
|
||||||
|
|
||||||
if handle.object_id:
|
if handle.object_id:
|
||||||
self.jobject = datastore.get(handle.object_id)
|
self._jobject = datastore.get(handle.object_id)
|
||||||
self.jobject.object_id = ''
|
self._jobject.object_id = ''
|
||||||
del self.jobject['ctime']
|
del self._jobject.metadata['ctime']
|
||||||
del self.jobject['mtime']
|
del self._jobject.metadata['mtime']
|
||||||
elif create_jobject:
|
elif create_jobject:
|
||||||
logging.debug('Creating a jobject.')
|
logging.debug('Creating a jobject.')
|
||||||
self.jobject = datastore.create()
|
self._jobject = datastore.create()
|
||||||
self.jobject['title'] = '%s %s' % (get_bundle_name(), 'Activity')
|
self._jobject.metadata['title'] = '%s %s' % (get_bundle_name(), 'Activity')
|
||||||
self.jobject['activity'] = self.get_service_name()
|
self._jobject.metadata['activity'] = self.get_service_name()
|
||||||
self.jobject['keep'] = '0'
|
self._jobject.metadata['keep'] = '0'
|
||||||
self.jobject['buddies'] = ''
|
self._jobject.metadata['buddies'] = ''
|
||||||
self.jobject['preview'] = ''
|
self._jobject.metadata['preview'] = ''
|
||||||
self.jobject['icon-color'] = profile.get_color().to_string()
|
self._jobject.metadata['icon-color'] = profile.get_color().to_string()
|
||||||
self.jobject.file_path = ''
|
self._jobject.file_path = ''
|
||||||
datastore.write(self.jobject,
|
datastore.write(self._jobject,
|
||||||
reply_handler=self._internal_jobject_create_cb,
|
reply_handler=self._internal_jobject_create_cb,
|
||||||
error_handler=self._internal_jobject_error_cb)
|
error_handler=self._internal_jobject_error_cb)
|
||||||
else:
|
else:
|
||||||
self.jobject = None
|
self._jobject = None
|
||||||
|
|
||||||
def do_set_property(self, pspec, value):
|
def do_set_property(self, pspec, value):
|
||||||
if pspec.name == 'active':
|
if pspec.name == 'active':
|
||||||
if self._active != value:
|
if self._active != value:
|
||||||
self._active = value
|
self._active = value
|
||||||
if not self._active and self.jobject:
|
if not self._active and self._jobject:
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def do_get_property(self, pspec):
|
def do_get_property(self, pspec):
|
||||||
if pspec.name == 'active':
|
if pspec.name == 'active':
|
||||||
return self._active
|
return self._active
|
||||||
|
|
||||||
|
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):
|
def _internal_jobject_create_cb(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _internal_jobject_error_cb(self, err):
|
def _internal_jobject_error_cb(self, err):
|
||||||
logging.debug("Error creating activity datastore object: %s" % err)
|
logging.debug("Error creating activity datastore object: %s" % err)
|
||||||
|
|
||||||
def read_file(self):
|
def read_file(self, file_path):
|
||||||
"""
|
"""
|
||||||
Subclasses implement this method if they support resuming objects from
|
Subclasses implement this method if they support resuming objects from
|
||||||
the journal. Can access the object through the jobject attribute.
|
the journal. 'file_path' is the file to read from.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def write_file(self):
|
def write_file(self, file_path):
|
||||||
"""
|
"""
|
||||||
Subclasses implement this method if they support saving data to objects
|
Subclasses implement this method if they support saving data to objects
|
||||||
in the journal. Can access the object through the jobject attribute.
|
in the journal. 'file_path' is the file to write to.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@ -259,11 +267,12 @@ class Activity(Window, gtk.Container):
|
|||||||
def save(self):
|
def save(self):
|
||||||
"""Request that the activity is saved to the Journal."""
|
"""Request that the activity is saved to the Journal."""
|
||||||
try:
|
try:
|
||||||
self.jobject.file_path = os.path.join('/tmp', '%i.txt' % time.time())
|
file_path = os.path.join('/tmp', '%i' % time.time())
|
||||||
self.write_file()
|
self.write_file(file_path)
|
||||||
|
self._jobject.file_path = file_path
|
||||||
except NotImplementedError:
|
except NotImplementedError:
|
||||||
self.jobject.file_path = ''
|
pass
|
||||||
datastore.write(self.jobject,
|
datastore.write(self._jobject,
|
||||||
reply_handler=self._internal_save_cb,
|
reply_handler=self._internal_save_cb,
|
||||||
error_handler=self._internal_save_error_cb)
|
error_handler=self._internal_save_error_cb)
|
||||||
|
|
||||||
@ -322,7 +331,7 @@ class Activity(Window, gtk.Container):
|
|||||||
self._shared_activity.leave()
|
self._shared_activity.leave()
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
if self.jobject:
|
if self._jobject:
|
||||||
try:
|
try:
|
||||||
self.save()
|
self.save()
|
||||||
except:
|
except:
|
||||||
@ -330,6 +339,14 @@ class Activity(Window, gtk.Container):
|
|||||||
raise
|
raise
|
||||||
self.destroy()
|
self.destroy()
|
||||||
|
|
||||||
|
def get_metadata(self):
|
||||||
|
if self._jobject:
|
||||||
|
return self._jobject.metadata
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
metadata = property(get_metadata, None)
|
||||||
|
|
||||||
def get_bundle_name():
|
def get_bundle_name():
|
||||||
"""Return the bundle name for the current process' bundle
|
"""Return the bundle name for the current process' bundle
|
||||||
"""
|
"""
|
||||||
|
@ -19,38 +19,48 @@ import gobject
|
|||||||
|
|
||||||
from sugar.datastore import dbus_helpers
|
from sugar.datastore import dbus_helpers
|
||||||
|
|
||||||
class DSObject(gobject.GObject):
|
class DSMetadata(gobject.GObject):
|
||||||
__gsignals__ = {
|
__gsignals__ = {
|
||||||
'updated': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
'updated': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||||
([]))
|
([]))
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, object_id, metadata=None, file_path=None):
|
def __init__(self, props={}):
|
||||||
gobject.GObject.__init__(self)
|
gobject.GObject.__init__(self)
|
||||||
|
self._props = props
|
||||||
|
|
||||||
|
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 has_key(self, key):
|
||||||
|
return self._props.has_key(key)
|
||||||
|
|
||||||
|
def get_dictionary(self):
|
||||||
|
return self._props
|
||||||
|
|
||||||
|
class DSObject:
|
||||||
|
def __init__(self, object_id, metadata=None, file_path=None):
|
||||||
self.object_id = object_id
|
self.object_id = object_id
|
||||||
self._metadata = metadata
|
self._metadata = metadata
|
||||||
self._file_path = file_path
|
self._file_path = file_path
|
||||||
|
|
||||||
def __getitem__(self, key):
|
|
||||||
return self.metadata[key]
|
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
|
||||||
if not self.metadata.has_key(key) or self.metadata[key] != value:
|
|
||||||
self.metadata[key] = value
|
|
||||||
self.emit('updated')
|
|
||||||
|
|
||||||
def __delitem__(self, key):
|
|
||||||
del self.metadata[key]
|
|
||||||
|
|
||||||
def get_metadata(self):
|
def get_metadata(self):
|
||||||
if self._metadata is None and not self.object_id is None:
|
if self._metadata is None and not self.object_id is None:
|
||||||
self.set_metadata(dbus_helpers.get_properties(self.object_id))
|
metadata = DSMetadata(dbus_helpers.get_properties(self.object_id))
|
||||||
|
self._metadata = metadata
|
||||||
return self._metadata
|
return self._metadata
|
||||||
|
|
||||||
def set_metadata(self, metadata):
|
def set_metadata(self, metadata):
|
||||||
if self._metadata != metadata:
|
if self._metadata != metadata:
|
||||||
self._metadata = metadata
|
self._metadata = metadata
|
||||||
self.emit('updated')
|
|
||||||
|
|
||||||
metadata = property(get_metadata, set_metadata)
|
metadata = property(get_metadata, set_metadata)
|
||||||
|
|
||||||
@ -62,7 +72,6 @@ class DSObject(gobject.GObject):
|
|||||||
def set_file_path(self, file_path):
|
def set_file_path(self, file_path):
|
||||||
if self._file_path != file_path:
|
if self._file_path != file_path:
|
||||||
self._file_path = file_path
|
self._file_path = file_path
|
||||||
self.emit('updated')
|
|
||||||
|
|
||||||
file_path = property(get_file_path, set_file_path)
|
file_path = property(get_file_path, set_file_path)
|
||||||
|
|
||||||
@ -71,23 +80,23 @@ def get(object_id):
|
|||||||
metadata = dbus_helpers.get_properties(object_id)
|
metadata = dbus_helpers.get_properties(object_id)
|
||||||
file_path = dbus_helpers.get_filename(object_id)
|
file_path = dbus_helpers.get_filename(object_id)
|
||||||
|
|
||||||
ds_object = DSObject(object_id, metadata, file_path)
|
ds_object = DSObject(object_id, DSMetadata(metadata), file_path)
|
||||||
# TODO: register the object for updates
|
# TODO: register the object for updates
|
||||||
return ds_object
|
return ds_object
|
||||||
|
|
||||||
def create():
|
def create():
|
||||||
return DSObject(object_id=None, metadata={}, file_path=None)
|
return DSObject(object_id=None, metadata=DSMetadata(), file_path=None)
|
||||||
|
|
||||||
def write(ds_object, reply_handler=None, error_handler=None):
|
def write(ds_object, reply_handler=None, error_handler=None):
|
||||||
logging.debug('datastore.write')
|
logging.debug('datastore.write')
|
||||||
if ds_object.object_id:
|
if ds_object.object_id:
|
||||||
dbus_helpers.update(ds_object.object_id,
|
dbus_helpers.update(ds_object.object_id,
|
||||||
ds_object.metadata,
|
ds_object.metadata.get_dictionary(),
|
||||||
ds_object.file_path,
|
ds_object.file_path,
|
||||||
reply_handler=reply_handler,
|
reply_handler=reply_handler,
|
||||||
error_handler=error_handler)
|
error_handler=error_handler)
|
||||||
else:
|
else:
|
||||||
ds_object.object_id = dbus_helpers.create(ds_object.metadata,
|
ds_object.object_id = dbus_helpers.create(ds_object.metadata.get_dictionary(),
|
||||||
ds_object.file_path)
|
ds_object.file_path)
|
||||||
# TODO: register the object for updates
|
# TODO: register the object for updates
|
||||||
logging.debug('Written object %s to the datastore.' % ds_object.object_id)
|
logging.debug('Written object %s to the datastore.' % ds_object.object_id)
|
||||||
@ -114,7 +123,7 @@ def find(query, sorting=None, limit=None, offset=None, reply_handler=None,
|
|||||||
object_id = props['uid']
|
object_id = props['uid']
|
||||||
del props['uid']
|
del props['uid']
|
||||||
|
|
||||||
ds_object = DSObject(object_id, props, file_path)
|
ds_object = DSObject(object_id, DSMetadata(props), file_path)
|
||||||
objects.append(ds_object)
|
objects.append(ds_object)
|
||||||
|
|
||||||
return objects, total_count
|
return objects, total_count
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
import gtk
|
import gtk
|
||||||
|
from gtk import gdk, keysyms
|
||||||
import gobject
|
import gobject
|
||||||
import pango
|
import pango
|
||||||
|
|
||||||
@ -49,6 +50,7 @@ class Palette(gtk.Window):
|
|||||||
|
|
||||||
self._palette_label = gtk.Label()
|
self._palette_label = gtk.Label()
|
||||||
self._palette_label.set_ellipsize(pango.ELLIPSIZE_START)
|
self._palette_label.set_ellipsize(pango.ELLIPSIZE_START)
|
||||||
|
self._palette_label.show()
|
||||||
|
|
||||||
self._separator = gtk.HSeparator()
|
self._separator = gtk.HSeparator()
|
||||||
self._separator.hide()
|
self._separator.hide()
|
||||||
@ -58,7 +60,10 @@ class Palette(gtk.Window):
|
|||||||
self._menu_bar.show()
|
self._menu_bar.show()
|
||||||
|
|
||||||
self._content = gtk.HBox()
|
self._content = gtk.HBox()
|
||||||
|
self._content.show()
|
||||||
|
|
||||||
self._button_bar = gtk.HButtonBox()
|
self._button_bar = gtk.HButtonBox()
|
||||||
|
self._button_bar.show()
|
||||||
|
|
||||||
# Set main container
|
# Set main container
|
||||||
vbox = gtk.VBox(False, 0)
|
vbox = gtk.VBox(False, 0)
|
||||||
@ -69,11 +74,25 @@ class Palette(gtk.Window):
|
|||||||
vbox.pack_start(self._button_bar, True, True, self._PADDING)
|
vbox.pack_start(self._button_bar, True, True, self._PADDING)
|
||||||
vbox.show()
|
vbox.show()
|
||||||
|
|
||||||
# FIXME
|
# Widget events
|
||||||
self.connect('focus_out_event', self._close_palette)
|
self.connect('motion-notify-event', self._mouse_over_widget)
|
||||||
|
self.connect('leave-notify-event', self._mouse_out_widget)
|
||||||
|
self.connect('button-press-event', self._close_palette)
|
||||||
|
self.connect('key-press-event', self._on_key_press_event)
|
||||||
|
|
||||||
self.set_border_width(self._WIN_BORDER)
|
self.set_border_width(self._WIN_BORDER)
|
||||||
self.add(vbox)
|
self.add(vbox)
|
||||||
|
|
||||||
|
def _is_mouse_out(self, window, event):
|
||||||
|
# If we're clicking outside of the Palette
|
||||||
|
# return True
|
||||||
|
if (event.window != self.window or
|
||||||
|
(tuple(self.allocation.intersect(
|
||||||
|
gdk.Rectangle(x=int(event.x), y=int(event.y),
|
||||||
|
width=1, height=1)))) == (0, 0, 0, 0)):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
def do_set_property(self, pspec, value):
|
def do_set_property(self, pspec, value):
|
||||||
|
|
||||||
@ -99,7 +118,7 @@ class Palette(gtk.Window):
|
|||||||
elif self._alignment == ALIGNMENT_BOTTOM_RIGHT:
|
elif self._alignment == ALIGNMENT_BOTTOM_RIGHT:
|
||||||
move_x = parent_rectangle.x - palette_width
|
move_x = parent_rectangle.x - palette_width
|
||||||
move_y = window_axis[1] + parent_rectangle.y + parent_rectangle.height
|
move_y = window_axis[1] + parent_rectangle.y + parent_rectangle.height
|
||||||
|
|
||||||
elif self._alignment == ALIGNMENT_LEFT_BOTTOM:
|
elif self._alignment == ALIGNMENT_LEFT_BOTTOM:
|
||||||
move_x = parent_rectangle.x - palette_width
|
move_x = parent_rectangle.x - palette_width
|
||||||
move_y = palette_rectangle.y
|
move_y = palette_rectangle.y
|
||||||
@ -126,8 +145,9 @@ class Palette(gtk.Window):
|
|||||||
|
|
||||||
self.move(move_x, move_y)
|
self.move(move_x, move_y)
|
||||||
|
|
||||||
def _close_palette(self, widget, event):
|
def _close_palette(self, widget=None, event=None):
|
||||||
self.destroy()
|
gtk.gdk.pointer_ungrab()
|
||||||
|
self.hide()
|
||||||
|
|
||||||
def set_primary_state(self, label, accel_path=None):
|
def set_primary_state(self, label, accel_path=None):
|
||||||
if accel_path != None:
|
if accel_path != None:
|
||||||
@ -148,9 +168,42 @@ class Palette(gtk.Window):
|
|||||||
widget.show()
|
widget.show()
|
||||||
|
|
||||||
def append_button(self, button):
|
def append_button(self, button):
|
||||||
|
button.connect('released', self._close_palette)
|
||||||
self._button_bar.pack_start(button, True, True, self._PADDING)
|
self._button_bar.pack_start(button, True, True, self._PADDING)
|
||||||
button.show()
|
button.show()
|
||||||
|
|
||||||
def display(self, button):
|
def display(self, button):
|
||||||
self.show()
|
self.show()
|
||||||
self.set_position()
|
self.set_position()
|
||||||
|
self._pointer_grab()
|
||||||
|
|
||||||
|
def _pointer_grab(self):
|
||||||
|
gtk.gdk.pointer_grab(self.window, owner_events=False,
|
||||||
|
event_mask=gtk.gdk.BUTTON_PRESS_MASK |
|
||||||
|
gtk.gdk.BUTTON_RELEASE_MASK |
|
||||||
|
gtk.gdk.ENTER_NOTIFY_MASK |
|
||||||
|
gtk.gdk.LEAVE_NOTIFY_MASK |
|
||||||
|
gtk.gdk.POINTER_MOTION_MASK)
|
||||||
|
|
||||||
|
gdk.keyboard_grab(self.window, False)
|
||||||
|
|
||||||
|
def _mouse_out_widget(self, widget, event):
|
||||||
|
if (widget == self) and self._is_mouse_out(widget, event):
|
||||||
|
self._pointer_grab()
|
||||||
|
|
||||||
|
def _mouse_over_widget(self, widget, event):
|
||||||
|
gtk.gdk.pointer_ungrab()
|
||||||
|
|
||||||
|
def _on_key_press_event(self, window, event):
|
||||||
|
|
||||||
|
# Escape or Alt+Up: Close
|
||||||
|
# Enter, Return or Space: Select
|
||||||
|
|
||||||
|
keyval = event.keyval
|
||||||
|
state = event.state & gtk.accelerator_get_default_mod_mask()
|
||||||
|
if (keyval == keysyms.Escape or
|
||||||
|
((keyval == keysyms.Up or keyval == keysyms.KP_Up) and
|
||||||
|
state == gdk.MOD1_MASK)):
|
||||||
|
self._close_palette()
|
||||||
|
elif keyval == keysyms.Tab:
|
||||||
|
self._close_palette()
|
||||||
|
@ -36,4 +36,5 @@ class ToolButton(gtk.ToolButton):
|
|||||||
palette.props.alignment = ALIGNMENT_BOTTOM_LEFT
|
palette.props.alignment = ALIGNMENT_BOTTOM_LEFT
|
||||||
|
|
||||||
def set_tooltip(self, text):
|
def set_tooltip(self, text):
|
||||||
pass
|
tp = gtk.Tooltips()
|
||||||
|
self.set_tooltip(tp, text, text)
|
||||||
|
@ -21,6 +21,7 @@ import os
|
|||||||
import logging
|
import logging
|
||||||
import traceback
|
import traceback
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
|
import time
|
||||||
|
|
||||||
from sugar import env
|
from sugar import env
|
||||||
|
|
||||||
@ -113,6 +114,67 @@ def start(module_id):
|
|||||||
sys.excepthook = __exception_handler
|
sys.excepthook = __exception_handler
|
||||||
|
|
||||||
def cleanup():
|
def cleanup():
|
||||||
logs_dir = _get_logs_dir()
|
logs_dir = _get_logs_dir()
|
||||||
for f in os.listdir(logs_dir):
|
|
||||||
os.remove(os.path.join(logs_dir, f))
|
# File extension for backed up logfiles.
|
||||||
|
|
||||||
|
file_suffix = int(time.time())
|
||||||
|
|
||||||
|
# Absolute directory path where to store old logfiles.
|
||||||
|
# It will be created recursivly if it's not present.
|
||||||
|
|
||||||
|
backup_dirpath = os.path.join(logs_dir, 'old')
|
||||||
|
|
||||||
|
# How many versions shall be backed up of every logfile?
|
||||||
|
|
||||||
|
num_backup_versions = 4
|
||||||
|
|
||||||
|
# Make sure the backup location for old log files exists
|
||||||
|
|
||||||
|
if not os.path.exists(backup_dirpath):
|
||||||
|
os.makedirs(backup_dirpath)
|
||||||
|
|
||||||
|
# Iterate over every item in 'logs' directory
|
||||||
|
|
||||||
|
for filename in os.listdir(logs_dir):
|
||||||
|
|
||||||
|
old_filepath = os.path.join(logs_dir, filename)
|
||||||
|
|
||||||
|
if os.path.isfile(old_filepath):
|
||||||
|
|
||||||
|
# Backup every file
|
||||||
|
|
||||||
|
new_filename = filename + '.' + str(file_suffix)
|
||||||
|
new_filepath = os.path.join(backup_dirpath, new_filename)
|
||||||
|
os.rename(old_filepath, new_filepath)
|
||||||
|
|
||||||
|
backup_map = {}
|
||||||
|
|
||||||
|
# Temporarily map all backup logfiles
|
||||||
|
|
||||||
|
for filename in os.listdir(backup_dirpath):
|
||||||
|
|
||||||
|
# Remove the 'file_suffix' from the filename.
|
||||||
|
|
||||||
|
end = filename.rfind(".")
|
||||||
|
key = filename[0:end].lower()
|
||||||
|
key = key.replace(".", "_")
|
||||||
|
|
||||||
|
if key not in backup_map:
|
||||||
|
backup_map[key] = []
|
||||||
|
|
||||||
|
backup_list = backup_map[key]
|
||||||
|
|
||||||
|
backup_list.append( os.path.join(backup_dirpath, filename) )
|
||||||
|
|
||||||
|
# Only keep 'num_backup_versions' versions of every logfile.
|
||||||
|
# Remove the others.
|
||||||
|
|
||||||
|
for key in backup_map:
|
||||||
|
backup_list = backup_map[key]
|
||||||
|
backup_list.sort()
|
||||||
|
backup_list.reverse()
|
||||||
|
|
||||||
|
for i in range(num_backup_versions, len(backup_list)):
|
||||||
|
os.remove(backup_list[i])
|
||||||
|
|
||||||
|
43
sugar/objects/objecttype.py
Normal file
43
sugar/objects/objecttype.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
_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'])
|
||||||
|
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 = []
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
return { 'type_id' : self.type_id,
|
||||||
|
'name' : self.name,
|
||||||
|
'icon' : self.icon
|
||||||
|
}
|
||||||
|
|
||||||
|
class ObjectTypeRegistry(object):
|
||||||
|
def __init__(self):
|
||||||
|
bus = dbus.SessionBus()
|
||||||
|
bus_object = bus.get_object(_SERVICE, _PATH)
|
||||||
|
self._registry = dbus.Interface(bus_object, _IFACE)
|
||||||
|
|
||||||
|
def get_type(type_id):
|
||||||
|
type_dict = self._registry.GetType(type_id)
|
||||||
|
return _object_type_from_dict(type_dict)
|
||||||
|
|
||||||
|
def get_type_for_mime(mime_type):
|
||||||
|
type_dict = self._registry.GetTypeForMime(type_id)
|
||||||
|
return _object_type_from_dict(type_dict)
|
||||||
|
|
||||||
|
_registry = ObjectRegistry()
|
||||||
|
|
||||||
|
def get_registry():
|
||||||
|
return _registry
|
Loading…
Reference in New Issue
Block a user