Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMarco Pesenti Gritti <mpgritti@gmail.com>2008-10-06 13:23:40 (GMT)
committer Marco Pesenti Gritti <mpgritti@gmail.com>2008-10-06 13:23:40 (GMT)
commit4ce3decec07caa1016bcdfa03252150e4335ad77 (patch)
tree74037a0ccf1fcec4a1ad17cc160e8dc823a2e9c6 /src
parentae5b5a424e6e6523139dc2813cc4f915dfde6ea0 (diff)
Move the bundle registry inside the shell process.
Diffstat (limited to 'src')
-rw-r--r--src/jarabe/desktop/activitieslist.py63
-rw-r--r--src/jarabe/desktop/favoriteslayout.py4
-rw-r--r--src/jarabe/desktop/favoritesview.py53
-rw-r--r--src/jarabe/desktop/friendview.py8
-rw-r--r--src/jarabe/desktop/homebox.py15
-rw-r--r--src/jarabe/frame/activitiestray.py26
-rw-r--r--src/jarabe/frame/clipboardmenu.py12
-rw-r--r--src/jarabe/journal/journalactivity.py7
-rw-r--r--src/jarabe/journal/journaltoolbox.py25
-rw-r--r--src/jarabe/journal/misc.py22
-rw-r--r--src/jarabe/journal/palettes.py7
-rw-r--r--src/jarabe/model/Makefile.am1
-rw-r--r--src/jarabe/model/bundleregistry.py347
-rw-r--r--src/jarabe/model/neighborhood.py5
-rw-r--r--src/jarabe/model/shell.py8
-rw-r--r--src/jarabe/view/palettes.py36
16 files changed, 502 insertions, 137 deletions
diff --git a/src/jarabe/desktop/activitieslist.py b/src/jarabe/desktop/activitieslist.py
index 072a295..1cedda7 100644
--- a/src/jarabe/desktop/activitieslist.py
+++ b/src/jarabe/desktop/activitieslist.py
@@ -19,12 +19,12 @@ import gtk
import hippo
from sugar import profile
-from sugar import activity
from sugar import util
from sugar.graphics import style
from sugar.graphics.icon import CanvasIcon
from sugar.activity import activityfactory
+from jarabe.model import bundleregistry
from jarabe.view.palettes import ActivityPalette
class ActivitiesList(gtk.VBox):
@@ -56,28 +56,20 @@ class ActivitiesList(gtk.VBox):
self._box.props.background_color = style.COLOR_WHITE.get_int()
canvas.set_root(self._box)
- registry = activity.get_registry()
- registry.get_activities_async(reply_handler=self._get_activities_cb)
- registry.connect('activity-added', self.__activity_added_cb)
- registry.connect('activity-removed', self.__activity_removed_cb)
-
- def _get_activities_cb(self, activity_list):
- if activity_list:
- gobject.idle_add(self._add_activity_list, activity_list)
-
- def _add_activity_list(self, activity_list):
- info = activity_list.pop()
- if info.bundle_id != 'org.laptop.JournalActivity':
+ registry = bundleregistry.get_registry()
+ for info in registry:
self._add_activity(info)
- return len(activity_list) > 0
+
+ registry.connect('bundle-added', self.__activity_added_cb)
+ registry.connect('bundle-removed', self.__activity_removed_cb)
def __activity_added_cb(self, activity_registry, activity_info):
self._add_activity(activity_info)
def __activity_removed_cb(self, activity_registry, activity_info):
for entry in self._box.get_children():
- if entry.get_bundle_id() == activity_info.bundle_id and \
- entry.get_version() == activity_info.version:
+ if entry.get_bundle_id() == activity_info.get_bundle_id() and \
+ entry.get_version() == activity_info.get_activity_version():
self._box.remove(entry)
return
@@ -137,7 +129,7 @@ class ActivityIcon(CanvasIcon):
def __init__(self, activity_info):
CanvasIcon.__init__(self, size=style.STANDARD_ICON_SIZE, cache=True,
- file_name=activity_info.icon)
+ file_name=activity_info.get_icon())
self._activity_info = activity_info
self._uncolor()
self.connect('hovering-changed', self.__hovering_changed_event_cb)
@@ -149,7 +141,7 @@ class ActivityIcon(CanvasIcon):
return palette
def __erase_activated_cb(self, palette):
- self.emit('erase-activated', self._activity_info.bundle_id)
+ self.emit('erase-activated', self._activity_info.get_bundle_id())
def _color(self):
self.props.xo_color = profile.get_color()
@@ -185,14 +177,15 @@ class ActivityEntry(hippo.CanvasBox, hippo.CanvasItem):
box_height=style.GRID_CELL_SIZE,
orientation=hippo.ORIENTATION_HORIZONTAL)
- registry = activity.get_registry()
- registry.connect('activity-changed', self.__activity_changed_cb)
+ registry = bundleregistry.get_registry()
+ registry.connect('bundle-changed', self.__activity_changed_cb)
- self._bundle_id = activity_info.bundle_id
- self._version = activity_info.version
- self._favorite = activity_info.favorite
- self._title = activity_info.name
- self._installation_time = activity_info.installation_time
+ self._bundle_id = activity_info.get_bundle_id()
+ self._version = activity_info.get_activity_version()
+ self._favorite = registry.is_bundle_favorite(self._bundle_id,
+ self._version)
+ self._title = activity_info.get_name()
+ self._installation_time = activity_info.get_installation_time()
self._favorite_icon = FavoriteIcon(self._favorite)
self._favorite_icon.connect('notify::favorite',
@@ -209,13 +202,13 @@ class ActivityEntry(hippo.CanvasBox, hippo.CanvasItem):
else:
align = hippo.ALIGNMENT_START
- title = hippo.CanvasText(text=activity_info.name,
+ title = hippo.CanvasText(text=activity_info.get_name(),
xalign=align,
font_desc=style.FONT_BOLD.get_pango_desc(),
box_width=ActivityEntry._TITLE_COL_WIDTH)
self.append(title)
- version = hippo.CanvasText(text=activity_info.version,
+ version = hippo.CanvasText(text=activity_info.get_activity_version(),
xalign=hippo.ALIGNMENT_END,
font_desc=style.FONT_NORMAL.get_pango_desc(),
box_width=ActivityEntry._VERSION_COL_WIDTH)
@@ -224,7 +217,7 @@ class ActivityEntry(hippo.CanvasBox, hippo.CanvasItem):
expander = hippo.CanvasBox()
self.append(expander, hippo.PACK_EXPAND)
- timestamp = activity_info.installation_time
+ timestamp = activity_info.get_installation_time()
date = hippo.CanvasText(
text=util.timestamp_to_elapsed_string(timestamp),
xalign=align,
@@ -236,15 +229,19 @@ class ActivityEntry(hippo.CanvasBox, hippo.CanvasItem):
self.reverse()
def __favorite_changed_cb(self, favorite_icon, pspec):
- registry = activity.get_registry()
+ registry = bundleregistry.get_registry()
registry.set_activity_favorite(self._bundle_id, self._version,
favorite_icon.props.favorite)
def __activity_changed_cb(self, activity_registry, activity_info):
- if self._bundle_id == activity_info.bundle_id and \
- self._version == activity_info.version:
- self._title = activity_info.name
- self._favorite = activity_info.favorite
+ if self._bundle_id == activity_info.get_bundle_id() and \
+ self._version == activity_info.get_activity_version():
+ self._title = activity_info.get_name()
+
+ registry = bundleregistry.get_registry()
+ self._favorite = registry.is_bundle_favorite(self._bundle_id,
+ self._version)
+
self._favorite_icon.props.favorite = self._favorite
def __icon_button_release_event_cb(self, icon, event):
diff --git a/src/jarabe/desktop/favoriteslayout.py b/src/jarabe/desktop/favoriteslayout.py
index fe69e01..9438e56 100644
--- a/src/jarabe/desktop/favoriteslayout.py
+++ b/src/jarabe/desktop/favoriteslayout.py
@@ -24,8 +24,8 @@ import gtk
import hippo
from sugar.graphics import style
-from sugar import activity
+from jarabe.model import bundleregistry
from jarabe.desktop.grid import Grid
_logger = logging.getLogger('FavoritesLayout')
@@ -78,7 +78,7 @@ class FavoritesLayout(gobject.GObject, hippo.CanvasLayout):
if hasattr(icon, 'get_bundle_id') and hasattr(icon, 'get_version'):
min_width_, width = self.box.get_width_request()
min_height_, height = self.box.get_height_request(width)
- registry = activity.get_registry()
+ registry = bundleregistry.get_registry()
registry.set_activity_position(
icon.get_bundle_id(), icon.get_version(),
x * width / float(_BASE_SCALE),
diff --git a/src/jarabe/desktop/favoritesview.py b/src/jarabe/desktop/favoritesview.py
index f4a6c70..3bf4964 100644
--- a/src/jarabe/desktop/favoritesview.py
+++ b/src/jarabe/desktop/favoritesview.py
@@ -28,12 +28,12 @@ from sugar.graphics.icon import Icon, CanvasIcon
from sugar.graphics.menuitem import MenuItem
from sugar.graphics.alert import Alert
from sugar.profile import get_profile
-from sugar import activity
from sugar.activity import activityfactory
from jarabe.view.palettes import JournalPalette
from jarabe.view.palettes import CurrentActivityPalette, ActivityPalette
from jarabe.model import shell
+from jarabe.model import bundleregistry
from jarabe.controlpanel.gui import ControlPanel
from jarabe.service.session import get_session_manager
@@ -87,10 +87,10 @@ class FavoritesView(hippo.Canvas):
self._layout = None
self._alert = None
- registry = activity.get_registry()
- registry.connect('activity-added', self.__activity_added_cb)
- registry.connect('activity-removed', self.__activity_removed_cb)
- registry.connect('activity-changed', self.__activity_changed_cb)
+ registry = bundleregistry.get_registry()
+ registry.connect('bundle-added', self.__activity_added_cb)
+ registry.connect('bundle-removed', self.__activity_removed_cb)
+ registry.connect('bundle-changed', self.__activity_changed_cb)
# More DND stuff
self.add_events(gtk.gdk.BUTTON_PRESS_MASK |
@@ -111,14 +111,9 @@ class FavoritesView(hippo.Canvas):
def __erase_activated_cb(self, activity_icon, bundle_id):
self.emit('erase-activated', bundle_id)
- def _get_activities_cb(self, activity_list):
- for info in activity_list:
- if info.favorite and info.bundle_id != "org.laptop.JournalActivity":
- self._add_activity(info)
-
def __activity_added_cb(self, activity_registry, activity_info):
- if activity_info.favorite and \
- activity_info.bundle_id != "org.laptop.JournalActivity":
+ registry = bundleregistry.get_registry()
+ if registry.is_bundle_favorite(self._bundle_id, self._version):
self._add_activity(activity_info)
def _find_activity_icon(self, bundle_id, version):
@@ -129,19 +124,21 @@ class FavoritesView(hippo.Canvas):
return None
def __activity_removed_cb(self, activity_registry, activity_info):
- icon = self._find_activity_icon(activity_info.bundle_id,
- activity_info.version)
+ icon = self._find_activity_icon(activity_info.get_bundle_id(),
+ activity_info.get_activity_version())
if icon is not None:
self._layout.remove(icon)
def __activity_changed_cb(self, activity_registry, activity_info):
- if activity_info.bundle_id == 'org.laptop.JournalActivity':
+ if activity_info.get_bundle_id() == 'org.laptop.JournalActivity':
return
- icon = self._find_activity_icon(activity_info.bundle_id,
- activity_info.version)
+ icon = self._find_activity_icon(activity_info.get_bundle_id(),
+ activity_info.get_activity_version())
if icon is not None:
self._box.remove(icon)
- if activity_info.favorite:
+
+ registry = bundleregistry.get_registry()
+ if registry.is_bundle_favorite(self._bundle_id, self._version):
self._add_activity(activity_info)
def do_size_allocate(self, allocation):
@@ -265,8 +262,12 @@ class FavoritesView(hippo.Canvas):
self._current_activity = CurrentActivityIcon()
self._layout.append(self._current_activity, locked=True)
- registry = activity.get_registry()
- registry.get_activities_async(reply_handler=self._get_activities_cb)
+ registry = bundleregistry.get_registry()
+ for info in registry:
+ if registry.is_bundle_favorite(info.get_bundle_id(),
+ info.get_activity_version()):
+ self._add_activity(info)
+
if self._layout.allow_dnd():
self.drag_source_set(0, [], 0)
@@ -320,7 +321,9 @@ class ActivityIcon(CanvasIcon):
}
def __init__(self, activity_info):
- CanvasIcon.__init__(self, cache=True, file_name=activity_info.icon)
+ CanvasIcon.__init__(self, cache=True,
+ file_name=activity_info.get_icon())
+
self._activity_info = activity_info
self._uncolor()
self.connect('hovering-changed', self.__hovering_changed_event_cb)
@@ -332,7 +335,7 @@ class ActivityIcon(CanvasIcon):
return palette
def __erase_activated_cb(self, palette):
- self.emit('erase-activated', self._activity_info.bundle_id)
+ self.emit('erase-activated', self._activity_info.get_bundle_id())
def _color(self):
self.props.xo_color = get_profile().color
@@ -351,14 +354,14 @@ class ActivityIcon(CanvasIcon):
self.palette.popdown(immediate=True)
self._uncolor()
- activityfactory.create(self._activity_info.bundle_id)
+ activityfactory.create(self._activity_info.get_bundle_id())
def get_bundle_id(self):
- return self._activity_info.bundle_id
+ return self._activity_info.get_bundle_id()
bundle_id = property(get_bundle_id, None)
def get_version(self):
- return self._activity_info.version
+ return self._activity_info.get_activity_version()
version = property(get_version, None)
def _get_installation_time(self):
diff --git a/src/jarabe/desktop/friendview.py b/src/jarabe/desktop/friendview.py
index a4add98..4c5f1c8 100644
--- a/src/jarabe/desktop/friendview.py
+++ b/src/jarabe/desktop/friendview.py
@@ -19,9 +19,9 @@ import hippo
from sugar.graphics.icon import CanvasIcon
from sugar.graphics import style
from sugar.presence import presenceservice
-from sugar import activity
from jarabe.view.buddyicon import BuddyIcon
+from jarabe.model import bundleregistry
class FriendView(hippo.CanvasBox):
def __init__(self, buddy, **kwargs):
@@ -47,10 +47,10 @@ class FriendView(hippo.CanvasBox):
self._buddy.connect('color-changed', self._buddy_color_changed_cb)
def _get_new_icon_name(self, ps_activity):
- registry = activity.get_registry()
- activity_info = registry.get_activity(ps_activity.props.type)
+ registry = bundleregistry.get_registry()
+ activity_info = registry.get_bundle(ps_activity.props.type)
if activity_info:
- return activity_info.icon
+ return activity_info.get_icon()
return None
def _remove_activity_icon(self):
diff --git a/src/jarabe/desktop/homebox.py b/src/jarabe/desktop/homebox.py
index a02b465..337555d 100644
--- a/src/jarabe/desktop/homebox.py
+++ b/src/jarabe/desktop/homebox.py
@@ -27,9 +27,8 @@ from sugar.graphics.radiotoolbutton import RadioToolButton
from sugar.graphics.alert import Alert
from sugar.graphics.icon import Icon
from sugar import profile
-from sugar import activity
-from sugar.bundle.activitybundle import ActivityBundle
+from jarabe.model import bundleregistry
from jarabe.desktop import favoritesview
from jarabe.desktop.activitieslist import ActivitiesList
@@ -71,14 +70,14 @@ class HomeBox(gtk.VBox):
self._set_view(_FAVORITES_VIEW, layout)
def __erase_activated_cb(self, view, bundle_id):
- registry = activity.get_registry()
- activity_info = registry.get_activity(bundle_id)
+ registry = bundleregistry.get_registry()
+ activity_info = registry.get_bundle(bundle_id)
alert = Alert()
alert.props.title = _('Confirm erase')
alert.props.msg = \
_('Confirm erase: Do you want to permanently erase %s?') \
- % activity_info.name
+ % activity_info.get_name()
cancel_icon = Icon(icon_name='dialog-cancel')
alert.add_button(gtk.RESPONSE_CANCEL, _('Keep'), cancel_icon)
@@ -104,9 +103,9 @@ class HomeBox(gtk.VBox):
else:
self._favorites_view.remove_alert()
if response_id == gtk.RESPONSE_OK:
- registry = activity.get_registry()
- activity_info = registry.get_activity(bundle_id)
- ActivityBundle(activity_info.path).uninstall()
+ registry = bundleregistry.get_registry()
+ bundle = registry.get_bundle(bundle_id)
+ registry.uninstall(bundle)
def show_software_updates_alert(self):
alert = Alert()
diff --git a/src/jarabe/frame/activitiestray.py b/src/jarabe/frame/activitiestray.py
index f786654..dfeeced 100644
--- a/src/jarabe/frame/activitiestray.py
+++ b/src/jarabe/frame/activitiestray.py
@@ -29,12 +29,12 @@ from sugar.graphics.palette import Palette, WidgetInvoker
from sugar.graphics.menuitem import MenuItem
from sugar.activity.activityhandle import ActivityHandle
from sugar.activity import activityfactory
-from sugar import activity
from sugar import profile
from jarabe.model import shell
from jarabe.model import neighborhood
from jarabe.model import owner
+from jarabe.model import bundleregistry
from jarabe.view.palettes import JournalPalette, CurrentActivityPalette
from jarabe.view.pulsingicon import PulsingIcon
from jarabe.frame.frameinvoker import FrameWidgetInvoker
@@ -162,10 +162,10 @@ class PrivateInviteButton(BaseInviteButton):
self._bundle_id = invite.get_bundle_id()
self._icon.props.xo_color = profile.get_color()
- registry = activity.get_registry()
- activity_info = registry.get_activity(self._bundle_id)
+ registry = bundleregistry.get_registry()
+ activity_info = registry.get_bundle(self._bundle_id)
if activity_info:
- self._icon.props.file = activity_info.icon
+ self._icon.props.file = activity_info.get_icon()
else:
self._icon.props.icon_name = 'image-missing'
self.set_icon_widget(self._icon)
@@ -177,10 +177,10 @@ class PrivateInviteButton(BaseInviteButton):
self.set_palette(palette)
self._notif_icon.props.xo_color = profile.get_color()
- registry = activity.get_registry()
- activity_info = registry.get_activity(self._bundle_id)
+ registry = bundleregistry.get_registry()
+ activity_info = registry.get_bundle(self._bundle_id)
if activity_info:
- self._notif_icon.props.icon_filename = activity_info.icon
+ self._notif_icon.props.icon_filename = activity_info.get_icon()
else:
self._notif_icon.props.icon_name = 'image-missing'
@@ -236,10 +236,10 @@ class ActivityInvitePalette(BaseInvitePalette):
self._activity_model = activity_model
self._bundle_id = activity_model.get_bundle_id()
- registry = activity.get_registry()
- activity_info = registry.get_activity(self._bundle_id)
+ registry = bundleregistry.get_registry()
+ activity_info = registry.get_bundle(self._bundle_id)
if activity_info:
- self.set_primary_text(activity_info.name)
+ self.set_primary_text(activity_info.get_name())
else:
self.set_primary_text(self._bundle_id)
@@ -262,10 +262,10 @@ class PrivateInvitePalette(BaseInvitePalette):
self._private_channel = invite.get_private_channel()
self._bundle_id = invite.get_bundle_id()
- registry = activity.get_registry()
- activity_info = registry.get_activity(self._bundle_id)
+ registry = bundleregistry.get_registry()
+ activity_info = registry.get_bundle(self._bundle_id)
if activity_info:
- self.set_primary_text(activity_info.name)
+ self.set_primary_text(activity_info.get_name())
else:
self.set_primary_text(self._bundle_id)
diff --git a/src/jarabe/frame/clipboardmenu.py b/src/jarabe/frame/clipboardmenu.py
index 8461094..2bff201 100644
--- a/src/jarabe/frame/clipboardmenu.py
+++ b/src/jarabe/frame/clipboardmenu.py
@@ -28,10 +28,10 @@ from sugar.graphics.icon import Icon
from sugar.datastore import datastore
from sugar import mime
from sugar import profile
-from sugar import activity
from jarabe.frame import clipboard
from jarabe.journal import misc
+from jarabe.model import bundleregistry
class ClipboardMenu(Palette):
@@ -91,13 +91,13 @@ class ClipboardMenu(Palette):
submenu.remove(item)
for service_name in activities:
- registry = activity.get_registry()
- activity_info = registry.get_activity(service_name)
+ registry = bundleregistry.get_registry()
+ activity_info = registry.get_bundle(service_name)
if not activity_info:
logging.warning('Activity %s is unknown.' % service_name)
- item = gtk.MenuItem(activity_info.name)
+ item = gtk.MenuItem(activity_info.get_name())
item.connect('activate', self._open_submenu_item_activate_cb,
service_name)
submenu.append(item)
@@ -128,10 +128,10 @@ class ClipboardMenu(Palette):
if not mime_type:
return ''
- registry = activity.get_registry()
+ registry = bundleregistry.get_registry()
activities = registry.get_activities_for_type(mime_type)
if activities:
- return [activity_info.bundle_id for activity_info in activities]
+ return [activity_info.get_bundle_id() for activity_info in activities]
else:
return ''
diff --git a/src/jarabe/journal/journalactivity.py b/src/jarabe/journal/journalactivity.py
index 51f0c61..1f63696 100644
--- a/src/jarabe/journal/journalactivity.py
+++ b/src/jarabe/journal/journalactivity.py
@@ -33,6 +33,7 @@ from sugar import env
from sugar.activity import activityfactory
from sugar import wm
+from jarabe.model import bundleregistry
from jarabe.journal.journaltoolbox import MainToolbox, DetailToolbox
from jarabe.journal.listview import ListView
from jarabe.journal.detailview import DetailView
@@ -278,14 +279,16 @@ class JournalActivity(Window):
self._list_view.update_dates()
def _check_for_bundle(self, jobject):
+ registry = bundleregistry.get_registry()
+
bundle = misc.get_bundle(jobject)
if bundle is None:
return
- if bundle.is_installed():
+ if registry.is_installed(bundle):
return
try:
- bundle.install()
+ registry.install(bundle)
except (ZipExtractException, RegistrationException), e:
logging.warning('Could not install bundle %s: %r' %
(jobject.file_path, e))
diff --git a/src/jarabe/journal/journaltoolbox.py b/src/jarabe/journal/journaltoolbox.py
index 8d52a06..8124afd 100644
--- a/src/jarabe/journal/journaltoolbox.py
+++ b/src/jarabe/journal/journaltoolbox.py
@@ -35,6 +35,7 @@ from sugar import profile
from sugar import mime
from sugar.datastore import datastore
+from jarabe.model import bundleregistry
from jarabe.journal import volumesmanager
from jarabe.journal import misc
@@ -254,22 +255,22 @@ class SearchToolbar(gtk.Toolbar):
# TRANS: Item in a combo box that filters by entry type.
self._what_search_combo.append_item(_ACTION_ANYTHING, _('Anything'))
- registry = activity.get_registry()
+ registry = bundleregistry.get_registry()
appended_separator = False
for service_name in datastore.get_unique_values('activity'):
- activity_info = registry.get_activity(service_name)
+ activity_info = registry.get_bundle(service_name)
if not activity_info is None:
if not appended_separator:
self._what_search_combo.append_separator()
appended_separator = True
- if os.path.exists(activity_info.icon):
+ if os.path.exists(activity_info.get_icon()):
self._what_search_combo.append_item(service_name,
- activity_info.name,
- file_name=activity_info.icon)
+ activity_info.get_name(),
+ file_name=activity_info.get_icon())
else:
self._what_search_combo.append_item(service_name,
- activity_info.name,
+ activity_info.get_name(),
icon_name='application-octet-stream')
if service_name == current_value:
@@ -359,10 +360,12 @@ class EntryToolbar(gtk.Toolbar):
pass
def _erase_button_clicked_cb(self, button):
+ registry = bundleregistry.get_registry()
+
if self._jobject:
bundle = misc.get_bundle(self._jobject)
- if bundle is not None and bundle.is_installed():
- bundle.uninstall()
+ if bundle is not None and registry.is_installed(bundle):
+ registry.uninstall(bundle)
datastore.delete(self._jobject.object_id)
def _resume_menu_item_activate_cb(self, menu_item, service_name):
@@ -408,11 +411,11 @@ class EntryToolbar(gtk.Toolbar):
menu_item.destroy()
for activity_info in misc.get_activities(self._jobject):
- menu_item = MenuItem(activity_info.name)
- menu_item.set_image(Icon(file=activity_info.icon,
+ menu_item = MenuItem(activity_info.get_name())
+ menu_item.set_image(Icon(file=activity_info.get_icon(),
icon_size=gtk.ICON_SIZE_MENU))
menu_item.connect('activate', self._resume_menu_item_activate_cb,
- activity_info.bundle_id)
+ activity_info.get_bundle_id())
palette.menu.append(menu_item)
menu_item.show()
diff --git a/src/jarabe/journal/misc.py b/src/jarabe/journal/misc.py
index 42d179b..3fa8bd7 100644
--- a/src/jarabe/journal/misc.py
+++ b/src/jarabe/journal/misc.py
@@ -23,7 +23,6 @@ from gettext import gettext as _
import gtk
-from sugar import activity
from sugar.activity import activityfactory
from sugar.activity.activityhandle import ActivityHandle
from sugar import mime
@@ -32,6 +31,7 @@ from sugar.bundle.contentbundle import ContentBundle
from sugar.bundle.bundle import MalformedBundleException
from sugar import util
+from jarabe.model import bundleregistry
from jarabe.journal.journalentrybundle import JournalEntryBundle
def _get_icon_file_name(icon_name):
@@ -66,9 +66,9 @@ def get_icon_name(jobject):
if not file_name and jobject.metadata['activity']:
service_name = jobject.metadata['activity']
- activity_info = activity.get_registry().get_activity(service_name)
+ activity_info = bundleregistry.get_registry().get_bundle(service_name)
if activity_info:
- file_name = activity_info.icon
+ file_name = activity_info.get_icon()
mime_type = jobject.metadata['mime_type']
if not file_name and mime_type:
@@ -110,7 +110,7 @@ def get_bundle(jobject):
return None
def _get_activities_for_mime(mime_type):
- registry = activity.get_registry()
+ registry = bundleregistry.get_registry()
result = registry.get_activities_for_type(mime_type)
if not result:
for parent_mime in mime.get_mime_parents(mime_type):
@@ -122,7 +122,7 @@ def get_activities(jobject):
bundle_id = jobject.metadata.get('activity', '')
if bundle_id:
- activity_info = activity.get_registry().get_activity(bundle_id)
+ activity_info = bundleregistry.get_registry().get_bundle(bundle_id)
if activity_info:
activities.append(activity_info)
@@ -130,22 +130,24 @@ def get_activities(jobject):
if mime_type:
activities_info = _get_activities_for_mime(mime_type)
for activity_info in activities_info:
- if activity_info.bundle_id != bundle_id:
+ if activity_info.get_bundle_id() != bundle_id:
activities.append(activity_info)
return activities
def resume(jobject, bundle_id=None):
+ registry = bundleregistry.get_registry()
+
if jobject.is_activity_bundle() and not bundle_id:
logging.debug('Creating activity bundle')
bundle = ActivityBundle(jobject.file_path)
- if not bundle.is_installed():
+ if not registry.is_installed(bundle):
logging.debug('Installing activity bundle')
- bundle.install()
- elif bundle.need_upgrade():
+ registry.install(bundle)
+ else:
logging.debug('Upgrading activity bundle')
- bundle.upgrade()
+ registry.upgrade(bundle)
logging.debug('activityfactory.creating bundle with id %r',
bundle.get_bundle_id())
diff --git a/src/jarabe/journal/palettes.py b/src/jarabe/journal/palettes.py
index dfed3b9..501e4fb 100644
--- a/src/jarabe/journal/palettes.py
+++ b/src/jarabe/journal/palettes.py
@@ -27,6 +27,7 @@ from sugar.graphics.icon import Icon
from sugar.datastore import datastore
from sugar.graphics.xocolor import XoColor
+from jarabe.model import bundleregistry
from jarabe.journal import misc
class ObjectPalette(Palette):
@@ -94,9 +95,11 @@ class ObjectPalette(Palette):
pass
def __erase_activate_cb(self, menu_item):
+ registry = bundleregistry.get_registry()
+
bundle = misc.get_bundle(self._jobject)
- if bundle is not None and bundle.is_installed():
- bundle.uninstall()
+ if bundle is not None and registry.is_installed(bundle):
+ registry.uninstall(bundle)
datastore.delete(self._jobject.object_id)
diff --git a/src/jarabe/model/Makefile.am b/src/jarabe/model/Makefile.am
index ad5b3ff..d480f0f 100644
--- a/src/jarabe/model/Makefile.am
+++ b/src/jarabe/model/Makefile.am
@@ -3,6 +3,7 @@ sugar_PYTHON = \
__init__.py \
accesspoint.py \
buddy.py \
+ bundleregistry.py \
friends.py \
invites.py \
owner.py \
diff --git a/src/jarabe/model/bundleregistry.py b/src/jarabe/model/bundleregistry.py
new file mode 100644
index 0000000..5be1cf0
--- /dev/null
+++ b/src/jarabe/model/bundleregistry.py
@@ -0,0 +1,347 @@
+# Copyright (C) 2006-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 os
+import logging
+import traceback
+
+import gobject
+import simplejson
+
+from sugar.bundle.activitybundle import ActivityBundle
+from sugar.bundle.bundle import MalformedBundleException, \
+ AlreadyInstalledException, RegistrationException
+from sugar import env
+
+from jarabe import config
+
+class BundleRegistry(gobject.GObject):
+ """Service that tracks the available activity bundles"""
+
+ __gsignals__ = {
+ 'bundle-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'bundle-removed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'bundle-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT]))
+ }
+
+ def __init__(self):
+ gobject.GObject.__init__(self)
+
+ self._mime_defaults = self._load_mime_defaults()
+
+ self._bundles = []
+ for activity_dir in self._get_activity_directories():
+ self._scan_directory(activity_dir)
+
+ self._last_defaults_mtime = -1
+ self._favorite_bundles = {}
+
+ try:
+ self._load_favorites()
+ except Exception:
+ logging.error('Error while loading favorite_activities\n%s.' \
+ % traceback.format_exc())
+
+ self._merge_default_favorites()
+
+ def _get_activity_directories(self):
+ directories = []
+ if os.environ.has_key('SUGAR_ACTIVITIES'):
+ directories.extend(os.environ['SUGAR_ACTIVITIES'].split(':'))
+
+ directories.append(env.get_user_activities_path())
+
+ return directories
+
+ def _load_mime_defaults(self):
+ defaults = {}
+
+ f = open(os.path.join(config.data_path, 'mime.defaults'), 'r')
+ for line in f.readlines():
+ line = line.strip()
+ if line and not line.startswith('#'):
+ mime = line[:line.find(' ')]
+ handler = line[line.rfind(' ') + 1:]
+ defaults[mime] = handler
+ f.close()
+
+ return defaults
+
+ def _get_favorite_key(self, bundle_id, version):
+ """We use a string as a composite key for the favorites dictionary
+ because JSON doesn't support tuples and python won't accept a list
+ as a dictionary key.
+ """
+ if ' ' in bundle_id:
+ raise ValueError('bundle_id cannot contain spaces')
+ return '%s %s' % (bundle_id, version)
+
+ def _load_favorites(self):
+ favorites_path = env.get_profile_path('favorite_activities')
+ if os.path.exists(favorites_path):
+ favorites_data = simplejson.load(open(favorites_path))
+
+ favorite_bundles = favorites_data['favorites']
+ if not isinstance(favorite_bundles, dict):
+ raise ValueError('Invalid format in %s.' % favorites_path)
+ if favorite_bundles:
+ first_key = favorite_bundles.keys()[0]
+ if not isinstance(first_key, basestring):
+ raise ValueError('Invalid format in %s.' % favorites_path)
+
+ first_value = favorite_bundles.values()[0]
+ if first_value is not None and \
+ not isinstance(first_value, dict):
+ raise ValueError('Invalid format in %s.' % favorites_path)
+
+ self._last_defaults_mtime = float(favorites_data['defaults-mtime'])
+ self._favorite_bundles = favorite_bundles
+
+ def _merge_default_favorites(self):
+ default_activities = []
+ defaults_path = os.path.join(config.data_path, 'activities.defaults')
+ if os.path.exists(defaults_path):
+ file_mtime = os.stat(defaults_path).st_mtime
+ if file_mtime > self._last_defaults_mtime:
+ f = open(defaults_path, 'r')
+ for line in f.readlines():
+ line = line.strip()
+ if line and not line.startswith('#'):
+ default_activities.append(line)
+ f.close()
+ self._last_defaults_mtime = file_mtime
+
+ if not default_activities:
+ return
+
+ for bundle_id in default_activities:
+ max_version = -1
+ for bundle in self._bundles:
+ if bundle.get_bundle_id() == bundle_id and \
+ max_version < bundle.get_activity_version():
+ max_version = bundle.get_activity_version()
+
+ key = self._get_favorite_key(bundle_id, max_version)
+ if max_version > -1 and key not in self._favorite_bundles:
+ self._favorite_bundles[key] = None
+
+ logging.debug('After merging: %r' % self._favorite_bundles)
+
+ self._write_favorites_file()
+
+ def get_bundle(self, bundle_id):
+ """Returns an bundle given his service name"""
+ for bundle in self._bundles:
+ if bundle.get_bundle_id() == bundle_id:
+ return bundle
+ return None
+
+ def __iter__(self):
+ return self._bundles.__iter__()
+
+ def _scan_directory(self, path):
+ if not os.path.isdir(path):
+ return
+
+ # Sort by mtime to ensure a stable activity order
+ bundles = {}
+ for f in os.listdir(path):
+ if not f.endswith('.activity'):
+ continue
+ try:
+ bundle_dir = os.path.join(path, f)
+ if os.path.isdir(bundle_dir):
+ bundles[bundle_dir] = os.stat(bundle_dir).st_mtime
+ except Exception, e:
+ logging.error('Error while processing installed activity ' \
+ 'bundle: %s, %s, %s' % (f, e.__class__, e))
+
+ bundle_dirs = bundles.keys()
+ bundle_dirs.sort(lambda d1, d2: cmp(bundles[d1], bundles[d2]))
+ for folder in bundle_dirs:
+ try:
+ self._add_bundle(folder)
+ except Exception, e:
+ logging.error('Error while processing installed activity ' \
+ 'bundle: %s, %s, %s' % (folder, e.__class__, e))
+
+ def add_bundle(self, bundle_path):
+ bundle = self._add_bundle(bundle_path)
+ if bundle is not None:
+ self._set_bundle_favorite(bundle.get_bundle_id(),
+ bundle.get_activity_version(),
+ True)
+ self.emit('bundle-added', bundle)
+ return True
+ else:
+ return False
+
+ def _add_bundle(self, bundle_path):
+ try:
+ bundle = ActivityBundle(bundle_path)
+ except MalformedBundleException:
+ return None
+
+ self._bundles.append(bundle)
+ return bundle
+
+ def remove_bundle(self, bundle_path):
+ for bundle in self._bundles:
+ if bundle.get_path() == bundle_path:
+ self._bundles.remove(bundle)
+ self.emit('bundle-removed', bundle)
+ return True
+ return False
+
+ def get_activities_for_type(self, mime_type):
+ result = []
+ for bundle in self._bundles:
+ if bundle.get_mime_types() and mime_type in bundle.get_mime_types():
+ if self.get_default_for_type(mime_type) == \
+ bundle.get_bundle_id():
+ result.insert(0, bundle)
+ else:
+ result.append(bundle)
+ return result
+
+ def get_default_for_type(self, mime_type):
+ if self._mime_defaults.has_key(mime_type):
+ return self._mime_defaults[mime_type]
+ else:
+ return None
+
+ def _find_bundle(self, bundle_id, version):
+ for bundle in self._bundles:
+ if bundle.get_bundle_id() == bundle_id and \
+ bundle.get_activity_version() == version:
+ return bundle
+ raise ValueError('No bundle %r with version %r exists.' % \
+ (bundle_id, version))
+
+ def set_bundle_favorite(self, bundle_id, version, favorite):
+ changed = self._set_bundle_favorite(bundle_id, version, favorite)
+ if changed:
+ bundle = self._find_bundle(bundle_id, version)
+ self.emit('bundle-changed', bundle)
+
+ def _set_bundle_favorite(self, bundle_id, version, favorite):
+ key = self._get_favorite_key(bundle_id, version)
+ if favorite and not key in self._favorite_bundles:
+ self._favorite_bundles[key] = None
+ elif not favorite and key in self._favorite_bundles:
+ del self._favorite_bundles[key]
+ else:
+ return False
+
+ self._write_favorites_file()
+ return True
+
+ def is_bundle_favorite(self, bundle_id, version):
+ key = self._get_favorite_key(bundle_id, version)
+ return key in self._favorite_bundles
+
+ def set_bundle_position(self, bundle_id, version, x, y):
+ key = self._get_favorite_key(bundle_id, version)
+ if key not in self._favorite_bundles:
+ raise ValueError('Bundle %s %s not favorite' % (bundle_id, version))
+
+ if self._favorite_bundles[key] is None:
+ self._favorite_bundles[key] = {}
+ if 'position' not in self._favorite_bundles[key] or \
+ [x, y] != self._favorite_bundles[key]['position']:
+ self._favorite_bundles[key]['position'] = [x, y]
+ else:
+ return
+
+ self._write_favorites_file()
+ bundle = self._find_bundle(bundle_id, version)
+ self.emit('bundle-changed', bundle)
+
+ def get_bundle_position(self, bundle_id, version):
+ """Get the coordinates where the user wants the representation of this
+ bundle to be displayed. Coordinates are relative to a 1000x1000 area.
+ """
+ key = self._get_favorite_key(bundle_id, version)
+ if key not in self._favorite_bundles or \
+ self._favorite_bundles[key] is None or \
+ 'position' not in self._favorite_bundles[key]:
+ return (-1, -1)
+ else:
+ return tuple(self._favorite_bundles[key]['position'])
+
+ def _write_favorites_file(self):
+ path = env.get_profile_path('favorite_activities')
+ favorites_data = {'defaults-mtime': self._last_defaults_mtime,
+ 'favorites': self._favorite_bundles}
+ simplejson.dump(favorites_data, open(path, 'w'), indent=1)
+
+ def is_installed(self, bundle):
+ return self.get_activity(bundle.get_bundle_id()) is not None
+
+ def install(self, bundle):
+ activities_path = env.get_user_activities_path()
+ if self.is_installed(bundle):
+ raise AlreadyInstalledException
+
+ install_dir = env.get_user_activities_path()
+ install_path = bundle.install(install_dir)
+
+ if not self.add_bundle(install_path):
+ raise RegistrationException
+
+ def uninstall(self, bundle, force=False):
+ act = self.get_activity(bundle.get_bundle_id())
+ if not force and act.version != bundle.get_activity_version():
+ logging.warning('Not uninstalling, different bundle present')
+ return
+ elif not act.path.startswith(env.get_user_activities_path()):
+ logging.warning('Not uninstalling system activity')
+ return
+
+ install_path = act.path
+
+ bundle.uninstall(install_path, force)
+
+ if not self.remove_bundle(install_path):
+ raise RegistrationException
+
+ def upgrade(self, bundle):
+ act = self.get_activity(bundle.get_bundle_id())
+ if act is None:
+ logging.warning('Activity not installed')
+ elif act.path.startswith(env.get_user_activities_path()):
+ try:
+ self.uninstall(bundle, force=True)
+ except Exception, e:
+ logging.warning('Uninstall failed (%s), still trying ' \
+ 'to install newer bundle', e)
+ else:
+ logging.warning('Unable to uninstall system activity, ' \
+ 'installing upgraded version in user activities')
+
+ self.install(bundle)
+
+_instance = None
+
+def get_registry():
+ global _instance
+ if not _instance:
+ _instance = BundleRegistry()
+ return _instance
+
diff --git a/src/jarabe/model/neighborhood.py b/src/jarabe/model/neighborhood.py
index 9d27823..726c388 100644
--- a/src/jarabe/model/neighborhood.py
+++ b/src/jarabe/model/neighborhood.py
@@ -22,6 +22,7 @@ from sugar import activity
from jarabe.model.buddy import BuddyModel
from jarabe.model.accesspoint import AccessPointModel
+from jarabe.model import bundleregistry
from jarabe.model import network
class ActivityModel:
@@ -200,8 +201,8 @@ class Neighborhood(gobject.GObject):
self._check_activity(act)
def _check_activity(self, presence_activity):
- registry = activity.get_registry()
- bundle = registry.get_activity(presence_activity.props.type)
+ registry = bundleregistry.get_registry()
+ bundle = registry.get_bundle(presence_activity.props.type)
if not bundle:
return
if self.has_activity(presence_activity.props.id):
diff --git a/src/jarabe/model/shell.py b/src/jarabe/model/shell.py
index adc9d4c..334cff8 100644
--- a/src/jarabe/model/shell.py
+++ b/src/jarabe/model/shell.py
@@ -25,11 +25,11 @@ import gtk
import dbus
from sugar import wm
-from sugar.activity import get_registry
from sugar.graphics.xocolor import XoColor
from sugar.presence import presenceservice
from sugar import profile
+from jarabe.model.bundleregistry import get_registry
from jarabe import config
_SERVICE_NAME = "org.laptop.Activity"
@@ -125,7 +125,7 @@ class Activity(gobject.GObject):
if self.is_journal():
return os.path.join(config.data_path, 'icons/activity-journal.svg')
elif self._activity_info:
- return self._activity_info.icon
+ return self._activity_info.get_icon()
else:
return None
@@ -424,7 +424,7 @@ class ShellModel(gobject.GObject):
service_name = wm.get_bundle_id(window)
if service_name:
registry = get_registry()
- activity_info = registry.get_activity(service_name)
+ activity_info = registry.get_bundle(service_name)
else:
activity_info = None
@@ -502,7 +502,7 @@ class ShellModel(gobject.GObject):
def notify_launch(self, activity_id, service_name):
registry = get_registry()
- activity_info = registry.get_activity(service_name)
+ activity_info = registry.get_bundle(service_name)
if not activity_info:
raise ValueError("Activity service name '%s'" \
" was not found in the bundle registry."
diff --git a/src/jarabe/view/palettes.py b/src/jarabe/view/palettes.py
index a4df092..2a0bc86 100644
--- a/src/jarabe/view/palettes.py
+++ b/src/jarabe/view/palettes.py
@@ -23,7 +23,6 @@ import gtk
from sugar import env
from sugar import profile
-from sugar import activity
from sugar.graphics.palette import Palette
from sugar.graphics.menuitem import MenuItem
from sugar.graphics.icon import Icon
@@ -31,6 +30,8 @@ from sugar.graphics import style
from sugar.graphics.xocolor import XoColor
from sugar.activity import activityfactory
+from jarabe.model import bundleregistry
+
class BasePalette(Palette):
def __init__(self, home_activity):
Palette.__init__(self)
@@ -89,16 +90,19 @@ class ActivityPalette(Palette):
}
def __init__(self, activity_info):
- activity_icon = Icon(file=activity_info.icon,
+ activity_icon = Icon(file=activity_info.get_icon(),
xo_color=profile.get_color(),
icon_size=gtk.ICON_SIZE_LARGE_TOOLBAR)
- Palette.__init__(self, primary_text=activity_info.name,
+ Palette.__init__(self, primary_text=activity_info.get_name(),
icon=activity_icon)
- self._bundle_id = activity_info.bundle_id
- self._version = activity_info.version
- self._favorite = activity_info.favorite
+ registry = bundleregistry.get_registry()
+
+ self._bundle_id = activity_info.get_bundle_id()
+ self._version = activity_info.get_activity_version()
+ self._favorite = registry.is_bundle_favorite(self._bundle_id,
+ self._version)
menu_item = MenuItem(_('Start'), 'activity-start')
menu_item.connect('activate', self.__start_activate_cb)
@@ -121,8 +125,8 @@ class ActivityPalette(Palette):
self.menu.append(menu_item)
menu_item.show()
- registry = activity.get_registry()
- self._activity_changed_sid = registry.connect('activity_changed',
+ registry = bundleregistry.get_registry()
+ self._activity_changed_sid = registry.connect('bundle_changed',
self.__activity_changed_cb)
self._update_favorite_item()
@@ -147,15 +151,17 @@ class ActivityPalette(Palette):
activityfactory.create(self._bundle_id)
def __change_favorite_activate_cb(self, menu_item):
- registry = activity.get_registry()
- registry.set_activity_favorite(self._bundle_id,
- self._version,
- not self._favorite)
+ registry = bundleregistry.get_registry()
+ registry.set_bundle_favorite(self._bundle_id,
+ self._version,
+ not self._favorite)
def __activity_changed_cb(self, activity_registry, activity_info):
- if activity_info.bundle_id == self._bundle_id and \
- activity_info.version == self._version:
- self._favorite = activity_info.favorite
+ if activity_info.get_bundle_id() == self._bundle_id and \
+ activity_info.get_activity_version() == self._version:
+ registry = bundleregistry.get_registry()
+ self._favorite = registry.is_bundle_favorite(self._bundle_id,
+ self._version)
self._update_favorite_item()
def __erase_activate_cb(self, menu_item):