Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
07c39959d9 | ||
|
23d1d18619 | ||
|
23bf5db80c | ||
|
550e9973b7 | ||
|
e4e6b26e15 | ||
|
9551e1c2f5 | ||
|
a70ea12be8 | ||
|
fb5a3a53fa | ||
|
30eac56691 | ||
|
cb6f3a0836 | ||
|
8e579024b1 | ||
|
41c70293df | ||
|
4b015903bc |
@ -10,7 +10,9 @@ nobase_dist_js_DATA = \
|
|||||||
misc/history.js \
|
misc/history.js \
|
||||||
misc/modemManager.js \
|
misc/modemManager.js \
|
||||||
misc/params.js \
|
misc/params.js \
|
||||||
|
misc/semantic.js \
|
||||||
misc/util.js \
|
misc/util.js \
|
||||||
|
misc/zeitgeist.js \
|
||||||
perf/core.js \
|
perf/core.js \
|
||||||
ui/altTab.js \
|
ui/altTab.js \
|
||||||
ui/appDisplay.js \
|
ui/appDisplay.js \
|
||||||
@ -22,7 +24,6 @@ nobase_dist_js_DATA = \
|
|||||||
ui/dash.js \
|
ui/dash.js \
|
||||||
ui/dateMenu.js \
|
ui/dateMenu.js \
|
||||||
ui/dnd.js \
|
ui/dnd.js \
|
||||||
ui/docDisplay.js \
|
|
||||||
ui/endSessionDialog.js \
|
ui/endSessionDialog.js \
|
||||||
ui/environment.js \
|
ui/environment.js \
|
||||||
ui/extensionSystem.js \
|
ui/extensionSystem.js \
|
||||||
@ -64,4 +65,5 @@ nobase_dist_js_DATA = \
|
|||||||
ui/workspaceThumbnail.js \
|
ui/workspaceThumbnail.js \
|
||||||
ui/workspacesView.js \
|
ui/workspacesView.js \
|
||||||
ui/workspaceSwitcherPopup.js \
|
ui/workspaceSwitcherPopup.js \
|
||||||
ui/xdndHandler.js
|
ui/xdndHandler.js \
|
||||||
|
ui/zeitgeistSearch.js
|
||||||
|
@ -1,36 +1,32 @@
|
|||||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
|
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
const Shell = imports.gi.Shell;
|
|
||||||
const Lang = imports.lang;
|
|
||||||
const Signals = imports.signals;
|
|
||||||
const Search = imports.ui.search;
|
const Search = imports.ui.search;
|
||||||
|
|
||||||
const THUMBNAIL_ICON_MARGIN = 2;
|
function ZeitgeistItemInfo(event) {
|
||||||
|
this._init(event);
|
||||||
function DocInfo(recentInfo) {
|
|
||||||
this._init(recentInfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DocInfo.prototype = {
|
ZeitgeistItemInfo.prototype = {
|
||||||
_init : function(recentInfo) {
|
_init : function(event) {
|
||||||
this.recentInfo = recentInfo;
|
this.event = event;
|
||||||
// We actually used get_modified() instead of get_visited()
|
this.subject = event.subjects[0];
|
||||||
// here, as GtkRecentInfo doesn't updated get_visited()
|
this.timestamp = event.timestamp;
|
||||||
// correctly. See http://bugzilla.gnome.org/show_bug.cgi?id=567094
|
this.name = this.subject.text;
|
||||||
this.timestamp = recentInfo.get_modified();
|
|
||||||
this.name = recentInfo.get_display_name();
|
|
||||||
this._lowerName = this.name.toLowerCase();
|
this._lowerName = this.name.toLowerCase();
|
||||||
this.uri = recentInfo.get_uri();
|
this.uri = this.subject.uri;
|
||||||
this.mimeType = recentInfo.get_mime_type();
|
this.mimeType = this.subject.mimetype;
|
||||||
|
this.interpretation = this.subject.interpretation;
|
||||||
},
|
},
|
||||||
|
|
||||||
createIcon : function(size) {
|
createIcon : function(size) {
|
||||||
return St.TextureCache.get_default().load_recent_thumbnail(size, this.recentInfo);
|
return St.TextureCache.get_default().load_thumbnail(size, this.uri, this.subject.mimetype);
|
||||||
|
// FIXME: We should consider caching icons
|
||||||
},
|
},
|
||||||
|
|
||||||
launch : function(workspaceIndex) {
|
launch : function() {
|
||||||
Shell.DocSystem.get_default().open(this.recentInfo, workspaceIndex);
|
Gio.app_info_launch_default_for_uri(this.uri,
|
||||||
|
global.create_app_launch_context());
|
||||||
},
|
},
|
||||||
|
|
||||||
matchTerms: function(terms) {
|
matchTerms: function(terms) {
|
||||||
@ -48,93 +44,5 @@ DocInfo.prototype = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return mtype;
|
return mtype;
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
var docManagerInstance = null;
|
|
||||||
|
|
||||||
function getDocManager() {
|
|
||||||
if (docManagerInstance == null)
|
|
||||||
docManagerInstance = new DocManager();
|
|
||||||
return docManagerInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DocManager wraps the DocSystem, primarily to expose DocInfo objects.
|
|
||||||
*/
|
|
||||||
function DocManager() {
|
|
||||||
this._init();
|
|
||||||
}
|
|
||||||
|
|
||||||
DocManager.prototype = {
|
|
||||||
_init: function() {
|
|
||||||
this._docSystem = Shell.DocSystem.get_default();
|
|
||||||
this._infosByTimestamp = [];
|
|
||||||
this._infosByUri = {};
|
|
||||||
this._docSystem.connect('changed', Lang.bind(this, this._reload));
|
|
||||||
this._reload();
|
|
||||||
},
|
|
||||||
|
|
||||||
_reload: function() {
|
|
||||||
let docs = this._docSystem.get_all();
|
|
||||||
this._infosByTimestamp = [];
|
|
||||||
this._infosByUri = {};
|
|
||||||
for (let i = 0; i < docs.length; i++) {
|
|
||||||
let recentInfo = docs[i];
|
|
||||||
|
|
||||||
let docInfo = new DocInfo(recentInfo);
|
|
||||||
this._infosByTimestamp.push(docInfo);
|
|
||||||
this._infosByUri[docInfo.uri] = docInfo;
|
|
||||||
}
|
|
||||||
this.emit('changed');
|
|
||||||
},
|
|
||||||
|
|
||||||
getTimestampOrderedInfos: function() {
|
|
||||||
return this._infosByTimestamp;
|
|
||||||
},
|
|
||||||
|
|
||||||
getInfosByUri: function() {
|
|
||||||
return this._infosByUri;
|
|
||||||
},
|
|
||||||
|
|
||||||
lookupByUri: function(uri) {
|
|
||||||
return this._infosByUri[uri];
|
|
||||||
},
|
|
||||||
|
|
||||||
queueExistenceCheck: function(count) {
|
|
||||||
return this._docSystem.queue_existence_check(count);
|
|
||||||
},
|
|
||||||
|
|
||||||
_searchDocs: function(items, terms) {
|
|
||||||
let multiplePrefixMatches = [];
|
|
||||||
let prefixMatches = [];
|
|
||||||
let multipleSubtringMatches = [];
|
|
||||||
let substringMatches = [];
|
|
||||||
for (let i = 0; i < items.length; i++) {
|
|
||||||
let item = items[i];
|
|
||||||
let mtype = item.matchTerms(terms);
|
|
||||||
if (mtype == Search.MatchType.MULTIPLE_PREFIX)
|
|
||||||
multiplePrefixMatches.push(item.uri);
|
|
||||||
else if (mtype == Search.MatchType.PREFIX)
|
|
||||||
prefixMatches.push(item.uri);
|
|
||||||
else if (mtype == Search.MatchType.MULTIPLE_SUBSTRING)
|
|
||||||
multipleSubtringMatches.push(item.uri);
|
|
||||||
else if (mtype == Search.MatchType.SUBSTRING)
|
|
||||||
substringMatches.push(item.uri);
|
|
||||||
}
|
|
||||||
return multiplePrefixMatches.concat(prefixMatches.concat(multipleSubtringMatches.concat(substringMatches)));
|
|
||||||
},
|
|
||||||
|
|
||||||
initialSearch: function(terms) {
|
|
||||||
return this._searchDocs(this._infosByTimestamp, terms);
|
|
||||||
},
|
|
||||||
|
|
||||||
subsearch: function(previousResults, terms) {
|
|
||||||
return this._searchDocs(previousResults.map(Lang.bind(this,
|
|
||||||
function(url) {
|
|
||||||
return this._infosByUri[url];
|
|
||||||
})), terms);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Signals.addSignalMethods(DocManager.prototype);
|
|
||||||
|
43
js/misc/semantic.js
Normal file
43
js/misc/semantic.js
Normal file
@ -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 <federico@gnome.org>
|
||||||
|
*
|
||||||
|
* 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";
|
264
js/misc/zeitgeist.js
Normal file
264
js/misc/zeitgeist.js
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Seif Lotfy <seif@lotfy.com>
|
||||||
|
* Copyright (C) 2011 Siegfried-Angel Gevatter Pujals <siegfried@gevatter.com>
|
||||||
|
* Copyright (C) 2010-2011 Collabora Ltd.
|
||||||
|
* Authored by: Seif Lotfy <seif@lotfy.com>
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
// It's unfortunate to have to define these by hand; maybe if D-Bus had a way to introspect enums...
|
||||||
|
MOST_RECENT_EVENTS : 0,
|
||||||
|
LEAST_RECENT_EVENTS : 1,
|
||||||
|
MOST_RECENT_SUBJECTS : 2,
|
||||||
|
LEAST_RECENT_SUBJECTS : 3,
|
||||||
|
MOST_POPULAR_SUBJECTS : 4,
|
||||||
|
LEAST_POPULAR_SUBJECTS : 5,
|
||||||
|
MOST_POPULAR_ACTOR : 6,
|
||||||
|
LEAST_POPULAR_ACTOR : 7,
|
||||||
|
MOST_RECENT_ACTOR : 8,
|
||||||
|
LEAST_RECENT_ACTOR : 9,
|
||||||
|
MOST_RECENT_ORIGIN : 10,
|
||||||
|
LEAST_RECENT_ORIGIN : 11,
|
||||||
|
MOST_POPULAR_ORIGIN : 12,
|
||||||
|
LEAST_POPULAR_ORIGIN : 13,
|
||||||
|
OLDEST_ACTOR : 14,
|
||||||
|
MOST_RECENT_SUBJECT_INTERPRETATION : 15,
|
||||||
|
LEAST_RECENT_SUBJECT_INTERPRETATION : 16,
|
||||||
|
MOST_POPULAR_SUBJECT_INTERPRETATION : 17,
|
||||||
|
LEAST_POPULAR_SUBJECT_INTERPRETATION : 18,
|
||||||
|
MOST_RECENT_MIME_TYPE : 19,
|
||||||
|
LEAST_RECENT_MIME_TYPE : 20,
|
||||||
|
MOST_POPULAR_MIME_TYPE : 21,
|
||||||
|
LEAST_POPULAR_MIME_TYPE : 22
|
||||||
|
};
|
||||||
|
|
||||||
|
const StorageState = {
|
||||||
|
// http://zeitgeist-project.com/docs/0.6/datamodel.html#storagestate
|
||||||
|
// As with ResultType, it would be nice if we could introspect enums through D-Bus
|
||||||
|
NOT_AVAILABLE : 0,
|
||||||
|
AVAILABLE : 1,
|
||||||
|
ANY : 2
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 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 = parseInt(rawEvent[0][1], 10); // timestamp - it comes as a string over d-bus (yuck)
|
||||||
|
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);
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
const GLib = imports.gi.GLib;
|
const GLib = imports.gi.GLib;
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
const Gtk = imports.gi.Gtk;
|
const Gtk = imports.gi.Gtk;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
@ -13,6 +14,7 @@ const _ = Gettext.gettext;
|
|||||||
|
|
||||||
const AppFavorites = imports.ui.appFavorites;
|
const AppFavorites = imports.ui.appFavorites;
|
||||||
const DND = imports.ui.dnd;
|
const DND = imports.ui.dnd;
|
||||||
|
const DocInfo = imports.misc.docInfo;
|
||||||
const IconGrid = imports.ui.iconGrid;
|
const IconGrid = imports.ui.iconGrid;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Overview = imports.ui.overview;
|
const Overview = imports.ui.overview;
|
||||||
@ -21,6 +23,7 @@ const Search = imports.ui.search;
|
|||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
const Workspace = imports.ui.workspace;
|
const Workspace = imports.ui.workspace;
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
|
const Zeitgeist = imports.misc.zeitgeist;
|
||||||
|
|
||||||
const MENU_POPUP_TIMEOUT = 600;
|
const MENU_POPUP_TIMEOUT = 600;
|
||||||
const SCROLL_TIME = 0.1;
|
const SCROLL_TIME = 0.1;
|
||||||
@ -582,6 +585,7 @@ AppIconMenu.prototype = {
|
|||||||
this.blockSourceEvents = true;
|
this.blockSourceEvents = true;
|
||||||
|
|
||||||
this._source = source;
|
this._source = source;
|
||||||
|
this._eventTemplate = new Zeitgeist.Event('', '', "application://" + this._source.app.get_id(), [], []);
|
||||||
|
|
||||||
this.connect('activate', Lang.bind(this, this._onActivate));
|
this.connect('activate', Lang.bind(this, this._onActivate));
|
||||||
this.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged));
|
this.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged));
|
||||||
@ -628,6 +632,63 @@ AppIconMenu.prototype = {
|
|||||||
this._toggleFavoriteMenuItem = this._appendMenuItem(isFavorite ? _("Remove from Favorites")
|
this._toggleFavoriteMenuItem = this._appendMenuItem(isFavorite ? _("Remove from Favorites")
|
||||||
: _("Add to Favorites"));
|
: _("Add to Favorites"));
|
||||||
|
|
||||||
|
Zeitgeist.findEvents([new Date().getTime() - 86400000*90, Zeitgeist.MAX_TIMESTAMP],
|
||||||
|
[this._eventTemplate],
|
||||||
|
Zeitgeist.StorageState.ANY,
|
||||||
|
100,
|
||||||
|
Zeitgeist.ResultType.MOST_RECENT_SUBJECTS,
|
||||||
|
Lang.bind(this, this._appendJumplist));
|
||||||
|
},
|
||||||
|
|
||||||
|
_appendJumplist: function (events) {
|
||||||
|
let fetchedUris = [];
|
||||||
|
let hasJumplist = false;
|
||||||
|
|
||||||
|
function appendEvents(events2, count, type) {
|
||||||
|
if (count == null) {
|
||||||
|
count = 3;
|
||||||
|
}
|
||||||
|
if (type == null) {
|
||||||
|
type = "emblem-favorite";
|
||||||
|
}
|
||||||
|
let j = 0;
|
||||||
|
if (events.length > 0) {
|
||||||
|
for (let i in events) {
|
||||||
|
let uri = events[i].subjects[0].uri.replace('file://', '');
|
||||||
|
uri = uri.replace(/\%20/g, ' '); // FIXME: properly unescape, or get the display name otherwise
|
||||||
|
if (fetchedUris.indexOf(uri) == -1 &&
|
||||||
|
(GLib.file_test(uri, GLib.FileTest.EXISTS) || this._source.app.get_id() == "tomboy.desktop")) {
|
||||||
|
if (!hasJumplist) {
|
||||||
|
this._appendSeparator();
|
||||||
|
hasJumplist = true;
|
||||||
|
}
|
||||||
|
this._appendJumplistItem(events[i], type);
|
||||||
|
fetchedUris.push(uri);
|
||||||
|
j++;
|
||||||
|
if (j >= count)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
appendEvents.call(this, events, 4, "document-open-recent");
|
||||||
|
Zeitgeist.findEvents([new Date().getTime() - 86400000*90, Zeitgeist.MAX_TIMESTAMP],
|
||||||
|
[this._eventTemplate],
|
||||||
|
Zeitgeist.StorageState.ANY,
|
||||||
|
100,
|
||||||
|
Zeitgeist.ResultType.MOST_POPULAR_SUBJECTS,
|
||||||
|
Lang.bind(this, appendEvents));
|
||||||
|
},
|
||||||
|
|
||||||
|
_appendJumplistItem: function (event, type) {
|
||||||
|
let info = new DocInfo.ZeitgeistItemInfo(event);
|
||||||
|
let item = new PopupMenu.PopupImageMenuItem(info.name, type);
|
||||||
|
this.addMenuItem(item);
|
||||||
|
item.connect('activate', Lang.bind(this, function () {
|
||||||
|
let app = new Gio.DesktopAppInfo.new(this._source.app.get_id());
|
||||||
|
app.launch_uris([info.uri], null);
|
||||||
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
_appendSeparator: function () {
|
_appendSeparator: function () {
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
||||||
|
|
||||||
const Gettext = imports.gettext.domain('gnome-shell');
|
|
||||||
const _ = Gettext.gettext;
|
|
||||||
|
|
||||||
const DocInfo = imports.misc.docInfo;
|
|
||||||
const Params = imports.misc.params;
|
|
||||||
const Search = imports.ui.search;
|
|
||||||
|
|
||||||
|
|
||||||
function DocSearchProvider() {
|
|
||||||
this._init();
|
|
||||||
}
|
|
||||||
|
|
||||||
DocSearchProvider.prototype = {
|
|
||||||
__proto__: Search.SearchProvider.prototype,
|
|
||||||
|
|
||||||
_init: function(name) {
|
|
||||||
Search.SearchProvider.prototype._init.call(this, _("RECENT ITEMS"));
|
|
||||||
this._docManager = DocInfo.getDocManager();
|
|
||||||
},
|
|
||||||
|
|
||||||
getResultMeta: function(resultId) {
|
|
||||||
let docInfo = this._docManager.lookupByUri(resultId);
|
|
||||||
if (!docInfo)
|
|
||||||
return null;
|
|
||||||
return { 'id': resultId,
|
|
||||||
'name': docInfo.name,
|
|
||||||
'createIcon': function(size) {
|
|
||||||
return docInfo.createIcon(size);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
activateResult: function(id, params) {
|
|
||||||
params = Params.parse(params, { workspace: null,
|
|
||||||
timestamp: null });
|
|
||||||
|
|
||||||
let docInfo = this._docManager.lookupByUri(id);
|
|
||||||
docInfo.launch(params.workspace ? params.workspace.index() : -1);
|
|
||||||
},
|
|
||||||
|
|
||||||
getInitialResultSet: function(terms) {
|
|
||||||
return this._docManager.initialSearch(terms);
|
|
||||||
},
|
|
||||||
|
|
||||||
getSubsearchResultSet: function(previousResults, terms) {
|
|
||||||
return this._docManager.subsearch(previousResults, terms);
|
|
||||||
}
|
|
||||||
};
|
|
@ -26,11 +26,13 @@ var commandHeader = 'const Clutter = imports.gi.Clutter; ' +
|
|||||||
'const Gtk = imports.gi.Gtk; ' +
|
'const Gtk = imports.gi.Gtk; ' +
|
||||||
'const Mainloop = imports.mainloop; ' +
|
'const Mainloop = imports.mainloop; ' +
|
||||||
'const Meta = imports.gi.Meta; ' +
|
'const Meta = imports.gi.Meta; ' +
|
||||||
|
'const Semantic = imports.misc.semantic' +
|
||||||
'const Shell = imports.gi.Shell; ' +
|
'const Shell = imports.gi.Shell; ' +
|
||||||
'const Tp = imports.gi.TelepathyGLib; ' +
|
'const Tp = imports.gi.TelepathyGLib; ' +
|
||||||
'const Main = imports.ui.main; ' +
|
'const Main = imports.ui.main; ' +
|
||||||
'const Lang = imports.lang; ' +
|
'const Lang = imports.lang; ' +
|
||||||
'const Tweener = imports.ui.tweener; ' +
|
'const Tweener = imports.ui.tweener; ' +
|
||||||
|
'const Zeitgeist = imports.misc.zeitgeist; ' +
|
||||||
/* Utility functions...we should probably be able to use these
|
/* Utility functions...we should probably be able to use these
|
||||||
* in the shell core code too. */
|
* in the shell core code too. */
|
||||||
'const stage = global.stage; ' +
|
'const stage = global.stage; ' +
|
||||||
|
@ -15,7 +15,6 @@ const Gdk = imports.gi.Gdk;
|
|||||||
const AppDisplay = imports.ui.appDisplay;
|
const AppDisplay = imports.ui.appDisplay;
|
||||||
const Dash = imports.ui.dash;
|
const Dash = imports.ui.dash;
|
||||||
const DND = imports.ui.dnd;
|
const DND = imports.ui.dnd;
|
||||||
const DocDisplay = imports.ui.docDisplay;
|
|
||||||
const Lightbox = imports.ui.lightbox;
|
const Lightbox = imports.ui.lightbox;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const MessageTray = imports.ui.messageTray;
|
const MessageTray = imports.ui.messageTray;
|
||||||
@ -25,6 +24,7 @@ const Tweener = imports.ui.tweener;
|
|||||||
const ViewSelector = imports.ui.viewSelector;
|
const ViewSelector = imports.ui.viewSelector;
|
||||||
const WorkspacesView = imports.ui.workspacesView;
|
const WorkspacesView = imports.ui.workspacesView;
|
||||||
const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
|
const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
|
||||||
|
const ZeitgeistSearch = imports.ui.zeitgeistSearch;
|
||||||
|
|
||||||
// Time for initial animation going into Overview mode
|
// Time for initial animation going into Overview mode
|
||||||
const ANIMATION_TIME = 0.25;
|
const ANIMATION_TIME = 0.25;
|
||||||
@ -192,7 +192,11 @@ Overview.prototype = {
|
|||||||
this.viewSelector.addSearchProvider(new AppDisplay.AppSearchProvider());
|
this.viewSelector.addSearchProvider(new AppDisplay.AppSearchProvider());
|
||||||
this.viewSelector.addSearchProvider(new AppDisplay.PrefsSearchProvider());
|
this.viewSelector.addSearchProvider(new AppDisplay.PrefsSearchProvider());
|
||||||
this.viewSelector.addSearchProvider(new PlaceDisplay.PlaceSearchProvider());
|
this.viewSelector.addSearchProvider(new PlaceDisplay.PlaceSearchProvider());
|
||||||
this.viewSelector.addSearchProvider(new DocDisplay.DocSearchProvider());
|
this.viewSelector.addSearchProvider(new ZeitgeistSearch.DocumentsAsyncSearchProvider());
|
||||||
|
this.viewSelector.addSearchProvider(new ZeitgeistSearch.VideosAsyncSearchProvider());
|
||||||
|
this.viewSelector.addSearchProvider(new ZeitgeistSearch.MusicAsyncSearchProvider());
|
||||||
|
this.viewSelector.addSearchProvider(new ZeitgeistSearch.PicturesAsyncSearchProvider());
|
||||||
|
this.viewSelector.addSearchProvider(new ZeitgeistSearch.OtherAsyncSearchProvider());
|
||||||
|
|
||||||
// TODO - recalculate everything when desktop size changes
|
// TODO - recalculate everything when desktop size changes
|
||||||
this.dash = new Dash.Dash();
|
this.dash = new Dash.Dash();
|
||||||
|
@ -115,6 +115,43 @@ function SearchProvider(title) {
|
|||||||
SearchProvider.prototype = {
|
SearchProvider.prototype = {
|
||||||
_init: function(title) {
|
_init: function(title) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
|
this.searchSystem = null;
|
||||||
|
this.searchAsync = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
_asyncCancelled: function() {
|
||||||
|
},
|
||||||
|
|
||||||
|
startAsync: function() {
|
||||||
|
this.searchAsync = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
tryCancelAsync: function() {
|
||||||
|
if (!this.searchAsync)
|
||||||
|
return;
|
||||||
|
this._asyncCancelled();
|
||||||
|
this.searchAsync = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* addItems:
|
||||||
|
* @items: an array of result identifier strings representing
|
||||||
|
* items which match the last given search terms.
|
||||||
|
*
|
||||||
|
* This should be used for something that requires a bit more
|
||||||
|
* logic; it's designed to be an asyncronous way to add a result
|
||||||
|
* to the current search.
|
||||||
|
*/
|
||||||
|
addItems: function( items) {
|
||||||
|
if (!this.searchSystem)
|
||||||
|
throw new Error('Search provider not registered');
|
||||||
|
|
||||||
|
if (!items.length)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.tryCancelAsync();
|
||||||
|
|
||||||
|
this.searchSystem.addProviderItems(this, items);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -212,6 +249,7 @@ SearchProvider.prototype = {
|
|||||||
};
|
};
|
||||||
Signals.addSignalMethods(SearchProvider.prototype);
|
Signals.addSignalMethods(SearchProvider.prototype);
|
||||||
|
|
||||||
|
|
||||||
function OpenSearchSystem() {
|
function OpenSearchSystem() {
|
||||||
this._init();
|
this._init();
|
||||||
}
|
}
|
||||||
@ -324,6 +362,7 @@ SearchSystem.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
registerProvider: function (provider) {
|
registerProvider: function (provider) {
|
||||||
|
provider.searchSystem = this;
|
||||||
this._providers.push(provider);
|
this._providers.push(provider);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -340,30 +379,50 @@ SearchSystem.prototype = {
|
|||||||
this._previousResults = [];
|
this._previousResults = [];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
addProviderItems: function(provider, items) {
|
||||||
|
let index = this._providers.indexOf(provider);
|
||||||
|
let [provider2, results] = this._previousResults[index];
|
||||||
|
if (provider !== provider2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
results.push.apply(results, items);
|
||||||
|
this.emit('results-updated', this._previousResults);
|
||||||
|
},
|
||||||
|
|
||||||
updateSearch: function(searchString) {
|
updateSearch: function(searchString) {
|
||||||
searchString = searchString.replace(/^\s+/g, '').replace(/\s+$/g, '');
|
searchString = searchString.replace(/^\s+/g, '').replace(/\s+$/g, '');
|
||||||
if (searchString == '')
|
if (searchString == '')
|
||||||
return [];
|
return;
|
||||||
|
|
||||||
let terms = searchString.split(/\s+/);
|
let terms = searchString.split(/\s+/);
|
||||||
let isSubSearch = terms.length == this._previousTerms.length;
|
this.updateSearchResults(terms);
|
||||||
if (isSubSearch) {
|
},
|
||||||
for (let i = 0; i < terms.length; i++) {
|
|
||||||
if (terms[i].indexOf(this._previousTerms[i]) != 0) {
|
updateSearchResults: function(terms) {
|
||||||
isSubSearch = false;
|
let isSubSearch = false;
|
||||||
break;
|
|
||||||
|
if (terms) {
|
||||||
|
isSubSearch = terms.length == this._previousTerms.length;
|
||||||
|
if (isSubSearch) {
|
||||||
|
for (let i = 0; i < terms.length; i++) {
|
||||||
|
if (terms[i].indexOf(this._previousTerms[i]) != 0) {
|
||||||
|
isSubSearch = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
terms = this._previousTerms;
|
||||||
}
|
}
|
||||||
|
|
||||||
let results = [];
|
let results = [];
|
||||||
if (isSubSearch) {
|
if (isSubSearch) {
|
||||||
for (let i = 0; i < this._previousResults.length; i++) {
|
for (let i = 0; i < this._providers.length; i++) {
|
||||||
let [provider, previousResults] = this._previousResults[i];
|
let [provider, previousResults] = this._previousResults[i];
|
||||||
|
provider.tryCancelAsync();
|
||||||
try {
|
try {
|
||||||
let providerResults = provider.getSubsearchResultSet(previousResults, terms);
|
let providerResults = provider.getSubsearchResultSet(previousResults, terms);
|
||||||
if (providerResults.length > 0)
|
results.push([provider, providerResults]);
|
||||||
results.push([provider, providerResults]);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
global.log ('A ' + error.name + ' has occured in ' + provider.title + ': ' + error.message);
|
global.log ('A ' + error.name + ' has occured in ' + provider.title + ': ' + error.message);
|
||||||
}
|
}
|
||||||
@ -371,10 +430,10 @@ SearchSystem.prototype = {
|
|||||||
} else {
|
} else {
|
||||||
for (let i = 0; i < this._providers.length; i++) {
|
for (let i = 0; i < this._providers.length; i++) {
|
||||||
let provider = this._providers[i];
|
let provider = this._providers[i];
|
||||||
|
provider.tryCancelAsync();
|
||||||
try {
|
try {
|
||||||
let providerResults = provider.getInitialResultSet(terms);
|
let providerResults = provider.getInitialResultSet(terms);
|
||||||
if (providerResults.length > 0)
|
results.push([provider, providerResults]);
|
||||||
results.push([provider, providerResults]);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
global.log ('A ' + error.name + ' has occured in ' + provider.title + ': ' + error.message);
|
global.log ('A ' + error.name + ' has occured in ' + provider.title + ': ' + error.message);
|
||||||
}
|
}
|
||||||
@ -383,8 +442,7 @@ SearchSystem.prototype = {
|
|||||||
|
|
||||||
this._previousTerms = terms;
|
this._previousTerms = terms;
|
||||||
this._previousResults = results;
|
this._previousResults = results;
|
||||||
|
this.emit('results-updated', results);
|
||||||
return results;
|
},
|
||||||
}
|
|
||||||
};
|
};
|
||||||
Signals.addSignalMethods(SearchSystem.prototype);
|
Signals.addSignalMethods(SearchSystem.prototype);
|
||||||
|
@ -182,6 +182,7 @@ function SearchResults(searchSystem, openSearchSystem) {
|
|||||||
SearchResults.prototype = {
|
SearchResults.prototype = {
|
||||||
_init: function(searchSystem, openSearchSystem) {
|
_init: function(searchSystem, openSearchSystem) {
|
||||||
this._searchSystem = searchSystem;
|
this._searchSystem = searchSystem;
|
||||||
|
this._searchSystem.connect('results-updated', Lang.bind(this, this._updateResults));
|
||||||
this._openSearchSystem = openSearchSystem;
|
this._openSearchSystem = openSearchSystem;
|
||||||
|
|
||||||
this.actor = new St.BoxLayout({ name: 'searchResults',
|
this.actor = new St.BoxLayout({ name: 'searchResults',
|
||||||
@ -216,9 +217,11 @@ SearchResults.prototype = {
|
|||||||
this._selectedProvider = -1;
|
this._selectedProvider = -1;
|
||||||
this._providers = this._searchSystem.getProviders();
|
this._providers = this._searchSystem.getProviders();
|
||||||
this._providerMeta = [];
|
this._providerMeta = [];
|
||||||
for (let i = 0; i < this._providers.length; i++)
|
this._providerMetaResults = {};
|
||||||
|
for (let i = 0; i < this._providers.length; i++) {
|
||||||
this.createProviderMeta(this._providers[i]);
|
this.createProviderMeta(this._providers[i]);
|
||||||
|
this._providerMetaResults[this.providers[i].title] = [];
|
||||||
|
}
|
||||||
this._searchProvidersBox = new St.BoxLayout({ style_class: 'search-providers-box' });
|
this._searchProvidersBox = new St.BoxLayout({ style_class: 'search-providers-box' });
|
||||||
this.actor.add(this._searchProvidersBox);
|
this.actor.add(this._searchProvidersBox);
|
||||||
|
|
||||||
@ -297,6 +300,12 @@ SearchResults.prototype = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_clearDisplayForProvider: function(index) {
|
||||||
|
let meta = this._providerMeta[index];
|
||||||
|
meta.resultDisplay.clear();
|
||||||
|
meta.actor.hide();
|
||||||
|
},
|
||||||
|
|
||||||
reset: function() {
|
reset: function() {
|
||||||
this._searchSystem.reset();
|
this._searchSystem.reset();
|
||||||
this._statusText.hide();
|
this._statusText.hide();
|
||||||
@ -311,15 +320,15 @@ SearchResults.prototype = {
|
|||||||
this._statusText.show();
|
this._statusText.show();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
doSearch: function (searchString) {
|
||||||
|
this._searchSystem.updateSearch(searchString);
|
||||||
|
},
|
||||||
|
|
||||||
_metaForProvider: function(provider) {
|
_metaForProvider: function(provider) {
|
||||||
return this._providerMeta[this._providers.indexOf(provider)];
|
return this._providerMeta[this._providers.indexOf(provider)];
|
||||||
},
|
},
|
||||||
|
|
||||||
updateSearch: function (searchString) {
|
_updateResults: function(searchSystem, results) {
|
||||||
let results = this._searchSystem.updateSearch(searchString);
|
|
||||||
|
|
||||||
this._clearDisplay();
|
|
||||||
|
|
||||||
if (results.length == 0) {
|
if (results.length == 0) {
|
||||||
this._statusText.set_text(_("No matching results."));
|
this._statusText.set_text(_("No matching results."));
|
||||||
this._statusText.show();
|
this._statusText.show();
|
||||||
@ -329,14 +338,22 @@ SearchResults.prototype = {
|
|||||||
this._statusText.hide();
|
this._statusText.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
let terms = this._searchSystem.getTerms();
|
let terms = searchSystem.getTerms();
|
||||||
this._openSearchSystem.setSearchTerms(terms);
|
this._openSearchSystem.setSearchTerms(terms);
|
||||||
|
|
||||||
for (let i = 0; i < results.length; i++) {
|
for (let i = 0; i < results.length; i++) {
|
||||||
let [provider, providerResults] = results[i];
|
let [provider, providerResults] = results[i];
|
||||||
let meta = this._metaForProvider(provider);
|
if (providerResults.length == 0)
|
||||||
meta.actor.show();
|
this._clearDisplayForProvider(i)
|
||||||
meta.resultDisplay.renderResults(providerResults, terms);
|
else {
|
||||||
|
if (this._providerMetaResults[provider.title] != providerResults) {
|
||||||
|
this._providerMetaResults[provider.title] = providerResults;
|
||||||
|
this._clearDisplayForProvider(i);
|
||||||
|
let meta = this._metaForProvider(provider);
|
||||||
|
meta.actor.show();
|
||||||
|
meta.resultDisplay.renderResults(providerResults, terms);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._selectedOpenSearchButton == -1)
|
if (this._selectedOpenSearchButton == -1)
|
||||||
|
@ -290,7 +290,7 @@ SearchTab.prototype = {
|
|||||||
_doSearch: function () {
|
_doSearch: function () {
|
||||||
this._searchTimeoutId = 0;
|
this._searchTimeoutId = 0;
|
||||||
let text = this._text.get_text().replace(/^\s+/g, '').replace(/\s+$/g, '');
|
let text = this._text.get_text().replace(/^\s+/g, '').replace(/\s+$/g, '');
|
||||||
this._searchResults.updateSearch(text);
|
this._searchResults.doSearch(text);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
202
js/ui/zeitgeistSearch.js
Normal file
202
js/ui/zeitgeistSearch.js
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Seif Lotfy <seif@lotfy.com>
|
||||||
|
* Copyright (C) 2011 Siegfried-Angel Gevatter Pujals <siegfried@gevatter.com>
|
||||||
|
* Copyright (C) 2010-2011 Collabora Ltd.
|
||||||
|
* Authored by: Seif Lotfy <seif@lotfy.com>
|
||||||
|
*
|
||||||
|
* 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 Lang = imports.lang;
|
||||||
|
const GLib = imports.gi.GLib;
|
||||||
|
const Gio = imports.gi.Gio
|
||||||
|
const Semantic = imports.misc.semantic;
|
||||||
|
const Zeitgeist = imports.misc.zeitgeist;
|
||||||
|
|
||||||
|
const Gettext = imports.gettext.domain('gnome-shell');
|
||||||
|
const _ = Gettext.gettext;
|
||||||
|
|
||||||
|
const DocInfo = imports.misc.docInfo;
|
||||||
|
const Search = imports.ui.search;
|
||||||
|
|
||||||
|
// FIXME: The subject cache is never being emptied.
|
||||||
|
let ZeitgeistSubjectCache = {};
|
||||||
|
|
||||||
|
function ZeitgeistAsyncSearchProvider(title, interpretations) {
|
||||||
|
this._init(title, interpretations);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZeitgeistAsyncSearchProvider.prototype = {
|
||||||
|
__proto__: Search.SearchProvider.prototype,
|
||||||
|
|
||||||
|
_init: function(title, interpretations) {
|
||||||
|
Search.SearchProvider.prototype._init.call(this, title);
|
||||||
|
this._buildTemplates(interpretations);
|
||||||
|
},
|
||||||
|
|
||||||
|
_buildTemplates: function(interpretations) {
|
||||||
|
this.templates = [];
|
||||||
|
for (let i = 0; i < interpretations.length; i++) {
|
||||||
|
let subject = new Zeitgeist.Subject('', interpretations[i], '', '', '', '', '');
|
||||||
|
let event = new Zeitgeist.Event('', '', '', [subject], []);
|
||||||
|
this.templates.push(event);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_search: function(terms) {
|
||||||
|
this._search_terms = terms;
|
||||||
|
Zeitgeist.fullTextSearch(terms[0]+'*',
|
||||||
|
this.templates,
|
||||||
|
Lang.bind(this, function(events) {
|
||||||
|
if (terms == this._search_terms)
|
||||||
|
this._asyncCallback(events);
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
_asyncCancelled: function() {
|
||||||
|
this._search_terms = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
getInitialResultSet: function(terms) {
|
||||||
|
this._search(terms);
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
|
||||||
|
getSubsearchResultSet: function(previousResults, terms) {
|
||||||
|
this.tryCancelAsync();
|
||||||
|
return this.getInitialResultSet(terms);
|
||||||
|
},
|
||||||
|
|
||||||
|
getResultMeta: function(resultId) {
|
||||||
|
return { 'id': ZeitgeistSubjectCache[resultId].uri,
|
||||||
|
'name': ZeitgeistSubjectCache[resultId].name,
|
||||||
|
'createIcon': function (size) {
|
||||||
|
return ZeitgeistSubjectCache[resultId].createIcon(size);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
activateResult: function(resultId) {
|
||||||
|
Gio.app_info_launch_default_for_uri(resultId,
|
||||||
|
global.create_app_launch_context());
|
||||||
|
},
|
||||||
|
|
||||||
|
_asyncCallback: function(events) {
|
||||||
|
let items = [];
|
||||||
|
for (let i = 0; i < events.length; i++) {
|
||||||
|
let event = events[i];
|
||||||
|
let subject = event.subjects[0];
|
||||||
|
let uri = subject.uri.replace('file://', '');
|
||||||
|
uri = GLib.uri_unescape_string(uri, '');
|
||||||
|
if (GLib.file_test(uri, GLib.FileTest.EXISTS)) {
|
||||||
|
if (!ZeitgeistSubjectCache.hasOwnProperty(subject.uri)) {
|
||||||
|
let info = new DocInfo.ZeitgeistItemInfo(event);
|
||||||
|
ZeitgeistSubjectCache[info.uri] = info;
|
||||||
|
}
|
||||||
|
items.push(subject.uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.addItems(items);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function DocumentsAsyncSearchProvider() {
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
DocumentsAsyncSearchProvider.prototype = {
|
||||||
|
__proto__: ZeitgeistAsyncSearchProvider.prototype,
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
let interpretations = [Semantic.NFO_DOCUMENT];
|
||||||
|
ZeitgeistAsyncSearchProvider.prototype._init.call(this, _("DOCUMENTS"), interpretations);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function VideosAsyncSearchProvider() {
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
VideosAsyncSearchProvider.prototype = {
|
||||||
|
__proto__: ZeitgeistAsyncSearchProvider.prototype,
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
let interpretations = [Semantic.NFO_VIDEO];
|
||||||
|
ZeitgeistAsyncSearchProvider.prototype._init.call(this, _("VIDEOS"), interpretations);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function MusicAsyncSearchProvider() {
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
MusicAsyncSearchProvider.prototype = {
|
||||||
|
__proto__: ZeitgeistAsyncSearchProvider.prototype,
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
let interpretations = [
|
||||||
|
Semantic.NFO_AUDIO,
|
||||||
|
Semantic.NMM_MUSIC_PIECE];
|
||||||
|
ZeitgeistAsyncSearchProvider.prototype._init.call(this, _("MUSIC"), interpretations);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function PicturesAsyncSearchProvider() {
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
PicturesAsyncSearchProvider.prototype = {
|
||||||
|
__proto__: ZeitgeistAsyncSearchProvider.prototype,
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
let interpretations = [Semantic.NFO_IMAGE];
|
||||||
|
ZeitgeistAsyncSearchProvider.prototype._init.call(this, _("PICTURES"), interpretations);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function OtherAsyncSearchProvider() {
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
OtherAsyncSearchProvider.prototype = {
|
||||||
|
__proto__: ZeitgeistAsyncSearchProvider.prototype,
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
let interpretations = [
|
||||||
|
'!' + Semantic.NFO_IMAGE,
|
||||||
|
'!' + Semantic.NFO_DOCUMENT,
|
||||||
|
'!' + Semantic.NFO_VIDEO,
|
||||||
|
'!' + Semantic.NFO_AUDIO,
|
||||||
|
'!' + Semantic.NMM_MUSIC_PIECE];
|
||||||
|
ZeitgeistAsyncSearchProvider.prototype._init.call(this, _("OTHER"), interpretations);
|
||||||
|
},
|
||||||
|
|
||||||
|
_buildTemplates: function(interpretations) {
|
||||||
|
// Here we want to get everything matching all of the templates, and
|
||||||
|
// not just any of them. Therefore we need to AND the interpretations
|
||||||
|
// instead of OR'ing them; this is done by having an Event with
|
||||||
|
// different Subjects.
|
||||||
|
this.templates = [];
|
||||||
|
let subjects = [];
|
||||||
|
for (let i = 0; i < interpretations.length; i++) {
|
||||||
|
let subject = new Zeitgeist.Subject('', interpretations[i], '', '', '', '', '');
|
||||||
|
subjects.push(subject);
|
||||||
|
}
|
||||||
|
let event = new Zeitgeist.Event('', '', '', subjects, []);
|
||||||
|
this.templates.push(event);
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user