diff options
author | Marco 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) |
commit | 4ce3decec07caa1016bcdfa03252150e4335ad77 (patch) | |
tree | 74037a0ccf1fcec4a1ad17cc160e8dc823a2e9c6 /src | |
parent | ae5b5a424e6e6523139dc2813cc4f915dfde6ea0 (diff) |
Move the bundle registry inside the shell process.
Diffstat (limited to 'src')
-rw-r--r-- | src/jarabe/desktop/activitieslist.py | 63 | ||||
-rw-r--r-- | src/jarabe/desktop/favoriteslayout.py | 4 | ||||
-rw-r--r-- | src/jarabe/desktop/favoritesview.py | 53 | ||||
-rw-r--r-- | src/jarabe/desktop/friendview.py | 8 | ||||
-rw-r--r-- | src/jarabe/desktop/homebox.py | 15 | ||||
-rw-r--r-- | src/jarabe/frame/activitiestray.py | 26 | ||||
-rw-r--r-- | src/jarabe/frame/clipboardmenu.py | 12 | ||||
-rw-r--r-- | src/jarabe/journal/journalactivity.py | 7 | ||||
-rw-r--r-- | src/jarabe/journal/journaltoolbox.py | 25 | ||||
-rw-r--r-- | src/jarabe/journal/misc.py | 22 | ||||
-rw-r--r-- | src/jarabe/journal/palettes.py | 7 | ||||
-rw-r--r-- | src/jarabe/model/Makefile.am | 1 | ||||
-rw-r--r-- | src/jarabe/model/bundleregistry.py | 347 | ||||
-rw-r--r-- | src/jarabe/model/neighborhood.py | 5 | ||||
-rw-r--r-- | src/jarabe/model/shell.py | 8 | ||||
-rw-r--r-- | src/jarabe/view/palettes.py | 36 |
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): |