Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Francis <francis@sugarlabs.org>2012-11-29 18:37:12 (GMT)
committer Daniel Francis <francis@sugarlabs.org>2012-11-29 18:37:12 (GMT)
commit376e117543ee6d793474ec8735ba592ce188881d (patch)
tree75f7fb36edbb2b6c2b41473285f8f2110d9a46d5
parent42100d16e5e0a436942ee46e26f407ac144e0ac4 (diff)
Multiple home views
Signed-off-by: Daniel Francis <francis@sugarlabs.org>
-rw-r--r--src/jarabe/desktop/activitieslist.py67
-rw-r--r--src/jarabe/desktop/favoritesview.py55
-rw-r--r--src/jarabe/desktop/homebox.py29
-rw-r--r--src/jarabe/desktop/viewtoolbar.py68
-rw-r--r--src/jarabe/model/bundleregistry.py86
5 files changed, 274 insertions, 31 deletions
diff --git a/src/jarabe/desktop/activitieslist.py b/src/jarabe/desktop/activitieslist.py
index 6594ee9..da8bb65 100644
--- a/src/jarabe/desktop/activitieslist.py
+++ b/src/jarabe/desktop/activitieslist.py
@@ -1,5 +1,6 @@
# Copyright (C) 2008 One Laptop Per Child
# Copyright (C) 2009 Tomeu Vizoso
+# Copyright (C) 2012 Daniel Francis
#
# 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
@@ -66,9 +67,14 @@ class ActivitiesTreeView(Gtk.TreeView):
cell_favorite = CellRendererFavorite(self)
cell_favorite.connect('clicked', self.__favorite_clicked_cb)
+ cell_school = CellRendererSchool(self)
+ cell_school.connect('clicked', self.__school_clicked_cb)
+
column = Gtk.TreeViewColumn()
column.pack_start(cell_favorite, True)
+ column.pack_start(cell_school, True)
column.set_cell_data_func(cell_favorite, self.__favorite_set_data_cb)
+ column.set_cell_data_func(cell_school, self.__school_set_data_cb)
self.append_column(column)
cell_icon = CellRendererActivityIcon(self)
@@ -135,6 +141,15 @@ class ActivitiesTreeView(Gtk.TreeView):
else:
cell.props.xo_color = None
+ def __school_set_data_cb(self, column, cell, model, tree_iter, data):
+ school = model[tree_iter][ListModel.COLUMN_SCHOOL]
+ if school:
+ client = GConf.Client.get_default()
+ color = XoColor(client.get_string('/desktop/sugar/user/color'))
+ cell.props.xo_color = color
+ else:
+ cell.props.xo_color = None
+
def __favorite_clicked_cb(self, cell, path):
row = self.get_model()[path]
registry = bundleregistry.get_registry()
@@ -142,6 +157,13 @@ class ActivitiesTreeView(Gtk.TreeView):
row[ListModel.COLUMN_VERSION],
not row[ListModel.COLUMN_FAVORITE])
+ def __school_clicked_cb(self, cell, path):
+ row = self.get_model()[path]
+ registry = bundleregistry.get_registry()
+ registry.set_bundle_for_school(row[ListModel.COLUMN_BUNDLE_ID],
+ row[ListModel.COLUMN_VERSION],
+ not row[ListModel.COLUMN_SCHOOL])
+
def __icon_clicked_cb(self, cell, path):
row = self.get_model()[path]
@@ -171,15 +193,16 @@ class ListModel(Gtk.TreeModelSort):
COLUMN_BUNDLE_ID = 0
COLUMN_FAVORITE = 1
- COLUMN_ICON = 2
- COLUMN_TITLE = 3
- COLUMN_VERSION = 4
- COLUMN_VERSION_TEXT = 5
- COLUMN_DATE = 6
- COLUMN_DATE_TEXT = 7
+ COLUMN_SCHOOL = 2
+ COLUMN_ICON = 3
+ COLUMN_TITLE = 4
+ COLUMN_VERSION = 5
+ COLUMN_VERSION_TEXT = 6
+ COLUMN_DATE = 7
+ COLUMN_DATE_TEXT = 8
def __init__(self):
- self._model = Gtk.ListStore(str, bool, str, str, str, str, int, str)
+ self._model = Gtk.ListStore(str, bool, bool, str, str, str, str, int, str)
self._model_filter = self._model.filter_new()
Gtk.TreeModelSort.__init__(self, model=self._model_filter)
self.set_sort_column_id(ListModel.COLUMN_TITLE, Gtk.SortType.ASCENDING)
@@ -201,10 +224,12 @@ class ListModel(Gtk.TreeModelSort):
bundle_id = activity_info.get_bundle_id()
version = activity_info.get_activity_version()
favorite = activity_registry.is_bundle_favorite(bundle_id, version)
+ school = activity_registry.is_bundle_for_school(bundle_id, version)
for row in self._model:
if row[ListModel.COLUMN_BUNDLE_ID] == bundle_id and \
row[ListModel.COLUMN_VERSION] == version:
row[ListModel.COLUMN_FAVORITE] = favorite
+ row[ListModel.COLUMN_SCHOOL] = school
return
def __activity_removed_cb(self, activity_registry, activity_info):
@@ -226,7 +251,8 @@ class ListModel(Gtk.TreeModelSort):
registry = bundleregistry.get_registry()
favorite = registry.is_bundle_favorite(activity_info.get_bundle_id(),
version)
-
+ school = registry.is_bundle_for_school(activity_info.get_bundle_id(),
+ version)
tag_list = activity_info.get_tags()
if tag_list is None or not tag_list:
title = '<b>%s</b>' % activity_info.get_name()
@@ -238,6 +264,7 @@ class ListModel(Gtk.TreeModelSort):
self._model.append([activity_info.get_bundle_id(),
favorite,
+ school,
activity_info.get_icon(),
title,
version,
@@ -269,6 +296,23 @@ class CellRendererFavorite(CellRendererIcon):
self.props.prelit_fill_color = prelit_color.get_fill_color()
+class CellRendererSchool(CellRendererIcon):
+ __gtype_name__ = 'SugarCellRendererSchool'
+
+ def __init__(self, tree_view):
+ CellRendererIcon.__init__(self, tree_view)
+
+ self.props.width = style.GRID_CELL_SIZE
+ self.props.height = style.GRID_CELL_SIZE
+ self.props.size = style.SMALL_ICON_SIZE
+ self.props.icon_name = 'school-server'
+ self.props.mode = Gtk.CellRendererMode.ACTIVATABLE
+ client = GConf.Client.get_default()
+ prelit_color = XoColor(client.get_string('/desktop/sugar/user/color'))
+ self.props.prelit_stroke_color = prelit_color.get_stroke_color()
+ self.props.prelit_fill_color = prelit_color.get_fill_color()
+
+
class CellRendererActivityIcon(CellRendererIcon):
__gtype_name__ = 'SugarCellRendererActivityIcon'
@@ -500,18 +544,18 @@ class ActivityListPalette(ActivityPalette):
self._favorite_item.set_image(self._favorite_icon)
self._favorite_item.connect('activate',
self.__change_favorite_activate_cb)
- self.menu.append(self._favorite_item)
+# self.menu.append(self._favorite_item)
self._favorite_item.show()
if activity_info.is_user_activity():
- self._add_erase_option(registry, activity_info)
+ pass # self._add_erase_option(registry, activity_info)
registry = bundleregistry.get_registry()
self._activity_changed_sid = registry.connect('bundle_changed',
self.__activity_changed_cb)
self._update_favorite_item()
- self.menu.connect('destroy', self.__destroy_cb)
+ #self.menu.connect('destroy', self.__destroy_cb)
def _add_erase_option(self, registry, activity_info):
menu_item = MenuItem(_('Erase'), 'list-remove')
@@ -556,3 +600,4 @@ class ActivityListPalette(ActivityPalette):
def __erase_activate_cb(self, menu_item):
self.emit('erase-activated', self._bundle_id)
+
diff --git a/src/jarabe/desktop/favoritesview.py b/src/jarabe/desktop/favoritesview.py
index a9358f6..16a0cef 100644
--- a/src/jarabe/desktop/favoritesview.py
+++ b/src/jarabe/desktop/favoritesview.py
@@ -74,8 +74,13 @@ _favorites_settings = None
class FavoritesBox(Gtk.VBox):
__gtype_name__ = 'SugarFavoritesBox'
- def __init__(self):
+ def __init__(self, favorites):
+ """
+ If the argument is True, it will load the activities marked as favorites.
+ Else, it will load the activities marked for school.
+ """
Gtk.VBox.__init__(self)
+ self.load_favorites = favorites
self._view = FavoritesView(self)
self.pack_start(self._view, True, True, 0)
@@ -157,9 +162,14 @@ class FavoritesView(ViewContainer):
self.set_layout(self._layout)
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._box.load_favorites:
+ if registry.is_bundle_favorite(info.get_bundle_id(),
+ info.get_activity_version()):
+ self._add_activity(info)
+ else:
+ if registry.is_bundle_for_school(info.get_bundle_id(),
+ info.get_activity_version()):
+ self._add_activity(info)
def _set_layout(self, layout):
if layout not in LAYOUT_MAP:
@@ -288,11 +298,16 @@ class FavoritesView(ViewContainer):
def __connect_to_bundle_registry_cb(self):
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._box.load_favorites:
+ for info in registry:
+ if registry.is_bundle_favorite(info.get_bundle_id(),
+ info.get_activity_version()):
+ self._add_activity(info)
+ else:
+ for info in registry:
+ if registry.is_bundle_for_school(info.get_bundle_id(),
+ info.get_activity_version()):
+ self._add_activity(info)
registry.connect('bundle-added', self.__activity_added_cb)
registry.connect('bundle-removed', self.__activity_removed_cb)
registry.connect('bundle-changed', self.__activity_changed_cb)
@@ -308,9 +323,14 @@ class FavoritesView(ViewContainer):
def __activity_added_cb(self, activity_registry, activity_info):
registry = bundleregistry.get_registry()
- if registry.is_bundle_favorite(activity_info.get_bundle_id(),
- activity_info.get_activity_version()):
- self._add_activity(activity_info)
+ if self._box.load_favorites:
+ if registry.is_bundle_favorite(activity_info.get_bundle_id(),
+ activity_info.get_activity_version()):
+ self._add_activity(activity_info)
+ else:
+ if registry.is_bundle_for_school(activity_info.get_bundle_id(),
+ activity_info.get_activity_version()):
+ self._add_activity(activity_info)
def __activity_removed_cb(self, activity_registry, activity_info):
icon = self._find_activity_icon(activity_info.get_bundle_id(),
@@ -334,9 +354,14 @@ class FavoritesView(ViewContainer):
self.remove(icon)
registry = bundleregistry.get_registry()
- if registry.is_bundle_favorite(activity_info.get_bundle_id(),
- activity_info.get_activity_version()):
- self._add_activity(activity_info)
+ if self._box.load_favorites:
+ if registry.is_bundle_favorite(activity_info.get_bundle_id(),
+ activity_info.get_activity_version()):
+ self._add_activity(activity_info)
+ else:
+ if registry.is_bundle_for_school(activity_info.get_bundle_id(),
+ activity_info.get_activity_version()):
+ self._add_activity(activity_info)
def set_filter(self, query):
query = query.strip()
diff --git a/src/jarabe/desktop/homebox.py b/src/jarabe/desktop/homebox.py
index b87c345..2af711f 100644
--- a/src/jarabe/desktop/homebox.py
+++ b/src/jarabe/desktop/homebox.py
@@ -1,4 +1,5 @@
# Copyright (C) 2008 One Laptop Per Child
+# Copyright (C) 2012 Daniel Francis
#
# 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
@@ -30,7 +31,8 @@ from jarabe.desktop.activitieslist import ActivitiesList
from jarabe.util.normalize import normalize_string
_FAVORITES_VIEW = 0
-_LIST_VIEW = 1
+_SCHOOL_VIEW = 1
+_LIST_VIEW = 2
class HomeBox(Gtk.VBox):
@@ -41,7 +43,8 @@ class HomeBox(Gtk.VBox):
Gtk.VBox.__init__(self)
- self._favorites_box = favoritesview.FavoritesBox()
+ self._favorites_box = favoritesview.FavoritesBox(True)
+ self._school_box = favoritesview.FavoritesBox(False)
self._list_view = ActivitiesList()
toolbar.connect('query-changed', self.__toolbar_query_changed_cb)
@@ -81,8 +84,10 @@ class HomeBox(Gtk.VBox):
def __software_update_response_cb(self, alert, response_id):
if self._list_view in self.get_children():
self._list_view.remove_alert()
- else:
+ elif self._favorites_box in self.get_children():
self._favorites_box.remove_alert()
+ else:
+ self._school_box.remove_alert()
if response_id != Gtk.ResponseType.REJECT:
update_trigger_file = os.path.expanduser('~/.sugar-update')
@@ -104,6 +109,7 @@ class HomeBox(Gtk.VBox):
self._query = normalize_string(query.decode('utf-8'))
self._list_view.set_filter(self._query)
self._favorites_box.set_filter(self._query)
+ self._school_box.set_filter(self._query)
def __toolbar_view_changed_cb(self, toolbar, view):
self._set_view(view)
@@ -126,14 +132,30 @@ class HomeBox(Gtk.VBox):
if view == _FAVORITES_VIEW:
if self._list_view in self.get_children():
self.remove(self._list_view)
+ elif self._school_box in self.get_children():
+ self.remove(self._school_box)
if self._favorites_box not in self.get_children():
self.add(self._favorites_box)
self._favorites_box.show()
self._favorites_box.grab_focus()
+
+ elif view == _SCHOOL_VIEW:
+ if self._list_view in self.get_children():
+ self.remove(self._list_view)
+ elif self._favorites_box in self.get_children():
+ self.remove(self._favorites_box)
+
+ if self._school_box not in self.get_children():
+ self.add(self._school_box)
+ self._school_box.show()
+ self._school_box.grab_focus()
+
elif view == _LIST_VIEW:
if self._favorites_box in self.get_children():
self.remove(self._favorites_box)
+ elif self._school_box in self.get_children():
+ self.remove(self._school_box)
if self._list_view not in self.get_children():
self.add(self._list_view)
@@ -160,3 +182,4 @@ class HomeBox(Gtk.VBox):
if resume_mode and self._query != '':
self._list_view.set_filter(self._query)
self._favorites_box.set_filter(self._query)
+ self._school_box.set_filter(self._query)
diff --git a/src/jarabe/desktop/viewtoolbar.py b/src/jarabe/desktop/viewtoolbar.py
index 5cb0186..8d658d8 100644
--- a/src/jarabe/desktop/viewtoolbar.py
+++ b/src/jarabe/desktop/viewtoolbar.py
@@ -2,6 +2,7 @@
# Copyright (C) 2009 Tomeu Vizoso, Simon Schampijer
# Copyright (C) 2009-2012 One Laptop per Child
# Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
+# Copyright (C) 2012 Daniel Francis
#
# 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
@@ -31,7 +32,8 @@ from jarabe.desktop import favoritesview
_AUTOSEARCH_TIMEOUT = 1000
_FAVORITES_VIEW = 0
-_LIST_VIEW = 1
+_SCHOOL_VIEW = 1
+_LIST_VIEW = 2
class ViewToolbar(Gtk.Toolbar):
@@ -75,6 +77,13 @@ class ViewToolbar(Gtk.Toolbar):
_FAVORITES_VIEW)
self.insert(self._favorites_button, -1)
+ self._school_button = SchoolButton()
+ self._school_button.props.group = self._favorites_button
+ self._school_button.connect('toggled',
+ self.__view_button_toggled_cb,
+ _SCHOOL_VIEW)
+ self.insert(self._school_button, -1)
+
self._list_button = RadioToolButton(icon_name='view-list')
self._list_button.props.group = self._favorites_button
self._list_button.props.tooltip = _('List view')
@@ -87,10 +96,12 @@ class ViewToolbar(Gtk.Toolbar):
def show_view_buttons(self):
self._favorites_button.show()
+ self._school_button.show()
self._list_button.show()
def hide_view_buttons(self):
self._favorites_button.hide()
+ self._school_button.hide()
self._list_button.hide()
def clear_query(self):
@@ -149,6 +160,58 @@ class FavoritesButton(RadioToolButton):
self.props.tooltip = _('Favorites view')
self.props.accelerator = _('<Ctrl>1')
self.props.group = None
+ self.props.icon_name = 'gtk-home'
+
+ favorites_settings = favoritesview.get_settings()
+ self._layout = favorites_settings.layout
+ self._update_icon()
+
+ # someday, this will be a Gtk.Table()
+ layouts_grid = Gtk.HBox()
+ layout_item = None
+ for layoutid, layoutclass in sorted(favoritesview.LAYOUT_MAP.items()):
+ layout_item = RadioToolButton(icon_name=layoutclass.icon_name,
+ group=layout_item, active=False)
+ if layoutid == self._layout:
+ layout_item.set_active(True)
+ layouts_grid.pack_start(layout_item, True, False, 0)
+ layout_item.connect('toggled', self.__layout_activate_cb,
+ layoutid)
+ layouts_grid.show_all()
+ self.props.palette.set_content(layouts_grid)
+
+ def __layout_activate_cb(self, menu_item, layout):
+ if not menu_item.get_active():
+ return
+ if self._layout == layout and self.props.active:
+ return
+
+ if self._layout != layout:
+ self._layout = layout
+ self._update_icon()
+
+ favorites_settings = favoritesview.get_settings()
+ favorites_settings.layout = layout
+
+ if not self.props.active:
+ self.props.active = True
+ else:
+ self.emit('toggled')
+
+ def _update_icon(self):
+ pass
+ # self.props.icon_name = favoritesview.LAYOUT_MAP[self._layout].icon_name
+
+
+class SchoolButton(RadioToolButton):
+ __gtype_name__ = 'SugarSchoolButton'
+
+ def __init__(self):
+ RadioToolButton.__init__(self)
+ self.props.icon_name = 'school-server'
+ self.props.tooltip = _('School favorites')
+ self.props.accelerator = _('<Ctrl>I')
+ self.props.group = None
favorites_settings = favoritesview.get_settings()
self._layout = favorites_settings.layout
@@ -187,4 +250,5 @@ class FavoritesButton(RadioToolButton):
self.emit('toggled')
def _update_icon(self):
- self.props.icon_name = favoritesview.LAYOUT_MAP[self._layout].icon_name
+ pass
+ #self.props.icon_name = favoritesview.LAYOUT_MAP[self._layout].icon_name
diff --git a/src/jarabe/model/bundleregistry.py b/src/jarabe/model/bundleregistry.py
index e441122..fb133a6 100644
--- a/src/jarabe/model/bundleregistry.py
+++ b/src/jarabe/model/bundleregistry.py
@@ -1,5 +1,6 @@
# Copyright (C) 2006-2007 Red Hat, Inc.
# Copyright (C) 2009 Aleksey Lim
+# Copyright (C) 2012 Daniel Francis
#
# 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
@@ -70,7 +71,9 @@ class BundleRegistry(GObject.GObject):
self._gio_monitors.append(monitor)
self._last_defaults_mtime = -1
+ self._last_school_defaults_mtime = -1
self._favorite_bundles = {}
+ self._school_bundles = {}
client = GConf.Client.get_default()
self._protected_activities = []
@@ -145,6 +148,27 @@ class BundleRegistry(GObject.GObject):
self._last_defaults_mtime = float(favorites_data['defaults-mtime'])
self._favorite_bundles = favorite_bundles
+ school_path = env.get_profile_path('school_activities')
+ if os.path.exists(school_path):
+ school_data = simplejson.load(open(school_path))
+
+ school_bundles = school_data['school']
+ if not isinstance(school_bundles, dict):
+ raise ValueError('Invalid format in %s.' % school_path)
+ if school_bundles:
+ first_key = school_bundles.keys()[0]
+ if not isinstance(first_key, basestring):
+ raise ValueError('Invalid format in %s.' % school_path)
+
+ first_value = school_bundles.values()[0]
+ if first_value is not None and \
+ not isinstance(first_value, dict):
+ raise ValueError('Invalid format in %s.' % school_path)
+
+ self._last_school_defaults_mtime = float(school_data['defaults-mtime'])
+ self._school_bundles = school_bundles
+
+
def _merge_default_favorites(self):
default_activities = []
defaults_path = os.path.join(config.data_path, 'activities.defaults')
@@ -179,6 +203,40 @@ class BundleRegistry(GObject.GObject):
self._write_favorites_file()
+ default_school_activities = []
+ defaults_school_path = os.path.join(config.data_path, 'schoolactivities.defaults')
+ if os.path.exists(defaults_school_path):
+ file_mtime = os.stat(defaults_school_path).st_mtime
+ if file_mtime > self._last_school_defaults_mtime:
+ f = open(defaults_school_path, 'r')
+ for line in f.readlines():
+ line = line.strip()
+ if line and not line.startswith('#'):
+ default_school_activities.append(line)
+ f.close()
+ self._last_school_defaults_mtime = file_mtime
+
+ if not default_school_activities:
+ return
+
+ for bundle_id in default_school_activities:
+ max_version = '0'
+ for bundle in self._bundles:
+ if bundle.get_bundle_id() == bundle_id and \
+ NormalizedVersion(max_version) < \
+ NormalizedVersion(bundle.get_activity_version()):
+ max_version = bundle.get_activity_version()
+
+ key = self._get_favorite_key(bundle_id, max_version)
+ if NormalizedVersion(max_version) > NormalizedVersion('0') and \
+ key not in self._favorite_bundles:
+ self._school_bundles[key] = None
+
+ logging.debug('After merging: %r', self._favorite_bundles)
+
+ self._write_school_file()
+
+
def get_bundle(self, bundle_id):
"""Returns an bundle given his service name"""
for bundle in self._bundles:
@@ -314,10 +372,32 @@ class BundleRegistry(GObject.GObject):
self._write_favorites_file()
return True
+ def set_bundle_for_school(self, bundle_id, version, favorite):
+ changed = self._set_bundle_for_school(bundle_id, version, favorite)
+ if changed:
+ bundle = self._find_bundle(bundle_id, version)
+ self.emit('bundle-changed', bundle)
+
+ def _set_bundle_for_school(self, bundle_id, version, favorite):
+ key = self._get_favorite_key(bundle_id, version)
+ if favorite and not key in self._school_bundles:
+ self._school_bundles[key] = None
+ elif not favorite and key in self._school_bundles:
+ del self._school_bundles[key]
+ else:
+ return False
+
+ self._write_school_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 is_bundle_for_school(self, bundle_id, version):
+ key = self._get_favorite_key(bundle_id, version)
+ return key in self._school_bundles
+
def is_activity_protected(self, bundle_id):
return bundle_id in self._protected_activities
@@ -357,6 +437,12 @@ class BundleRegistry(GObject.GObject):
'favorites': self._favorite_bundles}
simplejson.dump(favorites_data, open(path, 'w'), indent=1)
+ def _write_school_file(self):
+ path = env.get_profile_path('school_activities')
+ school_data = {'defaults-mtime': self._last_school_defaults_mtime,
+ 'school': self._favorite_bundles}
+ simplejson.dump(school_data, open(path, 'w'), indent=1)
+
def is_installed(self, bundle):
# TODO treat ContentBundle in special way
# needs rethinking while fixing ContentBundle support