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 = { 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);
}, },
/** /**
@ -224,6 +261,7 @@ SearchProvider.prototype = {
}; };
Signals.addSignalMethods(SearchProvider.prototype); Signals.addSignalMethods(SearchProvider.prototype);
function OpenSearchSystem() { function OpenSearchSystem() {
this._init(); this._init();
} }
@ -336,6 +374,7 @@ SearchSystem.prototype = {
}, },
registerProvider: function (provider) { registerProvider: function (provider) {
provider.searchSystem = this;
this._providers.push(provider); this._providers.push(provider);
}, },
@ -352,30 +391,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);
} }
@ -383,10 +442,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);
} }
@ -395,8 +454,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);

View File

@ -157,6 +157,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',
@ -296,15 +297,16 @@ 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(); 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();
@ -314,11 +316,13 @@ 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];
if (providerResults.length == 0)
continue;
let meta = this._metaForProvider(provider); let meta = this._metaForProvider(provider);
meta.actor.show(); meta.actor.show();
meta.resultDisplay.renderResults(providerResults, terms); meta.resultDisplay.renderResults(providerResults, terms);

View File

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