search: Remove the ability to add synchronous search providers

As shown in the previous commits, synchronous search is easily implemented
by the asynchronous search API. The only reason we still have a
synchronous search API is of historical reasons. Well, we're not a museum,
and git log can keep our fossils safe if need be....

https://bugzilla.gnome.org/show_bug.cgi?id=675328
This commit is contained in:
Jasper St. Pierre 2012-05-02 15:54:25 -04:00
parent 58f77a19ed
commit 333e380340
7 changed files with 47 additions and 116 deletions

View File

@ -312,12 +312,10 @@ const AppSearchProvider = new Lang.Class({
_init: function() { _init: function() {
this.parent(_("APPLICATIONS")); this.parent(_("APPLICATIONS"));
this.async = true;
this._appSys = Shell.AppSystem.get_default(); this._appSys = Shell.AppSystem.get_default();
}, },
getResultMetasAsync: function(apps, callback) { getResultMetas: function(apps, callback) {
let metas = []; let metas = [];
for (let i = 0; i < apps.length; i++) { for (let i = 0; i < apps.length; i++) {
let app = apps[i]; let app = apps[i];
@ -331,11 +329,11 @@ const AppSearchProvider = new Lang.Class({
callback(metas); callback(metas);
}, },
getInitialResultSetAsync: function(terms) { getInitialResultSet: function(terms) {
this.searchSystem.pushResults(this, this._appSys.initial_search(terms)); this.searchSystem.pushResults(this, this._appSys.initial_search(terms));
}, },
getSubsearchResultSetAsync: function(previousResults, terms) { getSubsearchResultSet: function(previousResults, terms) {
this.searchSystem.pushResults(this, this._appSys.subsearch(previousResults, terms)); this.searchSystem.pushResults(this, this._appSys.subsearch(previousResults, terms));
}, },
@ -375,12 +373,11 @@ const SettingsSearchProvider = new Lang.Class({
_init: function() { _init: function() {
this.parent(_("SETTINGS")); this.parent(_("SETTINGS"));
this.async = true;
this._appSys = Shell.AppSystem.get_default(); this._appSys = Shell.AppSystem.get_default();
this._gnomecc = this._appSys.lookup_app('gnome-control-center.desktop'); this._gnomecc = this._appSys.lookup_app('gnome-control-center.desktop');
}, },
getResultMetasAsync: function(prefs, callback) { getResultMetas: function(prefs, callback) {
let metas = []; let metas = [];
for (let i = 0; i < prefs.length; i++) { for (let i = 0; i < prefs.length; i++) {
let pref = prefs[i]; let pref = prefs[i];
@ -394,11 +391,11 @@ const SettingsSearchProvider = new Lang.Class({
callback(metas); callback(metas);
}, },
getInitialResultSetAsync: function(terms) { getInitialResultSet: function(terms) {
this.searchSystem.pushResults(this, this._appSys.search_settings(terms)); this.searchSystem.pushResults(this, this._appSys.search_settings(terms));
}, },
getSubsearchResultSetAsync: function(previousResults, terms) { getSubsearchResultSet: function(previousResults, terms) {
this.searchSystem.pushResults(this, this._appSys.search_settings(terms)); this.searchSystem.pushResults(this, this._appSys.search_settings(terms));
}, },

View File

@ -151,11 +151,10 @@ const ContactSearchProvider = new Lang.Class({
_init: function() { _init: function() {
this.parent(_("CONTACTS")); this.parent(_("CONTACTS"));
this.async = true;
this._contactSys = Shell.ContactSystem.get_default(); this._contactSys = Shell.ContactSystem.get_default();
}, },
getResultMetasAsync: function(ids, callback) { getResultMetas: function(ids, callback) {
let metas = []; let metas = [];
for (let i = 0; i < ids.length; i++) { for (let i = 0; i < ids.length; i++) {
let contact = new Contact(ids[i]); let contact = new Contact(ids[i]);
@ -169,11 +168,11 @@ const ContactSearchProvider = new Lang.Class({
callback(metas); callback(metas);
}, },
getInitialResultSetAsync: function(terms) { getInitialResultSet: function(terms) {
this.searchSystem.pushResults(this, this._contactSys.initial_search(terms)); this.searchSystem.pushResults(this, this._contactSys.initial_search(terms));
}, },
getSubsearchResultSetAsync: function(previousResults, terms) { getSubsearchResultSet: function(previousResults, terms) {
this.searchSystem.pushResults(this, this._contactSys.subsearch(previousResults, terms)); this.searchSystem.pushResults(this, this._contactSys.subsearch(previousResults, terms));
}, },

View File

@ -365,11 +365,10 @@ const PlaceSearchProvider = new Lang.Class({
_init: function() { _init: function() {
this.parent(_("PLACES & DEVICES")); this.parent(_("PLACES & DEVICES"));
this.async = true;
this.placesManager = new PlacesManager(); this.placesManager = new PlacesManager();
}, },
getResultMetasAsync: function(resultIds, callback) { getResultMetas: function(resultIds, callback) {
let metas = []; let metas = [];
for (let i = 0; i < resultIds.length; i++) { for (let i = 0; i < resultIds.length; i++) {
let placeInfo = this.placesManager.lookupPlaceById(resultIds[i]); let placeInfo = this.placesManager.lookupPlaceById(resultIds[i]);
@ -417,12 +416,12 @@ const PlaceSearchProvider = new Lang.Class({
this.searchSystem.pushResults(this, prefixResults.concat(substringResults)); this.searchSystem.pushResults(this, prefixResults.concat(substringResults));
}, },
getInitialResultSetAsync: function(terms) { getInitialResultSet: function(terms) {
let places = this.placesManager.getAllPlaces(); let places = this.placesManager.getAllPlaces();
this._searchPlaces(places, terms); this._searchPlaces(places, terms);
}, },
getSubsearchResultSetAsync: function(previousResults, terms) { getSubsearchResultSet: function(previousResults, terms) {
let places = previousResults.map(Lang.bind(this, function(id) { let places = previousResults.map(Lang.bind(this, function(id) {
return this.placesManager.lookupPlaceById(id); return this.placesManager.lookupPlaceById(id);
})); }));

View File

@ -91,7 +91,6 @@ const RemoteSearchProvider = new Lang.Class({
dbusName, dbusPath); dbusName, dbusPath);
this.parent(title.toUpperCase()); this.parent(title.toUpperCase());
this.async = true;
this._cancellable = new Gio.Cancellable(); this._cancellable = new Gio.Cancellable();
}, },
@ -120,7 +119,7 @@ const RemoteSearchProvider = new Lang.Class({
this.searchSystem.pushResults(this, results[0]); this.searchSystem.pushResults(this, results[0]);
}, },
getInitialResultSetAsync: function(terms) { getInitialResultSet: function(terms) {
this._cancellable.cancel(); this._cancellable.cancel();
this._cancellable.reset(); this._cancellable.reset();
try { try {
@ -133,7 +132,7 @@ const RemoteSearchProvider = new Lang.Class({
} }
}, },
getSubsearchResultSetAsync: function(previousResults, newTerms) { getSubsearchResultSet: function(previousResults, newTerms) {
this._cancellable.cancel(); this._cancellable.cancel();
this._cancellable.reset(); this._cancellable.reset();
try { try {
@ -164,7 +163,7 @@ const RemoteSearchProvider = new Lang.Class({
callback(resultMetas); callback(resultMetas);
}, },
getResultMetasAsync: function(ids, callback) { getResultMetas: function(ids, callback) {
this._cancellable.cancel(); this._cancellable.cancel();
this._cancellable.reset(); this._cancellable.reset();
try { try {

View File

@ -70,11 +70,8 @@ const SearchResultDisplay = new Lang.Class({
* Subclass this object to add a new result type * Subclass this object to add a new result type
* to the search system, then call registerProvider() * to the search system, then call registerProvider()
* in SearchSystem with an instance. * in SearchSystem with an instance.
* By default, search is synchronous and uses the * Search is asynchronous and uses the
* getInitialResultSet()/getSubsearchResultSet() methods. * getInitialResultSet()/getSubsearchResultSet() methods.
* For asynchronous search, set the async property to true
* and implement getInitialResultSetAsync()/getSubsearchResultSetAsync()
* instead.
*/ */
const SearchProvider = new Lang.Class({ const SearchProvider = new Lang.Class({
Name: 'SearchProvider', Name: 'SearchProvider',
@ -82,7 +79,6 @@ const SearchProvider = new Lang.Class({
_init: function(title) { _init: function(title) {
this.title = title; this.title = title;
this.searchSystem = null; this.searchSystem = null;
this.async = false;
}, },
/** /**
@ -93,7 +89,7 @@ const SearchProvider = new Lang.Class({
* therefore a single term of length one or two), or when * therefore a single term of length one or two), or when
* a new term is added. * a new term is added.
* *
* Should return an array of result identifier strings representing * Should "return" an array of result identifier strings representing
* items which match the given search terms. This * items which match the given search terms. This
* is expected to be a substring match on the metadata for a given * is expected to be a substring match on the metadata for a given
* item. Ordering of returned results is up to the discretion of the provider, * item. Ordering of returned results is up to the discretion of the provider,
@ -103,6 +99,9 @@ const SearchProvider = new Lang.Class({
* description) before single matches * description) before single matches
* * Put items which match on a prefix before non-prefix substring matches * * Put items which match on a prefix before non-prefix substring matches
* *
* We say "return" above, but in order to make the query asynchronous, use
* this.searchSystem.pushResults();. The return value should be ignored.
*
* This function should be fast; do not perform unindexed full-text searches * This function should be fast; do not perform unindexed full-text searches
* or network queries. * or network queries.
*/ */
@ -110,18 +109,6 @@ const SearchProvider = new Lang.Class({
throw new Error('Not implemented'); throw new Error('Not implemented');
}, },
/**
* getInitialResultSetAsync:
* @terms: Array of search terms, treated as logical AND
*
* Like getInitialResultSet(), but the method should return immediately
* without a return value - use SearchSystem.pushResults() when the
* corresponding results are ready.
*/
getInitialResultSetAsync: function(terms) {
throw new Error('Not implemented');
},
/** /**
* getSubsearchResultSet: * getSubsearchResultSet:
* @previousResults: Array of item identifiers * @previousResults: Array of item identifiers
@ -134,46 +121,23 @@ const SearchProvider = new Lang.Class({
* *
* This allows search providers to only search through the previous * This allows search providers to only search through the previous
* result set, rather than possibly performing a full re-query. * result set, rather than possibly performing a full re-query.
*
* Similar to getInitialResultSet, the return value for this will
* be ignored; use this.searchSystem.pushResults();.
*/ */
getSubsearchResultSet: function(previousResults, newTerms) { getSubsearchResultSet: function(previousResults, newTerms) {
throw new Error('Not implemented'); throw new Error('Not implemented');
}, },
/**
* getSubsearchResultSetAsync:
* @previousResults: Array of item identifiers
* @newTerms: Updated search terms
*
* Like getSubsearchResultSet(), but the method should return immediately
* without a return value - use SearchSystem.pushResults() when the
* corresponding results are ready.
*/
getSubsearchResultSetAsync: function(previousResults, newTerms) {
throw new Error('Not implemented');
},
/** /**
* getResultMetas: * getResultMetas:
* @ids: Result identifier strings * @ids: Result identifier strings
* *
* Return an array of objects with 'id', 'name', (both strings) and * Call callback with array of objects with 'id', 'name', (both strings) and
* 'createIcon' (function(size) returning a Clutter.Texture) properties * 'createIcon' (function(size) returning a Clutter.Texture) properties
* with the same number of members as @ids * with the same number of members as @ids
*/ */
getResultMetas: function(ids) { getResultMetas: function(ids, callback) {
throw new Error('Not implemented');
},
/**
* getResultMetasAsync:
* @ids: Result identifier strings
* @callback: callback to pass the results to when ready
*
* Like getResultMetas(), but the method should return immediately
* without a return value - pass the results to the provided @callback
* when ready.
*/
getResultMetasAsync: function(ids, callback) {
throw new Error('Not implemented'); throw new Error('Not implemented');
}, },
@ -387,13 +351,8 @@ const SearchSystem = new Lang.Class({
for (let i = 0; i < this._providers.length; i++) { for (let i = 0; i < this._providers.length; i++) {
let [provider, previousResults] = previousResultsArr[i]; let [provider, previousResults] = previousResultsArr[i];
try { try {
if (provider.async) { results.push([provider, []]);
results.push([provider, []]); provider.getSubsearchResultSet(previousResults, terms);
provider.getSubsearchResultSetAsync(previousResults, terms);
} else {
let providerResults = provider.getSubsearchResultSet(previousResults, terms);
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);
} }
@ -402,13 +361,8 @@ const SearchSystem = new Lang.Class({
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];
try { try {
if (provider.async) { results.push([provider, []]);
results.push([provider, []]); provider.getInitialResultSet(terms);
provider.getInitialResultSetAsync(terms);
} else {
let providerResults = provider.getInitialResultSet(terms);
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);
} }

View File

@ -119,13 +119,7 @@ const GridSearchResults = new Lang.Class({
if (results.length == 0) if (results.length == 0)
return; return;
if (provider.async) { provider.getResultMetas(results, Lang.bind(this, this.renderResults));
provider.getResultMetasAsync(results,
Lang.bind(this, this.renderResults));
} else {
let metas = provider.getResultMetas(results);
this.renderResults(metas);
}
})); }));
})); }));
this._notDisplayedResult = []; this._notDisplayedResult = [];
@ -390,29 +384,21 @@ const SearchResults = new Lang.Class({
meta.resultDisplay.setResults(providerResults, terms); meta.resultDisplay.setResults(providerResults, terms);
let results = meta.resultDisplay.getResultsForDisplay(); let results = meta.resultDisplay.getResultsForDisplay();
if (provider.async) { provider.getResultMetas(results, Lang.bind(this, function(metas) {
provider.getResultMetasAsync(results, Lang.bind(this,
function(metas) {
this._clearDisplayForProvider(provider);
meta.actor.show();
// Hinding drops the key focus if we have it
let focus = global.stage.get_key_focus();
this._content.hide();
meta.resultDisplay.renderResults(metas);
this._maybeSetInitialSelection();
this._content.show();
if (this._content.contains(focus))
global.stage.set_key_focus(focus);
}));
} else {
let metas = provider.getResultMetas(results);
this._clearDisplayForProvider(provider); this._clearDisplayForProvider(provider);
meta.actor.show(); meta.actor.show();
// Hinding drops the key focus if we have it
let focus = global.stage.get_key_focus();
this._content.hide();
meta.resultDisplay.renderResults(metas); meta.resultDisplay.renderResults(metas);
} this._maybeSetInitialSelection();
this._content.show();
if (this._content.contains(focus))
global.stage.set_key_focus(focus);
}));
} }
this._maybeSetInitialSelection(); this._maybeSetInitialSelection();
}, },
@ -436,9 +422,7 @@ const SearchResults = new Lang.Class({
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); let meta = this._metaForProvider(provider);
meta.hasPendingResults = provider.async; meta.hasPendingResults = true;
if (!meta.hasPendingResults)
this._updateProviderResults(provider, providerResults, terms);
} }
this._content.show(); this._content.show();

View File

@ -166,10 +166,9 @@ const WandaSearchProvider = new Lang.Class({
_init: function() { _init: function() {
this.parent(_("Your favorite Easter Egg")); this.parent(_("Your favorite Easter Egg"));
this.async = true;
}, },
getResultMetasAsync: function(fish, callback) { getResultMetas: function(fish, callback) {
callback([{ 'id': fish[0], // there may be many fish in the sea, but callback([{ 'id': fish[0], // there may be many fish in the sea, but
// only one which speaks the truth! // only one which speaks the truth!
'name': capitalize(fish[0]), 'name': capitalize(fish[0]),
@ -188,7 +187,7 @@ const WandaSearchProvider = new Lang.Class({
}]); }]);
}, },
getInitialResultSetAsync: function(terms) { getInitialResultSet: function(terms) {
if (terms.join(' ') == MAGIC_FISH_KEY) { if (terms.join(' ') == MAGIC_FISH_KEY) {
this.searchSystem.pushResults(this, [ FISH_NAME ]); this.searchSystem.pushResults(this, [ FISH_NAME ]);
} else { } else {
@ -196,8 +195,8 @@ const WandaSearchProvider = new Lang.Class({
} }
}, },
getSubsearchResultSetAsync: function(previousResults, terms) { getSubsearchResultSet: function(previousResults, terms) {
this.getInitialResultSetAsync(terms); this.getInitialResultSet(terms);
}, },
activateResult: function(fish, params) { activateResult: function(fish, params) {