diff --git a/js/Makefile.am b/js/Makefile.am index 55bb11131..2c1bfb640 100644 --- a/js/Makefile.am +++ b/js/Makefile.am @@ -9,7 +9,9 @@ nobase_dist_js_DATA = \ misc/gnomeSession.js \ misc/history.js \ misc/params.js \ + misc/semantic.js \ misc/util.js \ + misc/zeitgeist.js \ perf/core.js \ ui/altTab.js \ ui/appDisplay.js \ diff --git a/js/misc/semantic.js b/js/misc/semantic.js new file mode 100644 index 000000000..1593c1575 --- /dev/null +++ b/js/misc/semantic.js @@ -0,0 +1,43 @@ +/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- + * + * Semantic-desktop interpretations for various data types + * + * Authors: Federico Mena Quintero + * + * 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, 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., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +const NFO_AUDIO = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#Audio"; +const NFO_DOCUMENT = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#Document"; +const NFO_HTML_DOCUMENT = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#HtmlDocument"; +const NFO_IMAGE = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#Image"; +const NFO_MEDIA = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#Media"; +const NFO_MIND_MAP = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#MindMap"; +const NFO_PAGINATED_TEXT_DOCUMENT = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#PaginatedTextDocument"; +const NFO_PLAIN_TEXT_DOCUMENT = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#PlainTextDocument"; +const NFO_PRESENTATION = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#Presentation"; +const NFO_RASTER_IMAGE = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#RasterImage"; +const NFO_SOURCE_CODE = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#SourceCode"; +const NFO_SPREADSHEET = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#Spreadsheet"; +const NFO_TEXT_DOCUMENT = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#TextDocument"; +const NFO_VECTOR_IMAGE = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#VectorImage"; +const NFO_VIDEO = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#Video"; + +const NMM_CURSOR = "http://www.semanticdesktop.org/ontologies/2009/02/19/nmm#Cursor"; +const NMM_ICON = "http://www.semanticdesktop.org/ontologies/2009/02/19/nmm#Icon"; +const NMM_MOVIE = "http://www.semanticdesktop.org/ontologies/2009/02/19/nmm#Movie"; +const NMM_MUSIC_PIECE = "http://www.semanticdesktop.org/ontologies/2009/02/19/nmm#MusicPiece"; +const NMM_TV_SHOW = "http://www.semanticdesktop.org/ontologies/2009/02/19/nmm#TVShow"; diff --git a/js/misc/zeitgeist.js b/js/misc/zeitgeist.js new file mode 100644 index 000000000..9fe58315c --- /dev/null +++ b/js/misc/zeitgeist.js @@ -0,0 +1,234 @@ +/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- + * + * Copyright (C) 2010 Seif Lotfy + * Copyright (C) 2011 Siegfried-Angel Gevatter Pujals + * Copyright (C) 2010-2011 Collabora Ltd. + * Authored by: Seif Lotfy + * + * 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, 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., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +const DBus = imports.dbus; + +const SIG_EVENT = '(asaasay)'; +const MAX_TIMESTAMP = 9999999999999; + +// Number of results given by fullTextSearch; 100 is probably enough. +// Note: We can't currently increase this number to anything above 132, due to +// https://bugs.launchpad.net/zeitgeist-extensions/+bug/716503 +const MAX_RESULTS = 100; + +const ResultType = { + // http://zeitgeist-project.com/docs/0.6/datamodel.html#resulttype + // We currently only use MOST_POPULAR_SUBJECTS + MOST_POPULAR_SUBJECTS: 4, +}; + +/* Zeitgeist Subjects (files, people, etc.) */ + +function Subject(uri, interpretation, manifestation, origin, mimetype, text, storage) { + this._init(uri, interpretation, manifestation, origin, mimetype, text, storage); +}; + +Subject.prototype = { + _init: function(uri, interpretation, manifestation, origin, mimetype, text, storage) { + this.uri = uri; + this.interpretation = interpretation; + this.manifestation = manifestation; + this.origin = origin; + this.mimetype = mimetype; + this.text = text; + this.storage = storage; + }, +}; + +Subject.fromPlain = function(rawSubject) { + return new Subject(rawSubject[0], // uri + rawSubject[1], // interpretation + rawSubject[2], // manifestation + rawSubject[3], // origin + rawSubject[4], // mimetype + rawSubject[5], // text + rawSubject[6]); // storage +}; + +Subject.toPlain = function(subject) { + let rawSubject = []; + rawSubject[0] = subject.uri; + rawSubject[1] = subject.interpretation; + rawSubject[2] = subject.manifestation + rawSubject[3] = subject.origin; + rawSubject[4] = subject.mimetype; + rawSubject[5] = subject.text; + rawSubject[6] = subject.storage; + return rawSubject; +}; + +/* Zeitgeist Events */ + +function Event(interpretation, manifestation, actor, subjects, payload) { + this._init(interpretation, manifestation, actor, subjects, payload); +}; + +Event.prototype = { + _init: function(interpretation, manifestation, actor, subjects, payload) { + this.id = 0; + this.timestamp = 0; + this.actor = actor; + this.interpretation = interpretation; + this.manifestation = manifestation; + this.actor = actor; + this.payload = payload; + this.subjects = subjects; + }, +}; + +Event.fromPlain = function(rawEvent) { + let subjects = rawEvent[1].map(Subject.fromPlain); + let event = new Event(rawEvent[0][2], // interpretation + rawEvent[0][3], // manifestation + rawEvent[0][4], // actor + subjects, // subjects + rawEvent[2]);// payload + event.id = rawEvent[0][0]; // id + event.timestamp = rawEvent[0][1]; // timestamp + return event; +}; + +Event.toPlain = function(event) { + let rawEvent = []; + rawEvent[0] = []; + rawEvent[0][0] = event.id.toString(); + rawEvent[0][1] = event.timestamp.toString(); + rawEvent[0][2] = event.interpretation; + rawEvent[0][3] = event.manifestation; + rawEvent[0][4] = event.actor; + rawEvent[1] = event.subjects.map(Subject.toPlain); + rawEvent[2] = event.payload; + return rawEvent; +}; + +// Zeitgeist D-Bus interface definitions. Note that most of these are +// incomplete, and only cover the methods/properties/signals that +// we're currently using. + +/* Zeitgeist D-Bus Interface */ + +const LOG_NAME = 'org.gnome.zeitgeist.Engine'; +const LOG_PATH = '/org/gnome/zeitgeist/log/activity'; +const LogIface = { + name: 'org.gnome.zeitgeist.Log', + methods: [ + { name: 'GetEvents', + inSignature: 'au', + outSignature: 'a'+SIG_EVENT }, + { name: 'FindRelatedUris', + inSignature: 'au', + outSignature: '(xx)a(' + SIG_EVENT + ')a'+ SIG_EVENT + 'uuu' }, + { name: 'FindEventIds', + inSignature: '(xx)a' + SIG_EVENT + 'uuu', + outSignature: 'au' }, + { name: 'FindEvents', + inSignature: '(xx)a' + SIG_EVENT + 'uuu', + outSignature: 'a' + SIG_EVENT }, + { name: 'InsertEvents', + inSignature: 'a' + SIG_EVENT, + outSignature: 'au' }, + { name: 'DeleteEvents', + inSignature: 'au', + outSignature: '(xx)' }, + { name: 'DeleteLog', + inSignature: '', + outSignature: '' }, + { name: 'Quit', + inSignature: '', + outSignature: '' }, + // FIXME: Add missing DBus Methods + // - InstallMonitor + // - RemoveMonitor + ], + properties: [ + { name: 'Get', + inSignature: 'ss', + outSignature: 'v', + access: 'read' }, + { name: 'Set', + inSignature: 'ssv', + outSignature: '', + access: 'read' }, + { name: 'GetAll', + inSignature: 's', + outSignature: 'a{sv}', + access: 'read' }, + ] +}; + +const Log = DBus.makeProxyClass(LogIface); +const _log = new Log(DBus.session, LOG_NAME, LOG_PATH); + +function findEvents(timeRange, eventTemplates, storageState, numEvents, resultType, callback) { + function handler(results, error) { + if (error != null) + log("Error querying Zeitgeist for events: "+error); + else + callback(results.map(Event.fromPlain)); + } + _log.FindEventsRemote(timeRange, eventTemplates.map(Event.toPlain), + storageState, numEvents, resultType, handler); +} + +/* Zeitgeist Full-Text-Search Interface */ + +const INDEX_NAME = 'org.gnome.zeitgeist.Engine'; +const INDEX_PATH = '/org/gnome/zeitgeist/index/activity'; +const IndexIface = { + name: 'org.gnome.zeitgeist.Index', + methods: [ + { name: 'Search', + inSignature: 's(xx)a'+SIG_EVENT+'uuu', + outSignature: 'a'+SIG_EVENT+'u' }, + ], +}; + +const Index = DBus.makeProxyClass(IndexIface); +const _index = new Index(DBus.session, INDEX_NAME, INDEX_PATH); + +/** + * fullTextSearch: + * + * Asynchronously search Zeitgeist's index for events relating to the query. + * + * @param query The query string, using asterisks for wildcards. Wildcards must + * be used at the start and/or end of a string to get relevant information. + * @param eventTemplates Zeitgeist event templates, see + * http://zeitgeist-project.com/docs/0.6/datamodel.html#event for more + * information + * @param callback The callback, takes a list containing Zeitgeist.Event + * objects + */ +function fullTextSearch(query, eventTemplates, callback) { + function handler(results, error) { + if (error != null) + log("Error searching with Zeitgeist FTS: "+error); + else + callback(results[0].map(Event.fromPlain)); + } + _index.SearchRemote(query, [0, MAX_TIMESTAMP], + eventTemplates.map(Event.toPlain), + 0, // offset into the search results + MAX_RESULTS, + ResultType.MOST_POPULAR_SUBJECTS, handler); +} diff --git a/js/ui/lookingGlass.js b/js/ui/lookingGlass.js index c98fa22f7..03b83ecfd 100644 --- a/js/ui/lookingGlass.js +++ b/js/ui/lookingGlass.js @@ -26,10 +26,12 @@ var commandHeader = 'const Clutter = imports.gi.Clutter; ' + 'const Gtk = imports.gi.Gtk; ' + 'const Mainloop = imports.mainloop; ' + 'const Meta = imports.gi.Meta; ' + + 'const Semantic = imports.misc.semantic' + 'const Shell = imports.gi.Shell; ' + 'const Main = imports.ui.main; ' + 'const Lang = imports.lang; ' + 'const Tweener = imports.ui.tweener; ' + + 'const Zeitgeist = imports.misc.zeitgeist; ' + /* Utility functions...we should probably be able to use these * in the shell core code too. */ 'const stage = global.stage; ' +