[gnome-shell] Add support for asynchronous search providers



commit 3418e6e85e3250d52a2eaa511a5407a7f18552e7
Author: Philippe Normand <philn igalia com>
Date:   Sun Jul 24 12:29:36 2011 +0200

    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

 js/ui/search.js        |   66 +++++++++++++++++++++++++++++++++++++++++------
 js/ui/searchDisplay.js |   45 +++++++++++++++++++++++++-------
 js/ui/viewSelector.js  |    2 +-
 3 files changed, 93 insertions(+), 20 deletions(-)
---
diff --git a/js/ui/search.js b/js/ui/search.js
index 47cb0e6..5b6a2c2 100644
--- a/js/ui/search.js
+++ b/js/ui/search.js
@@ -112,6 +112,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);
     },
 
     /**
@@ -315,6 +352,7 @@ SearchSystem.prototype = {
     },
 
     registerProvider: function (provider) {
+        provider.searchSystem = this;
         this._providers.push(provider);
     },
 
@@ -331,12 +369,23 @@ SearchSystem.prototype = {
         this._previousResults = [];
     },
 
+    addProviderItems: function(provider, items) {
+        this.emit('search-updated', provider, items);
+    },
+
     updateSearch: function(searchString) {
         searchString = searchString.replace(/^\s+/g, '').replace(/\s+$/g, '');
         if (searchString == '')
-            return [];
+            return;
 
         let terms = searchString.split(/\s+/);
+        this.updateSearchResults(terms);
+    },
+
+    updateSearchResults: function(terms) {
+        if (!terms)
+            return;
+
         let isSubSearch = terms.length == this._previousTerms.length;
         if (isSubSearch) {
             for (let i = 0; i < terms.length; i++) {
@@ -349,12 +398,12 @@ SearchSystem.prototype = {
 
         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);
                 }
@@ -362,10 +411,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);
                 }
@@ -374,8 +423,7 @@ SearchSystem.prototype = {
 
         this._previousTerms = terms;
         this._previousResults = results;
-
-        return results;
-    }
+        this.emit('search-completed', results);
+    },
 };
 Signals.addSignalMethods(SearchSystem.prototype);
diff --git a/js/ui/searchDisplay.js b/js/ui/searchDisplay.js
index 580f410..04ef64c 100644
--- a/js/ui/searchDisplay.js
+++ b/js/ui/searchDisplay.js
@@ -189,6 +189,8 @@ function SearchResults(searchSystem, openSearchSystem) {
 SearchResults.prototype = {
     _init: function(searchSystem, openSearchSystem) {
         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.actor = new St.BoxLayout({ name: 'searchResults',
@@ -223,9 +225,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);
 
@@ -305,6 +309,12 @@ SearchResults.prototype = {
         }
     },
 
+    _clearDisplayForProvider: function(index) {
+        let meta = this._providerMeta[index];
+        meta.resultDisplay.clear();
+        meta.actor.hide();
+    },
+
     reset: function() {
         this._searchSystem.reset();
         this._statusText.hide();
@@ -319,15 +329,24 @@ 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();
+    _updateCurrentResults: function(searchSystem, provider, results) {
+        let terms = searchSystem.getTerms();
+        let meta = this._metaForProvider(provider);
+        meta.resultDisplay.clear();
+        meta.actor.show();
+        meta.resultDisplay.renderResults(results, terms);
+        return true;
+    },
 
+    _updateResults: function(searchSystem, results) {
         if (results.length == 0) {
             this._statusText.set_text(_("No matching results."));
             this._statusText.show();
@@ -337,7 +356,7 @@ SearchResults.prototype = {
             this._statusText.hide();
         }
 
-        let terms = this._searchSystem.getTerms();
+        let terms = searchSystem.getTerms();
         this._openSearchSystem.setSearchTerms(terms);
 
         // To avoid CSS transitions causing flickering
@@ -349,9 +368,15 @@ SearchResults.prototype = {
 
         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 {
+                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)
diff --git a/js/ui/viewSelector.js b/js/ui/viewSelector.js
index 53b349c..b33139f 100644
--- a/js/ui/viewSelector.js
+++ b/js/ui/viewSelector.js
@@ -297,7 +297,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;
     }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]