[gnome-shell] searchDisplay, viewSelector: add default result activation



commit b864b03a65113ded58ba196f7b2ff922e8d94b43
Author: Rui Matos <tiagomatos gmail com>
Date:   Mon Nov 14 03:13:26 2011 +0000

    searchDisplay, viewSelector: add default result activation
    
    Adds a way to highlight and activate the first search result when
    pressing enter on the search entry.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=663901

 js/ui/searchDisplay.js |   70 ++++++++++++++++++++++++++++++++++++++++++-----
 js/ui/viewSelector.js  |   29 ++++++++-----------
 2 files changed, 74 insertions(+), 25 deletions(-)
---
diff --git a/js/ui/searchDisplay.js b/js/ui/searchDisplay.js
index 23bdb1e..d189340 100644
--- a/js/ui/searchDisplay.js
+++ b/js/ui/searchDisplay.js
@@ -190,6 +190,13 @@ const GridSearchResults = new Lang.Class({
             return;
         let targetActor = this._grid.getItemAtIndex(this.selectionIndex);
         targetActor._delegate.activate();
+    },
+
+    getFirstResult: function() {
+        if (this.getVisibleResultCount() > 0)
+            return this._grid.getItemAtIndex(0)._delegate;
+        else
+            return null;
     }
 });
 
@@ -245,6 +252,9 @@ const SearchResults = new Lang.Class({
         this._openSearchProviders = [];
         this._openSearchSystem.connect('changed', Lang.bind(this, this._updateOpenSearchProviderButtons));
         this._updateOpenSearchProviderButtons();
+
+        this._highlightDefault = false;
+        this._defaultResult = null;
     },
 
     _updateOpenSearchProviderButtons: function() {
@@ -284,6 +294,16 @@ const SearchResults = new Lang.Class({
         button.set_child(bin);
         provider.actor = button;
 
+        button.setSelected = function(selected) {
+            if (selected)
+                button.add_style_pseudo_class('selected');
+            else
+                button.remove_style_pseudo_class('selected');
+        };
+        button.activate = Lang.bind(this, function() {
+            this._openSearchSystem.activateResult(provider.id);
+        });
+
         this._searchProvidersBox.add(button);
     },
 
@@ -364,17 +384,31 @@ const SearchResults = new Lang.Class({
         if (this._selectedOpenSearchButton > -1 || this._selectedProvider > -1)
             return;
 
+        let newDefaultResult = null;
+
         for (let i = 0; i < this._providerMeta.length; i++) {
             let meta = this._providerMeta[i];
             if (meta.hasPendingResults)
                 return;
 
-            if (meta.actor.visible)
+            let firstResult = meta.resultDisplay.getFirstResult();
+            if (firstResult && firstResult.actor.visible) {
+                newDefaultResult = firstResult;
                 break; // select this one!
+            }
         }
 
-        this.selectDown(false);
-        this._initialSelectionSet = true;
+        if (!newDefaultResult)
+            newDefaultResult = this._searchProvidersBox.get_first_child();
+
+        if (newDefaultResult != this._defaultResult) {
+            if (this._defaultResult)
+                this._defaultResult.setSelected(false);
+            if (newDefaultResult)
+                newDefaultResult.setSelected(this._highlightDefault);
+
+            this._defaultResult = newDefaultResult;
+        }
     },
 
     _updateCurrentResults: function(searchSystem, results) {
@@ -428,11 +462,9 @@ const SearchResults = new Lang.Class({
         let terms = searchSystem.getTerms();
         this._openSearchSystem.setSearchTerms(terms);
 
-        // To avoid CSS transitions causing flickering
-        // of the selection when the first search result
-        // stays the same, we hide the content while
-        // filling in the results and setting the initial
-        // selection.
+        // To avoid CSS transitions causing flickering when the first search
+        // result stays the same, we hide the content while filling in the
+        // results.
         this._content.hide();
 
         for (let i = 0; i < results.length; i++) {
@@ -535,5 +567,27 @@ const SearchResults = new Lang.Class({
         let resultDisplay = meta.resultDisplay;
         resultDisplay.activateSelected();
         Main.overview.hide();
+    },
+
+    activateDefault: function() {
+        if (this._defaultResult && this._defaultResult.actor.visible)
+            this._defaultResult.activate();
+    },
+
+    highlightDefault: function(highlight) {
+        this._highlightDefault = highlight;
+        if (this._defaultResult)
+            this._defaultResult.setSelected(highlight);
+    },
+
+    navigateFocus: function(direction) {
+        if (direction == Gtk.DirectionType.TAB_FORWARD && this._defaultResult) {
+            // The default result appears focused, so navigate directly to the
+            // next result.
+            this.actor.navigate_focus(null, direction, false);
+            this.actor.navigate_focus(global.stage.key_focus, direction, false);
+        } else {
+            this.actor.navigate_focus(null, direction, false);
+        }
     }
 });
diff --git a/js/ui/viewSelector.js b/js/ui/viewSelector.js
index 363d4df..8826556 100644
--- a/js/ui/viewSelector.js
+++ b/js/ui/viewSelector.js
@@ -133,14 +133,14 @@ const SearchTab = new Lang.Class({
         this._text.connect('text-changed', Lang.bind(this, this._onTextChanged));
         this._text.connect('key-press-event', Lang.bind(this, function (o, e) {
             // We can't connect to 'activate' here because search providers
-            // might want to do something with the modifiers in activateSelected.
+            // might want to do something with the modifiers in activateDefault.
             let symbol = e.get_key_symbol();
             if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
                 if (this._searchTimeoutId > 0) {
                     Mainloop.source_remove(this._searchTimeoutId);
                     this._doSearch();
                 }
-                this._searchResults.activateSelected();
+                this._searchResults.activateDefault();
                 return true;
             }
             return false;
@@ -152,6 +152,13 @@ const SearchTab = new Lang.Class({
 
         this._capturedEventId = 0;
 
+        this._text.connect('key-focus-in', Lang.bind(this, function() {
+            this._searchResults.highlightDefault(true);
+        }));
+        this._text.connect('key-focus-out', Lang.bind(this, function() {
+            this._searchResults.highlightDefault(false);
+        }));
+
         // Since the entry isn't inside the results container we install this
         // dummy widget as the last results container child so that we can
         // include the entry in the keynav tab path...
@@ -271,30 +278,18 @@ const SearchTab = new Lang.Class({
 
     _onKeyPress: function(entry, event) {
         let symbol = event.get_key_symbol();
-        if (symbol == Clutter.Up) {
-            if (!this.active)
-                return true;
-            this._searchResults.selectUp(false);
-
-            return true;
-        } else if (symbol == Clutter.Down) {
-            if (!this.active)
-                return true;
-
-            this._searchResults.selectDown(false);
-            return true;
-        } else if (symbol == Clutter.Escape) {
+        if (symbol == Clutter.Escape) {
             if (this._isActivated()) {
                 this._reset();
                 return true;
             }
         } else if (this.active) {
             if (symbol == Clutter.Tab) {
-                this._searchResults.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
+                this._searchResults.navigateFocus(Gtk.DirectionType.TAB_FORWARD);
                 return true;
             } else if (symbol == Clutter.ISO_Left_Tab) {
                 this._focusTrap.can_focus = false;
-                this._searchResults.actor.navigate_focus(null, Gtk.DirectionType.TAB_BACKWARD, false);
+                this._searchResults.navigateFocus(Gtk.DirectionType.TAB_BACKWARD);
                 this._focusTrap.can_focus = true;
                 return true;
             }



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