Use the new DataStore and remove the old one.

This commit is contained in:
Tomeu Vizoso
2007-05-10 11:01:32 +02:00
parent ac4338e3c0
commit 929dabd165
14 changed files with 438 additions and 1032 deletions
+94 -2
View File
@@ -22,6 +22,7 @@ activity must do to participate in the Sugar desktop.
import logging
import os
import time
import gtk, gobject
@@ -30,6 +31,8 @@ from sugar.activity.activityservice import ActivityService
from sugar.graphics.window import Window
from sugar.graphics.toolbox import Toolbox
from sugar.graphics.toolbutton import ToolButton
from sugar.datastore import datastore
from sugar import profile
class ActivityToolbar(gtk.Toolbar):
__gsignals__ = {
@@ -53,6 +56,30 @@ class ActivityToolbar(gtk.Toolbar):
if activity.get_shared():
self.share.set_sensitive(False)
self.share.show()
if activity.jobject:
self.title = gtk.Entry()
self.title.set_text(activity.jobject['title'])
self.title.connect('activate', self._title_activate_cb)
self._add_widget(self.title, expand=True)
activity.jobject.connect('updated', self._jobject_updated_cb)
def _jobject_updated_cb(self, jobject):
self.title.set_text(jobject['title'])
def _title_activate_cb(self, entry):
self._activity.jobject['title'] = self.title.get_text()
self._activity.save()
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.share.set_sensitive(False)
@@ -102,14 +129,18 @@ class Activity(Window, gtk.Container):
'joined': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([]))
}
def __init__(self, handle):
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
@@ -145,6 +176,61 @@ class Activity(Window, gtk.Container):
self._bus = ActivityService(self)
if handle.object_id:
self.jobject = datastore.get(handle.object_id)
elif create_jobject:
logging.debug('Creating a jobject.')
self.jobject = datastore.create()
self.jobject['title'] = 'New entry'
self.jobject['activity'] = self.get_service_name()
self.jobject['date'] = str(time.time())
self.jobject['icon'] = 'theme:object-text'
self.jobject['keep'] = '0'
self.jobject['buddies'] = ''
self.jobject['preview'] = ''
self.jobject['icon-color'] = profile.get_color().to_string()
self.jobject.file_path = '/tmp/teste'
f = open(self.jobject.file_path, 'w')
f.write('mec')
f.close()
datastore.write(self.jobject)
else:
self.jobject = None
self.connect('realize', self._realize_cb)
def _realize_cb(self, activity):
try:
self.read_file()
except NotImplementedError:
logging.debug('read_file() not implemented.')
pass
def read_file(self):
"""
Subclasses implement this method if they support resuming objects from
the journal. Can access the object through the jobject attribute.
"""
raise NotImplementedError
def write_file(self):
"""
Subclasses implement this method if they support saving data to objects
in the journal. Can access the object through the jobject attribute.
Must return the file path the data was saved to.
"""
raise NotImplementedError
def save(self):
"""Request that the activity is saved to the Journal."""
try:
file_path = self.write_file()
self.jobject.file_path = file_path
except NotImplementedError:
pass
datastore.write(self.jobject)
def _internal_joined_cb(self, activity, success, err):
"""Callback when join has finished"""
self._shared_activity.disconnect(self._join_id)
@@ -200,6 +286,12 @@ class Activity(Window, gtk.Container):
self._shared_activity.leave()
def _handle_close_cb(self, toolbar):
if self.jobject:
try:
self.save()
except:
self.destroy()
raise
self.destroy()
def _handle_share_cb(self, toolbar):
+3 -2
View File
@@ -1,4 +1,5 @@
sugardir = $(pythondir)/sugar/datastore
sugar_PYTHON = \
__init__.py \
sugar_PYTHON = \
__init__.py \
dbus_helpers.py \
datastore.py
+38 -272
View File
@@ -1,4 +1,4 @@
# Copyright (C) 2006, Red Hat, Inc.
# Copyright (C) 2007, One Laptop Per Child
#
# 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
@@ -15,289 +15,55 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 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"
_bus = dbus.SessionBus()
_data_store = dbus.Interface(_bus.get_object(DS_DBUS_SERVICE, DS_DBUS_PATH),
DS_DBUS_INTERFACE)
class DataStoreObject:
def __init__(self, metadata, file_path=None, handle=None):
self._metadata = metadata
self._file_path = file_path
self._handle = handle
def get_metadata(self):
return self._metadata
def get_file_path(self):
return self._file_path
def set_file_path(self, file_path):
self._file_path = file_path
def get_handle(self):
return self._handle
def get_object_type(self):
raise NotImplementedError()
class Text(DataStoreObject):
def get_object_type(self):
return 'text'
class Picture(DataStoreObject):
def get_object_type(self):
return 'picture'
class Link(DataStoreObject):
def get_object_type(self):
return 'link'
class WebSession(DataStoreObject):
def get_object_type(self):
return 'web_session'
def _read_from_object_path(object_path):
dbus_object = _bus.get_object(DS_DBUS_SERVICE, object_path)
metadata = dbus_object.get_properties(dbus.Dictionary({}, signature='sv'))
object_type = metadata['object-type']
file_path = metadata['file-path']
handle = metadata['handle']
del metadata['object-type']
del metadata['file-path']
del metadata['handle']
if object_type == 'text':
return Text(metadata, file_path, handle)
elif object_type == 'picture':
return Picture(metadata, file_path, handle)
elif object_type == 'link':
return Link(metadata, file_path, handle)
elif object_type == 'web_session':
return WebSession(metadata, file_path, handle)
else:
raise NotImplementedError('Unknown object type.')
def read(handle):
object_path = _data_store.get(handle)
return _read_from_object_path(object_path)
def write(obj):
metadata = obj.get_metadata().copy()
metadata['file-path'] = obj.get_file_path()
metadata['object-type'] = obj.get_object_type()
if obj.get_handle():
_data_store.update(int(obj.get_handle()), dbus.Dictionary(metadata))
return obj.get_handle()
else:
object_path = _data_store.create(dbus.Dictionary(metadata))
dbus_object = _bus.get_object(DS_DBUS_SERVICE, object_path)
return dbus_object.get_properties(['handle'])['handle']
def find(query):
object_paths = _data_store.find(query)
objects = []
for object_path in object_paths:
objects.append(_read_from_object_path(object_path))
return objects
def delete(handle):
pass
################################################################################
class ObjectCache(object):
def __init__(self):
self._cache = {}
def get(self, object_path):
try:
return self._cache[object_path]
except KeyError:
return None
def add(self, obj):
op = obj.object_path()
if not self._cache.has_key(op):
self._cache[op] = obj
def remove(self, object_path):
try:
del self._cache[object_path]
except IndexError:
pass
from sugar.datastore import dbus_helpers
class DSObject(gobject.GObject):
__gsignals__ = {
'updated': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT]))
([gobject.TYPE_PYOBJECT]))
}
_DS_OBJECT_DBUS_INTERFACE = "org.laptop.sugar.DataStore.Object"
def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
def __init__(self, object_id, metadata, file_path):
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(DS_DBUS_SERVICE, object_path)
self._dsobj = dbus.Interface(bobj, self._DS_OBJECT_DBUS_INTERFACE)
self._dsobj.connect_to_signal('Updated', self._updated_cb)
self._data = None
self._data_needs_update = True
self._properties = None
self._deleted = False
self.object_id = object_id
self.metadata = metadata
self.file_path = file_path
def object_path(self):
return self._object_path
def __getitem__(self, key):
return self.metadata[key]
def uid(self):
if not self._properties:
self._properties = self._dsobj.get_properties([])
return self._properties['uid']
def __setitem__(self, key, value):
self.metadata[key] = value
def _emit_updated_signal(self, data, prop_dict, deleted):
self.emit('updated', data, prop_dict, deleted)
return False
def get(object_id):
logging.debug('datastore.get')
metadata = dbus_helpers.get_properties(object_id)
file_path = dbus_helpers.get_filename(object_id)
logging.debug('filepath: ' + file_path)
ds_object = DSObject(object_id, metadata, file_path)
# TODO: register the object for updates
return ds_object
def _update_internal_properties(self, prop_dict):
did_update = False
for (key, value) in prop_dict.items():
if not len(value):
if self._properties.has_key(ley):
did_update = True
del self._properties[key]
else:
if self._properties.has_key(key):
if self._properties[key] != value:
did_update = True
self._properties[key] = value
else:
did_update = True
self._properties[key] = value
return did_update
def create():
return DSObject(object_id=None, metadata={}, file_path=None)
def _updated_cb(self, data=False, prop_dict={}, deleted=False):
if self._update_internal_properties(prop_dict):
gobject.idle_add(self._emit_updated_signal, data, prop_dict, deleted)
self._deleted = deleted
def write(ds_object):
logging.debug('datastore.write')
if ds_object.object_id:
dbus_helpers.update(ds_object.object_id,
ds_object.metadata,
ds_object.file_path)
else:
ds_object.object_id = dbus_helpers.create(ds_object.metadata,
ds_object.file_path)
# TODO: register the object for updates
logging.debug('Written object %s to the datastore.' % ds_object.object_id)
def get_data(self):
if self._data_needs_update:
data = self._dsobj.get_data()
self._data = ""
for c in data:
self._data += chr(c)
return self._data
def set_data(self, data):
old_data = self._data
self._data = data
try:
self._dsobj.set_data(dbus.ByteArray(data))
del old_data
except dbus.DBusException, e:
self._data = old_data
raise e
def set_properties(self, prop_dict):
old_props = self._properties
self._update_internal_properties(prop_dict)
try:
self._dsobj.set_properties(prop_dict)
del old_props
except dbus.DBusException, e:
self._properties = old_props
raise e
def get_properties(self, prop_list=[]):
if not self._properties:
self._properties = self._dsobj.get_properties(prop_list)
return self._properties
class DataStore(gobject.GObject):
_DS_DBUS_OBJECT_PATH = DS_DBUS_PATH + "/Object/"
def __init__(self):
gobject.GObject.__init__(self)
self._objcache = ObjectCache()
self._bus = dbus.SessionBus()
self._ds = dbus.Interface(self._bus.get_object(DS_DBUS_SERVICE,
DS_DBUS_PATH), DS_DBUS_INTERFACE)
def _new_object(self, object_path):
obj = self._objcache.get(object_path)
if obj:
return obj
if object_path.startswith(self._DS_DBUS_OBJECT_PATH):
obj = DSObject(self._bus, self._new_object,
self._del_object, object_path)
else:
raise RuntimeError("Unknown object type")
self._objcache.add(obj)
return obj
def _del_object(self, object_path):
# FIXME
pass
def get(self, uid=None, activity_id=None):
if not activity_id and not uid:
raise ValueError("At least one of activity_id or uid must be specified")
if activity_id and uid:
raise ValueError("Only one of activity_id or uid can be specified")
if activity_id:
if not util.validate_activity_id(activity_id):
raise ValueError("activity_id must be valid")
return self._new_object(self._ds.getActivityObject(activity_id))
elif uid:
if not len(uid):
raise ValueError("uid must be valid")
return self._new_object(self._ds.get(int(uid)))
raise RuntimeError("At least one of activity_id or uid must be specified")
def create(self, data, prop_dict={}, activity_id=None):
if activity_id and not util.validate_activity_id(activity_id):
raise ValueError("activity_id must be valid")
if not activity_id:
activity_id = ""
op = self._ds.create(dbus.ByteArray(data), dbus.Dictionary(prop_dict), activity_id)
return self._new_object(op)
def delete(self, obj):
op = obj.object_path()
obj = self._objcache.get(op)
if not obj:
raise RuntimeError("Object not found.")
self._ds.delete(op)
def find(self, prop_dict):
ops = self._ds.find(dbus.Dictionary(prop_dict))
objs = []
for op in ops:
objs.append(self._new_object(op))
return objs
_ds = None
def get_instance():
global _ds
if not _ds:
_ds = DataStore()
return _ds
def find(query):
object_ids = dbus_helpers.find({})
objects = []
for object_id in object_ids:
objects.append(get(object_id))
return objects
+302
View File
@@ -0,0 +1,302 @@
# Copyright (C) 2006, Red Hat, Inc.
# Copyright (C) 2007, One Laptop Per Child
#
# 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 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"
_bus = dbus.SessionBus()
_data_store = dbus.Interface(_bus.get_object(DS_DBUS_SERVICE, DS_DBUS_PATH),
DS_DBUS_INTERFACE)
def create(properties, filename):
logging.debug('dbus_helpers.create: %s, %s' % (properties, filename))
object_id = _data_store.create(dbus.Dictionary(properties), filename)
logging.debug('dbus_helpers.create: ' + object_id)
return object_id
def update(uid, properties, filename):
_data_store.update(uid, dbus.Dictionary(properties), filename)
def get_properties(uid):
return _data_store.get_properties(uid)
def get_filename(uid):
return _data_store.get_filename(uid)
def find(query):
return _data_store.find(query)
"""
class DataStoreObject(gobject.GObject):
__gsignals__ = {
'updated': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT]))
}
def __init__(self, metadata, file_path=None, handle=None):
self._metadata = metadata
self.file_path = file_path
self.handle = handle
def __getitem__(self, key):
return self._metadata[key]
def __setitem__(self, key, value):
self._metadata[key] = value
def get_metadata(self):
return self._metadata
def _read_from_object_path(object_path):
dbus_object = _bus.get_object(DS_DBUS_SERVICE, object_path)
metadata = dbus_object.get_properties(dbus.Dictionary({}, signature='sv'))
object_type = metadata['object-type']
file_path = metadata['file-path']
handle = metadata['handle']
del metadata['object-type']
del metadata['file-path']
del metadata['handle']
return DataStoreObject(metadata, file_path, handle)
def create():
return DataStoreObject({})
def read(handle):
object_path = _data_store.get(handle)
return _read_from_object_path(object_path)
def write(obj):
if obj.handle:
_data_store.update(int(obj.handle),
dbus.Dictionary(obj.get_metadata().copy()),
obj.get_file_path())
else:
object_path = _data_store.create(dbus.Dictionary(metadata),
obj.get_file_path())
dbus_object = _bus.get_object(DS_DBUS_SERVICE, object_path)
obj.handle = dbus_object.get_properties(['handle'])['handle']
def find(query):
object_paths = _data_store.find(query)
objects = []
for object_path in object_paths:
objects.append(_read_from_object_path(object_path))
return objects
def delete(handle):
pass
################################################################################
class ObjectCache(object):
def __init__(self):
self._cache = {}
def get(self, object_path):
try:
return self._cache[object_path]
except KeyError:
return None
def add(self, obj):
op = obj.object_path()
if not self._cache.has_key(op):
self._cache[op] = obj
def remove(self, object_path):
try:
del self._cache[object_path]
except IndexError:
pass
class DSObject(gobject.GObject):
__gsignals__ = {
'updated': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT]))
}
_DS_OBJECT_DBUS_INTERFACE = "org.laptop.sugar.DataStore.Object"
def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
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(DS_DBUS_SERVICE, object_path)
self._dsobj = dbus.Interface(bobj, self._DS_OBJECT_DBUS_INTERFACE)
self._dsobj.connect_to_signal('Updated', self._updated_cb)
self._data = None
self._data_needs_update = True
self._properties = None
self._deleted = False
def object_path(self):
return self._object_path
def uid(self):
if not self._properties:
self._properties = self._dsobj.get_properties([])
return self._properties['uid']
def _emit_updated_signal(self, data, prop_dict, deleted):
self.emit('updated', data, prop_dict, deleted)
return False
def _update_internal_properties(self, prop_dict):
did_update = False
for (key, value) in prop_dict.items():
if not len(value):
if self._properties.has_key(ley):
did_update = True
del self._properties[key]
else:
if self._properties.has_key(key):
if self._properties[key] != value:
did_update = True
self._properties[key] = value
else:
did_update = True
self._properties[key] = value
return did_update
def _updated_cb(self, data=False, prop_dict={}, deleted=False):
if self._update_internal_properties(prop_dict):
gobject.idle_add(self._emit_updated_signal, data, prop_dict, deleted)
self._deleted = deleted
def get_data(self):
if self._data_needs_update:
data = self._dsobj.get_data()
self._data = ""
for c in data:
self._data += chr(c)
return self._data
def set_data(self, data):
old_data = self._data
self._data = data
try:
self._dsobj.set_data(dbus.ByteArray(data))
del old_data
except dbus.DBusException, e:
self._data = old_data
raise e
def set_properties(self, prop_dict):
old_props = self._properties
self._update_internal_properties(prop_dict)
try:
self._dsobj.set_properties(prop_dict)
del old_props
except dbus.DBusException, e:
self._properties = old_props
raise e
def get_properties(self, prop_list=[]):
if not self._properties:
self._properties = self._dsobj.get_properties(prop_list)
return self._properties
class DataStore(gobject.GObject):
_DS_DBUS_OBJECT_PATH = DS_DBUS_PATH + "/Object/"
def __init__(self):
gobject.GObject.__init__(self)
self._objcache = ObjectCache()
self._bus = dbus.SessionBus()
self._ds = dbus.Interface(self._bus.get_object(DS_DBUS_SERVICE,
DS_DBUS_PATH), DS_DBUS_INTERFACE)
def _new_object(self, object_path):
obj = self._objcache.get(object_path)
if obj:
return obj
if object_path.startswith(self._DS_DBUS_OBJECT_PATH):
obj = DSObject(self._bus, self._new_object,
self._del_object, object_path)
else:
raise RuntimeError("Unknown object type")
self._objcache.add(obj)
return obj
def _del_object(self, object_path):
# FIXME
pass
def get(self, uid=None, activity_id=None):
if not activity_id and not uid:
raise ValueError("At least one of activity_id or uid must be specified")
if activity_id and uid:
raise ValueError("Only one of activity_id or uid can be specified")
if activity_id:
if not util.validate_activity_id(activity_id):
raise ValueError("activity_id must be valid")
return self._new_object(self._ds.getActivityObject(activity_id))
elif uid:
if not len(uid):
raise ValueError("uid must be valid")
return self._new_object(self._ds.get(int(uid)))
raise RuntimeError("At least one of activity_id or uid must be specified")
def create(self, data, prop_dict={}, activity_id=None):
if activity_id and not util.validate_activity_id(activity_id):
raise ValueError("activity_id must be valid")
if not activity_id:
activity_id = ""
op = self._ds.create(dbus.ByteArray(data), dbus.Dictionary(prop_dict), activity_id)
return self._new_object(op)
def delete(self, obj):
op = obj.object_path()
obj = self._objcache.get(op)
if not obj:
raise RuntimeError("Object not found.")
self._ds.delete(op)
def find(self, prop_dict):
ops = self._ds.find(dbus.Dictionary(prop_dict))
objs = []
for op in ops:
objs.append(self._new_object(op))
return objs
_ds = None
def get_instance():
global _ds
if not _ds:
_ds = DataStore()
return _ds
"""
-2
View File
@@ -55,13 +55,11 @@ class ComboBox(gtk.ComboBox):
def append_item(self, action_id, text, icon_name=None):
if not self._icon_renderer and icon_name:
logging.debug('Adding icon renderer.')
self._icon_renderer = gtk.CellRendererPixbuf()
self.pack_start(self._icon_renderer, False)
self.add_attribute(self._icon_renderer, 'icon-name', 2)
if not self._text_renderer and text:
logging.debug('Adding text renderer.')
self._text_renderer = gtk.CellRendererText()
self.pack_end(self._text_renderer, True)
self.add_attribute(self._text_renderer, 'text', 1)