>From 8bfefa7b39adec1258bd993c0d97c6940b021cfe Mon Sep 17 00:00:00 2001 From: Aleksander Morgado Date: Wed, 23 Oct 2013 17:46:24 +0200 Subject: [PATCH] localProvider: add a simple local files provider using Tracker --- src/Makefile.am | 3 +- src/localProvider.js | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/mainWindow.js | 16 +++++++++ 3 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 src/localProvider.js diff --git a/src/Makefile.am b/src/Makefile.am index 1ca2376..c2fc4dd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,7 +23,8 @@ dist_js_DATA = \ detailsWindow.js \ main.js \ mainWindow.js \ - workModel.js + workModel.js \ + localProvider.js CLEANFILES = \ gnome-books diff --git a/src/localProvider.js b/src/localProvider.js new file mode 100644 index 0000000..47235d2 --- /dev/null +++ b/src/localProvider.js @@ -0,0 +1,98 @@ +const Lang = imports.lang; + +const GObject = imports.gi.GObject; +const Signals = imports.signals; +const Tracker = imports.gi.Tracker; + +const QueryColumns = { + URN: 0, + URI: 1, + FILENAME: 2, + TITLE: 3, + AUTHOR: 4, +}; + +const localProvider = new Lang.Class({ + Name: 'localProvider', + + // Tell the provider to query Tracker looking for local ePub files (filtered + // explicitly with mimetype). The localProvider will emit 'book-found' + // signals for each result returned in the query. + // + // TODO: 'live query' where we get notified about newly added/removed epubs + // TODO: currently just author and title are included in the emitted signal + populate: function() { + let sparql = + 'SELECT DISTINCT ' + + ' ?u' + // urn + ' nie:url(?u)' + // uri + ' nfo:fileName(?u)' + // filename + ' nie:title(?u)' + // title + ' tracker:coalesce(nco:fullname(?creator),' + // creator or... + ' nco:fullname(?publisher),' + // ...publisher or... + ' \'\') ' + // ...nothing + 'WHERE {' + + ' ?u a nfo:FileDataObject .' + // limit to files + ' ?u nie:mimeType \'application/epub+zip\'' + // match files by mimetype + ' OPTIONAL { ?u nco:publisher ?publisher . }' + + ' OPTIONAL { ?u nco:creator ?creator . }' + + '}'; + + try { + // connect to tracker if not done before + if (this._connection == null) + this._connection = Tracker.SparqlConnection.get(null); + + // query to Tracker + this._connection.query_async(sparql, null, Lang.bind(this, this._onQueryReady)); + } catch (e) { + log('Unable to query the tracker database: ' + e.toString()); + } + }, + + // query is ready, get the cursor and start iterating it + _onQueryReady: function(connection, res) { + try { + let cursor = connection.query_finish(res); + + cursor.next_async(null, Lang.bind(this, this._onCursorNext)); + } catch (e) { + log('Unable to query single item ' + e.message); + } + }, + + // cursor iteration + _onCursorNext: function(cursor, res) { + try { + let valid = cursor.next_finish(res); + + if (!valid) { + cursor.close(); + return; + } + } catch (e) { + cursor.close(); + return; + } + + // add book from cursor info + this._addBookFromCursor(cursor); + + // keep on iterating cursor + cursor.next_async(null, Lang.bind(this, this._onCursorNext)); + }, + + // add a single book from the given cursor row + _addBookFromCursor: function(cursor) { + let urn = cursor.get_string(QueryColumns.URN)[0]; + let uri = cursor.get_string(QueryColumns.URI)[0]; + let filename = cursor.get_string(QueryColumns.FILENAME)[0]; + let title = cursor.get_string(QueryColumns.TITLE)[0]; + let author = cursor.get_string(QueryColumns.AUTHOR)[0]; + + // TODO: do something with URN, URI and filename if needed + + this.emit('book-found', title, author); + } +}); +Signals.addSignalMethods(localProvider.prototype); diff --git a/src/mainWindow.js b/src/mainWindow.js index b4ca394..6e48277 100644 --- a/src/mainWindow.js +++ b/src/mainWindow.js @@ -1,11 +1,13 @@ const Lang = imports.lang; +const Mainloop = imports.mainloop; const Gio = imports.gi.Gio; const GObject = imports.gi.GObject; const Gtk = imports.gi.Gtk; const workModel = imports.workModel; const detailsWindow = imports.detailsWindow; +const localProvider = imports.localProvider; const MainWindow = new Lang.Class({ Name: 'MainWindow', @@ -45,6 +47,13 @@ const MainWindow = new Lang.Class({ this._bookWindowAction = 'none'; this._bookshelf = {}; + + // create local provider and let it populate itself + this._localProvider = new localProvider.localProvider(); + this._localProvider.connect('book-found', Lang.bind(this, this._local_book_found)); + Mainloop.idle_add(Lang.bind(this, function() { + this._localProvider.populate(); + })); }, _populate_toolbar: function() { @@ -124,4 +133,11 @@ const MainWindow = new Lang.Class({ this._listStore.set(iter, [ 0, 1, 2 ], [ bookModel.id, bookModel.title, bookModel.author ]); this._bookshelf[bookModel.id] = bookModel; }, + + _local_book_found: function(localfiles, title, author) { + let book = new workModel.workModel(this._work_counter, title, author); + + this._work_counter++; + this._append_book(book); + }, }); -- 1.8.3.1