Add support for asynchronous search providers

https://bugzilla.gnome.org/show_bug.cgi?id=640659
This commit is contained in:
Seif Lotfy 2011-01-26 20:43:44 +01:00 committed by Federico Mena Quintero
parent 04afea76e3
commit 4b015903bc
3 changed files with 83 additions and 21 deletions

View File

@ -117,6 +117,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);
},
/**
@ -224,6 +261,7 @@ SearchProvider.prototype = {
};
Signals.addSignalMethods(SearchProvider.prototype);
function OpenSearchSystem() {
this._init();
}
@ -336,6 +374,7 @@ SearchSystem.prototype = {
},
registerProvider: function (provider) {
provider.searchSystem = this;
this._providers.push(provider);
},
@ -352,13 +391,30 @@ 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;
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) {
@ -367,14 +423,17 @@ SearchSystem.prototype = {
}
}
}
} 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]);
} catch (error) {
global.log ('A ' + error.name + ' has occured in ' + provider.title + ': ' + error.message);
@ -383,9 +442,9 @@ 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]);
} catch (error) {
global.log ('A ' + error.name + ' has occured in ' + provider.title + ': ' + error.message);
@ -395,8 +454,7 @@ SearchSystem.prototype = {
this._previousTerms = terms;
this._previousResults = results;
return results;
}
this.emit('results-updated', results);
},
};
Signals.addSignalMethods(SearchSystem.prototype);

View File

@ -157,6 +157,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',
@ -296,15 +297,16 @@ 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);
_updateResults: function(searchSystem, results) {
this._clearDisplay();
if (results.length == 0) {
this._statusText.set_text(_("No matching results."));
this._statusText.show();
@ -314,11 +316,13 @@ 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];
if (providerResults.length == 0)
continue;
let meta = this._metaForProvider(provider);
meta.actor.show();
meta.resultDisplay.renderResults(providerResults, terms);

View File

@ -268,7 +268,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;
}