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
	 Simon McVittie
						Simon McVittie