Add support for asynchronous search providers
Some search providers may want to change their results, or may not want to block on an external service to get their results (DBus, etc.) Set up an infrastructure to allow search providers to add their search results at a later time. Based on a patch by Jasper St. Pierre and Seif Lotfy. https://bugzilla.gnome.org/show_bug.cgi?id=655220
This commit is contained in:
parent
8f0c980d3c
commit
3418e6e85e
@ -112,6 +112,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);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -315,6 +352,7 @@ SearchSystem.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
registerProvider: function (provider) {
|
registerProvider: function (provider) {
|
||||||
|
provider.searchSystem = this;
|
||||||
this._providers.push(provider);
|
this._providers.push(provider);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -331,12 +369,23 @@ SearchSystem.prototype = {
|
|||||||
this._previousResults = [];
|
this._previousResults = [];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
addProviderItems: function(provider, items) {
|
||||||
|
this.emit('search-updated', provider, items);
|
||||||
|
},
|
||||||
|
|
||||||
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+/);
|
||||||
|
this.updateSearchResults(terms);
|
||||||
|
},
|
||||||
|
|
||||||
|
updateSearchResults: function(terms) {
|
||||||
|
if (!terms)
|
||||||
|
return;
|
||||||
|
|
||||||
let isSubSearch = terms.length == this._previousTerms.length;
|
let isSubSearch = terms.length == this._previousTerms.length;
|
||||||
if (isSubSearch) {
|
if (isSubSearch) {
|
||||||
for (let i = 0; i < terms.length; i++) {
|
for (let i = 0; i < terms.length; i++) {
|
||||||
@ -349,11 +398,11 @@ SearchSystem.prototype = {
|
|||||||
|
|
||||||
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);
|
||||||
@ -362,9 +411,9 @@ 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);
|
||||||
@ -374,8 +423,7 @@ SearchSystem.prototype = {
|
|||||||
|
|
||||||
this._previousTerms = terms;
|
this._previousTerms = terms;
|
||||||
this._previousResults = results;
|
this._previousResults = results;
|
||||||
|
this.emit('search-completed', results);
|
||||||
return results;
|
},
|
||||||
}
|
|
||||||
};
|
};
|
||||||
Signals.addSignalMethods(SearchSystem.prototype);
|
Signals.addSignalMethods(SearchSystem.prototype);
|
||||||
|
@ -189,6 +189,8 @@ 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('search-updated', Lang.bind(this, this._updateCurrentResults));
|
||||||
|
this._searchSystem.connect('search-completed', 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',
|
||||||
@ -223,9 +225,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);
|
||||||
|
|
||||||
@ -305,6 +309,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();
|
||||||
@ -319,15 +329,24 @@ 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) {
|
_updateCurrentResults: function(searchSystem, provider, results) {
|
||||||
let results = this._searchSystem.updateSearch(searchString);
|
let terms = searchSystem.getTerms();
|
||||||
|
let meta = this._metaForProvider(provider);
|
||||||
this._clearDisplay();
|
meta.resultDisplay.clear();
|
||||||
|
meta.actor.show();
|
||||||
|
meta.resultDisplay.renderResults(results, terms);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateResults: function(searchSystem, results) {
|
||||||
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();
|
||||||
@ -337,7 +356,7 @@ 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);
|
||||||
|
|
||||||
// To avoid CSS transitions causing flickering
|
// To avoid CSS transitions causing flickering
|
||||||
@ -349,10 +368,16 @@ SearchResults.prototype = {
|
|||||||
|
|
||||||
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) {
|
||||||
|
this._clearDisplayForProvider(i);
|
||||||
|
} else {
|
||||||
|
this._providerMetaResults[provider.title] = providerResults;
|
||||||
|
this._clearDisplayForProvider(i);
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this._selectedOpenSearchButton == -1)
|
if (this._selectedOpenSearchButton == -1)
|
||||||
this.selectDown(false);
|
this.selectDown(false);
|
||||||
|
@ -297,7 +297,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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user