[gnome-documents] all: introduce read support for favorite resources
- From: Cosimo Cecchi <cosimoc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-documents] all: introduce read support for favorite resources
- Date: Thu, 25 Aug 2011 21:44:29 +0000 (UTC)
commit 817af54597371747e1d8b3bf6019fd030db3e361
Author: Cosimo Cecchi <cosimoc gnome org>
Date: Thu Aug 25 16:13:47 2011 -0400
all: introduce read support for favorite resources
Together with a list of categories on the sidebar; the Favorites
category is the first we're going to implement. Right now only reading
is supported, writing support coming soon.
src/Makefile-js.am | 1 +
src/application.js | 2 +
src/categories.js | 85 +++++++++++++++++++++++++++++++++++++++++++++++++
src/docFactory.js | 27 ++++++++++++++-
src/global.js | 7 ++--
src/lib/gd-utils.c | 31 ++++++++++++++++++
src/lib/gd-utils.h | 8 +++++
src/sidebar.js | 88 ++++++++++++++++++++++++++++++++++++++++++++++++---
src/trackerModel.js | 24 +++++++++-----
9 files changed, 255 insertions(+), 18 deletions(-)
---
diff --git a/src/Makefile-js.am b/src/Makefile-js.am
index efa6c44..e5e4f55 100644
--- a/src/Makefile-js.am
+++ b/src/Makefile-js.am
@@ -1,6 +1,7 @@
jsdir = $(pkgdatadir)/js/
dist_js_DATA = \
application.js \
+ categories.js \
docFactory.js \
filterController.js \
gDataMiner.js \
diff --git a/src/application.js b/src/application.js
index d2330fb..b5c6aae 100644
--- a/src/application.js
+++ b/src/application.js
@@ -30,6 +30,7 @@ const Gtk = imports.gi.Gtk;
const GLib = imports.gi.GLib;
const Tracker = imports.gi.Tracker;
+const Categories = imports.categories;
const FilterController = imports.filterController;
const Format = imports.format;
const Global = imports.global;
@@ -108,6 +109,7 @@ Application.prototype = {
Global.settings = new Gio.Settings({ schema: 'org.gnome.documents' });
Global.offsetController = new OffsetController.OffsetController();
Global.filterController = new FilterController.FilterController();
+ Global.categoryManager = new Categories.CategoryManager();
// connect to tracker
Tracker.SparqlConnection.get_async(null, Lang.bind(this,
diff --git a/src/categories.js b/src/categories.js
new file mode 100644
index 0000000..43191b3
--- /dev/null
+++ b/src/categories.js
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2011 Red Hat, Inc.
+ *
+ * Gnome Documents 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.
+ *
+ * Gnome Documents 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 Gnome Documents; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author: Cosimo Cecchi <cosimoc redhat com>
+ *
+ */
+
+const Lang = imports.lang;
+const Signals = imports.signals;
+
+const _ = imports.gettext.gettext;
+
+function Category(id, name, icon) {
+ this._init(id, name, icon);
+};
+
+Category.prototype = {
+ _init: function(id, name, icon) {
+ this.id = id;
+ this.name = name;
+ this.icon = icon;
+ },
+
+ getFilter: function() {
+ if (this.id == 'favorites')
+ return '{ ?urn nao:hasTag nao:predefined-tag-favorite }';
+
+ return '';
+ }
+};
+
+function CategoryManager() {
+ this._init();
+};
+
+CategoryManager.prototype = {
+ _init: function() {
+ this.categories = [];
+
+ this.categories.push(new Category('recent', _("New and Recent"), ''));
+
+ this.categories.push(new Category('favorites', _("Favorites"), 'emblem-favorite-symbolic'));
+ this.categories.push(new Category('private', _("Private"), 'channel-secure-symbolic'));
+ this.categories.push(new Category('shared', _("Shared with you"), 'emblem-shared-symbolic'));
+
+ this.setActiveCategoryId('recent');
+ },
+
+ setActiveCategoryId: function(id) {
+ let matched = this.categories.filter(Lang.bind(this,
+ function(category) {
+ return (category.id == id);
+ }));
+
+ if (!matched.length)
+ return;
+
+ this.activeCategory = matched[0];
+
+ this.emit('active-category-changed');
+ },
+
+ getActiveCategoryId: function() {
+ return this.activeCategory.id;
+ },
+
+ getActiveCategoryFilter: function() {
+ return this.activeCategory.getFilter();
+ }
+};
+Signals.addSignalMethods(CategoryManager.prototype);
diff --git a/src/docFactory.js b/src/docFactory.js
index 87ccee0..4652ae0 100644
--- a/src/docFactory.js
+++ b/src/docFactory.js
@@ -43,6 +43,7 @@ DocCommon.prototype = {
this.mtime = cursor.get_string(TrackerModel.TrackerColumns.MTIME)[0];
this.resourceUrn = cursor.get_string(TrackerModel.TrackerColumns.RESOURCE_URN)[0];
+ this._favorite = cursor.get_boolean(TrackerModel.TrackerColumns.FAVORITE);
this._type = cursor.get_string(TrackerModel.TrackerColumns.TYPE)[0];
this.pixbuf = Utils.pixbufFromRdfType(this._type);
@@ -60,6 +61,28 @@ DocCommon.prototype = {
refreshIcon: function() {
this.pixbuf = Utils.pixbufFromRdfType(this._type);
+ this.checkEmblemsAndUpdateIcon();
+ },
+
+ checkEmblemsAndUpdateIcon: function() {
+ if (this._favorite) {
+ let emblemIcon = new Gio.ThemedIcon({ name: 'emblem-favorite' });
+ let emblem = new Gio.Emblem({ icon: emblemIcon });
+ let emblemedIcon = new Gio.EmblemedIcon({ gicon: this.pixbuf });
+ emblemedIcon.add_emblem(emblem);
+
+ let theme = Gtk.IconTheme.get_default();
+
+ try {
+ let iconInfo = theme.lookup_by_gicon(emblemedIcon,
+ this.pixbuf.get_width(),
+ Gtk.IconLookupFlags.FORCE_SIZE);
+ this.pixbuf = iconInfo.load_icon();
+ } catch (e) {
+ log('Unable to render the emblem: ' + e.toString());
+ }
+ }
+
this.emit('icon-updated');
},
@@ -133,7 +156,7 @@ LocalDocument.prototype = {
}
if (haveNewIcon)
- this.emit('icon-updated');
+ this.checkEmblemsAndUpdateIcon();
},
_onQueueThumbnailJob: function(object, res) {
@@ -166,7 +189,7 @@ LocalDocument.prototype = {
Utils.getIconSize(),
Utils.getIconSize());
- this.emit('icon-updated');
+ this.checkEmblemsAndUpdateIcon();
}
}
};
diff --git a/src/global.js b/src/global.js
index 769ed7f..077aff2 100644
--- a/src/global.js
+++ b/src/global.js
@@ -20,9 +20,10 @@
*/
let application = null;
-let sourceManager = null;
+let categoryManager = null;
let connection = null;
-let settings = null;
+let model = null;
let offsetController = null;
let selectionController = null;
-let model = null;
+let settings = null;
+let sourceManager = null;
diff --git a/src/lib/gd-utils.c b/src/lib/gd-utils.c
index f79da9d..3fd56d8 100644
--- a/src/lib/gd-utils.c
+++ b/src/lib/gd-utils.c
@@ -107,6 +107,37 @@ gd_sources_store_set (GtkListStore *store,
-1);
}
+/**
+ * gd_create_sidebar_store:
+ *
+ * Returns: (transfer full):
+ */
+GtkListStore *
+gd_create_sidebar_store (void)
+{
+ return gtk_list_store_new (4,
+ G_TYPE_STRING, // ID
+ G_TYPE_STRING, // NAME
+ G_TYPE_STRING, // ICON
+ G_TYPE_BOOLEAN); // HEADING
+}
+
+void
+gd_sidebar_store_set (GtkListStore *store,
+ GtkTreeIter *iter,
+ const gchar *id,
+ const gchar *name,
+ const gchar *icon_name,
+ gboolean heading)
+{
+ gtk_list_store_set (store, iter,
+ 0, id,
+ 1, name,
+ 2, icon_name,
+ 3, heading,
+ -1);
+}
+
#define ATTRIBUTES_FOR_THUMBNAIL \
G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE"," \
G_FILE_ATTRIBUTE_TIME_MODIFIED
diff --git a/src/lib/gd-utils.h b/src/lib/gd-utils.h
index 3214051..3f6d525 100644
--- a/src/lib/gd-utils.h
+++ b/src/lib/gd-utils.h
@@ -47,6 +47,14 @@ void gd_sources_store_set (GtkListStore *store,
const gchar *name,
gboolean heading);
+GtkListStore * gd_create_sidebar_store (void);
+void gd_sidebar_store_set (GtkListStore *store,
+ GtkTreeIter *iter,
+ const gchar *id,
+ const gchar *name,
+ const gchar *icon_name,
+ gboolean heading);
+
void gd_queue_thumbnail_job_for_file_async (GFile *file,
GAsyncReadyCallback callback,
gpointer user_data);
diff --git a/src/sidebar.js b/src/sidebar.js
index d379aeb..c81a021 100644
--- a/src/sidebar.js
+++ b/src/sidebar.js
@@ -35,17 +35,91 @@ const _SIDEBAR_WIDTH_REQUEST = 240;
const _SIDEBAR_SOURCES_PAGE = 0;
const _SIDEBAR_MAIN_PAGE = 1;
+const SidebarModelColumns = {
+ ID: 0,
+ NAME: 1,
+ ICON: 2,
+ HEADING: 3
+};
+
+function SidebarModel() {
+ this._init();
+};
+
+SidebarModel.prototype = {
+ _init: function() {
+ let iter = null;
+
+ this.model = Gd.create_sidebar_store();
+ this._categoryManager = Global.categoryManager;
+
+ let categories = this._categoryManager.categories;
+ categories.forEach(Lang.bind(this,
+ function(category) {
+ iter = this.model.append();
+ Gd.sidebar_store_set(this.model, iter,
+ category.id, category.name, category.icon, false);
+ }));
+ }
+};
+
function SidebarView() {
this._init();
};
SidebarView.prototype = {
_init: function() {
+ this._model = new SidebarModel();
+ this._treeModel = this._model.model;
+ this._categoryManager = Global.categoryManager;
+
+ this._treeView = new Gtk.TreeView({ headers_visible: false,
+ vexpand: true });
+ Gd.gtk_tree_view_set_activate_on_single_click(this._treeView, true);
+ this._treeView.set_model(this._treeModel);
+
+ this.widget = new Gtk.ScrolledWindow({ hscrollbar_policy: Gtk.PolicyType.NEVER });
+ this.widget.add(this._treeView);
+
+ this._treeView.connect('row-activated', Lang.bind(this,
+ function(view, path) {
+ let iter = this._treeModel.get_iter(path)[1];
+ let id = this._treeModel.get_value(iter, SidebarModelColumns.ID);
+
+ this._categoryManager.setActiveCategoryId(id);
+ }));
+
+ let col = new Gtk.TreeViewColumn();
+ this._treeView.append_column(col);
+
+ this._rendererIcon = new Gtk.CellRendererPixbuf({ xpad: 4 });
+ col.pack_start(this._rendererIcon, false);
+ col.add_attribute(this._rendererIcon,
+ 'icon-name', SidebarModelColumns.ICON);
+
+
+ this._rendererText = new Gtk.CellRendererText();
+ col.pack_start(this._rendererText, true);
+ col.add_attribute(this._rendererText,
+ 'text', SidebarModelColumns.NAME);
+
+ this.widget.show_all();
+ }
+};
+
+function SidebarMainPage() {
+ this._init();
+};
+
+SidebarMainPage.prototype = {
+ _init: function() {
this.widget = new Gtk.Grid({ orientation: Gtk.Orientation.VERTICAL,
- border_width: 6,
- width_request: _SIDEBAR_WIDTH_REQUEST,
- column_homogeneous: true });
+ border_width: 6,
+ width_request: _SIDEBAR_WIDTH_REQUEST,
+ column_homogeneous: true,
+ column_spacing: 12 });
+ // sources button
let buttonContent = new Gtk.Grid({ orientation: Gtk.Orientation.HORIZONTAL,
row_spacing: 6 });
// FIXME: setting yalign here seems wrong, but why are those not aligned
@@ -60,6 +134,10 @@ SidebarView.prototype = {
this.widget.add(this._sourcesButton);
this._sourcesButton.connect('clicked', Lang.bind(this, this._onSourcesButtonClicked));
+ // actual view
+ this._sidebarView = new SidebarView();
+ this.widget.add(this._sidebarView.widget);
+
this.widget.show_all();
},
@@ -67,7 +145,7 @@ SidebarView.prototype = {
this.emit('sources-button-clicked');
}
};
-Signals.addSignalMethods(SidebarView.prototype);
+Signals.addSignalMethods(SidebarMainPage.prototype);
function Sidebar() {
this._init();
@@ -85,7 +163,7 @@ Sidebar.prototype = {
this._sourceView = new Sources.SourceView();
this.widget.insert_page(this._sourceView.widget, null, _SIDEBAR_SOURCES_PAGE);
- this._sidebarView = new SidebarView();
+ this._sidebarView = new SidebarMainPage();
this.widget.insert_page(this._sidebarView.widget, null, _SIDEBAR_MAIN_PAGE);
this._sidebarView.connect('sources-button-clicked',
Lang.bind(this, this._onSourcesButtonClicked));
diff --git a/src/trackerModel.js b/src/trackerModel.js
index 77838bc..a06c074 100644
--- a/src/trackerModel.js
+++ b/src/trackerModel.js
@@ -57,7 +57,8 @@ const TrackerColumns = {
TOTAL_COUNT: 5,
IDENTIFIER: 6,
TYPE: 7,
- RESOURCE_URN: 8
+ RESOURCE_URN: 8,
+ FAVORITE: 9
};
function QueryBuilder() {
@@ -72,8 +73,7 @@ QueryBuilder.prototype = {
let filter =
('fn:contains ' +
'(fn:lower-case (tracker:coalesce(nie:title(%s), nfo:fileName(%s))), ' +
- '"%s") ' +
- '&& ').format(subject, subject, Global.filterController.getFilter());
+ '"%s")').format(subject, subject, Global.filterController.getFilter());
return filter;
},
@@ -82,8 +82,10 @@ QueryBuilder.prototype = {
let sparql = 'FILTER ((';
sparql += this._buildFilterSearch(subject);
+ sparql += ') && (';
sparql += Global.sourceManager.getActiveSourceFilter(subject);
- sparql += ')) ';
+
+ sparql += '))';
return sparql;
},
@@ -116,14 +118,16 @@ QueryBuilder.prototype = {
'tracker:coalesce(nie:title(?urn), nfo:fileName(?urn)) ' + // title
'tracker:coalesce(nco:fullname(?creator), nco:fullname(?publisher)) ' + // author
'tracker:coalesce(nfo:fileLastModified(?urn), nie:contentLastModified(?urn)) AS ?mtime ' + // mtime
- this._buildTotalCounter() +
- 'nao:identifier(?urn) ' +
- 'rdf:type(?urn) ' +
- 'nie:dataSource(?urn) ' +
+ this._buildTotalCounter() + // totalCount
+ 'nao:identifier(?urn) ' + // identifier
+ 'rdf:type(?urn) ' + // type
+ 'nie:dataSource(?urn) ' + // resource URN
+ '( EXISTS { ?urn nao:hasTag nao:predefined-tag-favorite } )' + // favorite
'WHERE { ' +
this._buildTypeFilter('?urn') +
'OPTIONAL { ?urn nco:creator ?creator . } ' +
'OPTIONAL { ?urn nco:publisher ?publisher . } ' +
+ Global.categoryManager.getActiveCategoryFilter() +
this._buildFilterString('?urn') +
' } ' +
'ORDER BY DESC (?mtime)' +
@@ -156,6 +160,10 @@ TrackerModel.prototype = {
this._sourceManager.connect('active-source-changed',
Lang.bind(this, this._refresh));
+ this._categoryManager = Global.categoryManager;
+ this._categoryManager.connect('active-category-changed',
+ Lang.bind(this, this._refresh));
+
this._offsetController = Global.offsetController;
this._offsetController.connect('offset-changed',
Lang.bind(this, this._performCurrentQuery));
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]