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/modemManager.js	\ | ||||
| 	misc/params.js		\ | ||||
| 	misc/semantic.js	\ | ||||
| 	misc/util.js		\ | ||||
| 	misc/zeitgeist.js	\ | ||||
| 	perf/core.js		\ | ||||
| 	ui/altTab.js		\ | ||||
| 	ui/appDisplay.js	\ | ||||
| @@ -22,7 +24,6 @@ nobase_dist_js_DATA = 	\ | ||||
| 	ui/dash.js		\ | ||||
| 	ui/dateMenu.js		\ | ||||
| 	ui/dnd.js		\ | ||||
| 	ui/docDisplay.js	\ | ||||
| 	ui/endSessionDialog.js	\ | ||||
| 	ui/environment.js	\ | ||||
| 	ui/extensionSystem.js	\ | ||||
| @@ -64,4 +65,5 @@ nobase_dist_js_DATA = 	\ | ||||
| 	ui/workspaceThumbnail.js	\ | ||||
| 	ui/workspacesView.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 -*- */ | ||||
|  | ||||
| const St = imports.gi.St; | ||||
| const Shell = imports.gi.Shell; | ||||
| const Lang = imports.lang; | ||||
| const Signals = imports.signals; | ||||
| const Search = imports.ui.search; | ||||
|  | ||||
| const THUMBNAIL_ICON_MARGIN = 2; | ||||
|  | ||||
| function DocInfo(recentInfo) { | ||||
|     this._init(recentInfo); | ||||
| function ZeitgeistItemInfo(event) { | ||||
|     this._init(event); | ||||
| } | ||||
|  | ||||
| DocInfo.prototype = { | ||||
|     _init : function(recentInfo) { | ||||
|         this.recentInfo = recentInfo; | ||||
|         // We actually used get_modified() instead of get_visited() | ||||
|         // here, as GtkRecentInfo doesn't updated get_visited() | ||||
|         // correctly. See http://bugzilla.gnome.org/show_bug.cgi?id=567094 | ||||
|         this.timestamp = recentInfo.get_modified(); | ||||
|         this.name = recentInfo.get_display_name(); | ||||
| ZeitgeistItemInfo.prototype = { | ||||
|     _init : function(event) { | ||||
|         this.event = event; | ||||
|         this.subject = event.subjects[0]; | ||||
|         this.timestamp = event.timestamp; | ||||
|         this.name = this.subject.text; | ||||
|         this._lowerName = this.name.toLowerCase(); | ||||
|         this.uri = recentInfo.get_uri(); | ||||
|         this.mimeType = recentInfo.get_mime_type(); | ||||
|         this.uri = this.subject.uri; | ||||
|         this.mimeType = this.subject.mimetype; | ||||
|         this.interpretation = this.subject.interpretation; | ||||
|     }, | ||||
|  | ||||
|     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) { | ||||
|         Shell.DocSystem.get_default().open(this.recentInfo, workspaceIndex); | ||||
|     launch : function() { | ||||
|         Gio.app_info_launch_default_for_uri(this.uri, | ||||
|                                             global.create_app_launch_context()); | ||||
|     }, | ||||
|  | ||||
|     matchTerms: function(terms) { | ||||
| @@ -48,93 +44,5 @@ DocInfo.prototype = { | ||||
|             } | ||||
|         } | ||||
|         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 GLib = imports.gi.GLib; | ||||
| const Gio = imports.gi.Gio; | ||||
| const Gtk = imports.gi.Gtk; | ||||
| const Shell = imports.gi.Shell; | ||||
| const Lang = imports.lang; | ||||
| @@ -13,6 +14,7 @@ const _ = Gettext.gettext; | ||||
|  | ||||
| const AppFavorites = imports.ui.appFavorites; | ||||
| const DND = imports.ui.dnd; | ||||
| const DocInfo = imports.misc.docInfo; | ||||
| const IconGrid = imports.ui.iconGrid; | ||||
| const Main = imports.ui.main; | ||||
| const Overview = imports.ui.overview; | ||||
| @@ -21,6 +23,7 @@ const Search = imports.ui.search; | ||||
| const Tweener = imports.ui.tweener; | ||||
| const Workspace = imports.ui.workspace; | ||||
| const Params = imports.misc.params; | ||||
| const Zeitgeist = imports.misc.zeitgeist; | ||||
|  | ||||
| const MENU_POPUP_TIMEOUT = 600; | ||||
| const SCROLL_TIME = 0.1; | ||||
| @@ -582,6 +585,7 @@ AppIconMenu.prototype = { | ||||
|         this.blockSourceEvents = true; | ||||
|  | ||||
|         this._source = source; | ||||
|         this._eventTemplate = new Zeitgeist.Event('', '', "application://" + this._source.app.get_id(), [], []); | ||||
|  | ||||
|         this.connect('activate', Lang.bind(this, this._onActivate)); | ||||
|         this.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged)); | ||||
| @@ -628,6 +632,63 @@ AppIconMenu.prototype = { | ||||
|         this._toggleFavoriteMenuItem = this._appendMenuItem(isFavorite ? _("Remove from 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 () { | ||||
|   | ||||
| @@ -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 Mainloop = imports.mainloop; ' + | ||||
|                     'const Meta = imports.gi.Meta; ' + | ||||
|                     'const Semantic = imports.misc.semantic' + | ||||
|                     'const Shell = imports.gi.Shell; ' + | ||||
|                     'const Tp = imports.gi.TelepathyGLib; ' + | ||||
|                     '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; ' + | ||||
|   | ||||
| @@ -15,7 +15,6 @@ const Gdk = imports.gi.Gdk; | ||||
| const AppDisplay = imports.ui.appDisplay; | ||||
| const Dash = imports.ui.dash; | ||||
| const DND = imports.ui.dnd; | ||||
| const DocDisplay = imports.ui.docDisplay; | ||||
| const Lightbox = imports.ui.lightbox; | ||||
| const Main = imports.ui.main; | ||||
| const MessageTray = imports.ui.messageTray; | ||||
| @@ -25,6 +24,7 @@ const Tweener = imports.ui.tweener; | ||||
| const ViewSelector = imports.ui.viewSelector; | ||||
| const WorkspacesView = imports.ui.workspacesView; | ||||
| const WorkspaceThumbnail = imports.ui.workspaceThumbnail; | ||||
| const ZeitgeistSearch = imports.ui.zeitgeistSearch; | ||||
|  | ||||
| // Time for initial animation going into Overview mode | ||||
| const ANIMATION_TIME = 0.25; | ||||
| @@ -192,7 +192,11 @@ Overview.prototype = { | ||||
|         this.viewSelector.addSearchProvider(new AppDisplay.AppSearchProvider()); | ||||
|         this.viewSelector.addSearchProvider(new AppDisplay.PrefsSearchProvider()); | ||||
|         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 | ||||
|         this.dash = new Dash.Dash(); | ||||
|   | ||||
| @@ -115,6 +115,43 @@ function SearchProvider(title) { | ||||
| SearchProvider.prototype = { | ||||
|     _init: function(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); | ||||
|  | ||||
|  | ||||
| function OpenSearchSystem() { | ||||
|     this._init(); | ||||
| } | ||||
| @@ -324,6 +362,7 @@ SearchSystem.prototype = { | ||||
|     }, | ||||
|  | ||||
|     registerProvider: function (provider) { | ||||
|         provider.searchSystem = this; | ||||
|         this._providers.push(provider); | ||||
|     }, | ||||
|  | ||||
| @@ -340,30 +379,50 @@ SearchSystem.prototype = { | ||||
|         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) { | ||||
|         searchString = searchString.replace(/^\s+/g, '').replace(/\s+$/g, ''); | ||||
|         if (searchString == '') | ||||
|             return []; | ||||
|             return; | ||||
|  | ||||
|         let terms = searchString.split(/\s+/); | ||||
|         let 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; | ||||
|         this.updateSearchResults(terms); | ||||
|     }, | ||||
|  | ||||
|     updateSearchResults: function(terms) { | ||||
|         let isSubSearch = false; | ||||
|  | ||||
|         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 = []; | ||||
|         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]; | ||||
|                 provider.tryCancelAsync(); | ||||
|                 try { | ||||
|                     let providerResults = provider.getSubsearchResultSet(previousResults, terms); | ||||
|                     if (providerResults.length > 0) | ||||
|                         results.push([provider, providerResults]); | ||||
|                     results.push([provider, providerResults]); | ||||
|                 } catch (error) { | ||||
|                     global.log ('A ' + error.name + ' has occured in ' + provider.title + ': ' + error.message); | ||||
|                 } | ||||
| @@ -371,10 +430,10 @@ SearchSystem.prototype = { | ||||
|         } else { | ||||
|             for (let i = 0; i < this._providers.length; i++) { | ||||
|                 let provider = this._providers[i]; | ||||
|                 provider.tryCancelAsync(); | ||||
|                 try { | ||||
|                     let providerResults = provider.getInitialResultSet(terms); | ||||
|                     if (providerResults.length > 0) | ||||
|                         results.push([provider, providerResults]); | ||||
|                     results.push([provider, providerResults]); | ||||
|                 } catch (error) { | ||||
|                     global.log ('A ' + error.name + ' has occured in ' + provider.title + ': ' + error.message); | ||||
|                 } | ||||
| @@ -383,8 +442,7 @@ SearchSystem.prototype = { | ||||
|  | ||||
|         this._previousTerms = terms; | ||||
|         this._previousResults = results; | ||||
|  | ||||
|         return results; | ||||
|     } | ||||
|         this.emit('results-updated', results); | ||||
|     }, | ||||
| }; | ||||
| Signals.addSignalMethods(SearchSystem.prototype); | ||||
|   | ||||
| @@ -182,6 +182,7 @@ function SearchResults(searchSystem, openSearchSystem) { | ||||
| SearchResults.prototype = { | ||||
|     _init: function(searchSystem, openSearchSystem) { | ||||
|         this._searchSystem = searchSystem; | ||||
|         this._searchSystem.connect('results-updated', Lang.bind(this, this._updateResults)); | ||||
|         this._openSearchSystem = openSearchSystem; | ||||
|  | ||||
|         this.actor = new St.BoxLayout({ name: 'searchResults', | ||||
| @@ -216,9 +217,11 @@ SearchResults.prototype = { | ||||
|         this._selectedProvider = -1; | ||||
|         this._providers = this._searchSystem.getProviders(); | ||||
|         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._providerMetaResults[this.providers[i].title] = []; | ||||
|         } | ||||
|         this._searchProvidersBox = new St.BoxLayout({ style_class: 'search-providers-box' }); | ||||
|         this.actor.add(this._searchProvidersBox); | ||||
|  | ||||
| @@ -296,6 +299,12 @@ SearchResults.prototype = { | ||||
|             meta.actor.hide(); | ||||
|         } | ||||
|     }, | ||||
|      | ||||
|     _clearDisplayForProvider: function(index) { | ||||
|         let meta = this._providerMeta[index]; | ||||
|         meta.resultDisplay.clear(); | ||||
|         meta.actor.hide(); | ||||
|     }, | ||||
|  | ||||
|     reset: function() { | ||||
|         this._searchSystem.reset(); | ||||
| @@ -311,15 +320,15 @@ SearchResults.prototype = { | ||||
|         this._statusText.show(); | ||||
|     }, | ||||
|  | ||||
|     doSearch: function (searchString) { | ||||
|         this._searchSystem.updateSearch(searchString); | ||||
|     }, | ||||
|  | ||||
|     _metaForProvider: function(provider) { | ||||
|         return this._providerMeta[this._providers.indexOf(provider)]; | ||||
|     }, | ||||
|  | ||||
|     updateSearch: function (searchString) { | ||||
|         let results = this._searchSystem.updateSearch(searchString); | ||||
|  | ||||
|         this._clearDisplay(); | ||||
|  | ||||
|     _updateResults: function(searchSystem, results) { | ||||
|         if (results.length == 0) { | ||||
|             this._statusText.set_text(_("No matching results.")); | ||||
|             this._statusText.show(); | ||||
| @@ -329,14 +338,22 @@ SearchResults.prototype = { | ||||
|             this._statusText.hide(); | ||||
|         } | ||||
|  | ||||
|         let terms = this._searchSystem.getTerms(); | ||||
|         let terms = searchSystem.getTerms(); | ||||
|         this._openSearchSystem.setSearchTerms(terms); | ||||
|  | ||||
|         for (let i = 0; i < results.length; i++) { | ||||
|             let [provider, providerResults] = results[i]; | ||||
|             let meta = this._metaForProvider(provider); | ||||
|             meta.actor.show(); | ||||
|             meta.resultDisplay.renderResults(providerResults, terms); | ||||
|             if (providerResults.length == 0) | ||||
|                 this._clearDisplayForProvider(i) | ||||
|             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) | ||||
|   | ||||
| @@ -290,7 +290,7 @@ SearchTab.prototype = { | ||||
|     _doSearch: function () { | ||||
|         this._searchTimeoutId = 0; | ||||
|         let text = this._text.get_text().replace(/^\s+/g, '').replace(/\s+$/g, ''); | ||||
|         this._searchResults.updateSearch(text); | ||||
|         this._searchResults.doSearch(text); | ||||
|  | ||||
|         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); | ||||
|     } | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user