[gnome-shell/wip/re-search: 122/151] searchDisplay, and others: Switch from provider title to provider icon



commit 8507d3c4e4a3ef4046473efc6857ff8cdd248400
Author: Tanner Doshier <doshitan gmail com>
Date:   Thu Aug 9 16:52:36 2012 -0500

    searchDisplay, and others: Switch from provider title to provider icon
    
    Display a '+' icon on the provider icon if there are more results that are
    hidden. If the provider icon is clicked, ask the provider to launch itself and
    perform a search with the current terms.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=681797

 data/org.gnome.ShellSearchProvider.xml |   20 +++++++
 js/ui/remoteSearch.js                  |    8 +++
 js/ui/search.js                        |   16 +++++
 js/ui/searchDisplay.js                 |   95 ++++++++++++++++++++++++++++++--
 4 files changed, 133 insertions(+), 6 deletions(-)
---
diff --git a/data/org.gnome.ShellSearchProvider.xml b/data/org.gnome.ShellSearchProvider.xml
index 558e662..4bf3076 100644
--- a/data/org.gnome.ShellSearchProvider.xml
+++ b/data/org.gnome.ShellSearchProvider.xml
@@ -143,5 +143,25 @@
         </doc:doc>
       </arg>
     </method>
+
+    <method name="LaunchSearch">
+      <doc:doc>
+        <doc:description>
+          <doc:para>
+            Called when the user clicks on the provider icon. The provider
+            application should open and run the active search term itself.
+          </doc:para>
+        </doc:description>
+      </doc:doc>
+      <arg type="as" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              The current search term(s).
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+    </method>
   </interface>
 </node>
diff --git a/js/ui/remoteSearch.js b/js/ui/remoteSearch.js
index 35176f4..2db7583 100644
--- a/js/ui/remoteSearch.js
+++ b/js/ui/remoteSearch.js
@@ -27,6 +27,9 @@ const SearchProviderIface = <interface name="org.gnome.Shell.SearchProvider">
 <method name="ActivateResult">
     <arg type="s" direction="in" />
 </method>
+<method name="LaunchSearch">
+    <arg type="as" direction="in" />
+</method>
 </interface>;
 
 var SearchProviderProxy = Gio.DBusProxy.makeProxyWrapper(SearchProviderIface);
@@ -112,6 +115,7 @@ const RemoteSearchProvider = new Lang.Class({
 
         this.parent(title.toUpperCase());
         this._cancellable = new Gio.Cancellable();
+        this.icon = icon;
     },
 
     createIcon: function(size, meta) {
@@ -196,6 +200,10 @@ const RemoteSearchProvider = new Lang.Class({
 
     activateResult: function(id) {
         this._proxy.ActivateResultRemote(id);
+    },
+
+    launchSearch: function(terms) {
+        this._proxy.LaunchSearchRemote(terms);
     }
 });
 
diff --git a/js/ui/search.js b/js/ui/search.js
index 22f53d9..fec3f2f 100644
--- a/js/ui/search.js
+++ b/js/ui/search.js
@@ -163,6 +163,16 @@ const SearchProvider = new Lang.Class({
      */
     activateResult: function(id) {
         throw new Error('Not implemented');
+    },
+
+    /**
+     * launchSearch:
+     * @terms: Current search terms
+     *
+     * Called when the user clicks the provider icon.
+     */
+    launchSearch: function(terms) {
+        throw new Error('Not implemented');
     }
 });
 Signals.addSignalMethods(SearchProvider.prototype);
@@ -261,5 +271,11 @@ const SearchSystem = new Lang.Class({
             }
         }
     },
+
+    launchSearch: function(provider) {
+        let terms = this.getTerms();
+        provider.launchSearch(terms);
+        Main.overview.toggle();
+    }
 });
 Signals.addSignalMethods(SearchSystem.prototype);
diff --git a/js/ui/searchDisplay.js b/js/ui/searchDisplay.js
index 5a914bd..f0ac119 100644
--- a/js/ui/searchDisplay.js
+++ b/js/ui/searchDisplay.js
@@ -7,6 +7,7 @@ const Meta = imports.gi.Meta;
 const St = imports.gi.St;
 const Atk = imports.gi.Atk;
 
+const AppDisplay = imports.ui.appDisplay;
 const DND = imports.ui.dnd;
 const IconGrid = imports.ui.iconGrid;
 const Main = imports.ui.main;
@@ -111,8 +112,8 @@ const GridSearchResults = new Lang.Class({
         this._grid = grid || new IconGrid.IconGrid({ rowLimit: MAX_SEARCH_RESULTS_ROWS,
                                                      xAlign: St.Align.START });
         this.actor = new St.Bin({ x_align: St.Align.START });
-
         this.actor.set_child(this._grid.actor);
+
         this._width = 0;
         this.actor.connect('notify::width', Lang.bind(this, function() {
             this._width = this.actor.width;
@@ -130,6 +131,7 @@ const GridSearchResults = new Lang.Class({
     },
 
     getResultsForDisplay: function() {
+        this._grid.actor.ensure_style();
         let alreadyVisible = this._pendingClear ? 0 : this._grid.visibleItemsCount();
         let canDisplay = this._grid.childrenInRow(this._width) * this._grid.getRowLimit()
                          - alreadyVisible;
@@ -143,6 +145,10 @@ const GridSearchResults = new Lang.Class({
         return this._grid.visibleItemsCount();
     },
 
+    hasMoreResults: function() {
+        return this._notDisplayedResult.length > 0;
+    },
+
     setResults: function(results, terms) {
         // copy the lists
         this._notDisplayedResult = results.slice(0);
@@ -220,21 +226,32 @@ const SearchResults = new Lang.Class({
     },
 
     createProviderMeta: function(provider) {
-        let providerBox = new St.BoxLayout({ style_class: 'search-section',
-                                             vertical: true });
-        let title = new St.Label({ style_class: 'search-section-header',
-                                   text: provider.title });
-        providerBox.add(title, { x_fill: false, x_align: St.Align.START });
+        let providerBox = new St.BoxLayout({ style_class: 'search-section' });
+        let isAppsProvider = (provider instanceof AppDisplay.AppSearchProvider);
+
+        let providerIcon;
+        if (!isAppsProvider) {
+            providerIcon = new ProviderIcon(provider);
+            providerIcon.connect('launch-search', Lang.bind(this, function(providerIcon) {
+                this._searchSystem.launchSearch(providerIcon.provider);
+            }));
+            providerBox.add(providerIcon.actor, { x_fill: false,
+                                                  y_fill: false,
+                                                  x_align: St.Align.START,
+                                                  y_align: St.Align.START });
+        }
 
         let resultDisplayBin = new St.Bin({ style_class: 'search-section-results',
                                             x_fill: true,
                                             y_fill: true });
         providerBox.add(resultDisplayBin, { expand: true });
+
         let resultDisplay = new GridSearchResults(provider);
         resultDisplayBin.set_child(resultDisplay.actor);
 
         this._providerMeta.push({ provider: provider,
                                   actor: providerBox,
+                                  icon: providerIcon,
                                   resultDisplay: resultDisplay });
         this._content.add(providerBox);
     },
@@ -341,6 +358,9 @@ const SearchResults = new Lang.Class({
             meta.resultDisplay.setResults(providerResults, terms);
             let results = meta.resultDisplay.getResultsForDisplay();
 
+            if (meta.icon)
+                meta.icon.moreIcon.visible = meta.resultDisplay.hasMoreResults();
+
             provider.getResultMetas(results, Lang.bind(this, function(metas) {
                 this._clearDisplayForProvider(provider);
                 meta.actor.show();
@@ -393,3 +413,66 @@ const SearchResults = new Lang.Class({
         }
     }
 });
+
+const ProviderIcon = new Lang.Class({
+    Name: 'ProviderIcon',
+
+    PROVIDER_ICON_SIZE: 48,
+
+    MORE_ICON_SIZE: 16,
+
+    _init: function(provider) {
+        this.provider = provider;
+
+        this.actor = new St.Button({ style_class: 'search-section-icon-bin',
+                                     reactive: true,
+                                     can_focus: true,
+                                     track_hover: true });
+        this.actor.connect('clicked', Lang.bind(this, this._onIconClicked));
+
+        this._content = new St.Widget({ layout_manager: new Clutter.BinLayout() });
+        this.actor.set_child(this._content);
+
+        let rtl = (this.actor.get_text_direction() == Clutter.TextDirection.RTL);
+
+        this.moreIcon = new St.Icon({ style_class: 'search-section-icon-more',
+                                      icon_size: this.MORE_ICON_SIZE,
+                                      icon_name: 'list-add-symbolic',
+                                      visible: false,
+                                      x_align: rtl ? Clutter.ActorAlign.START : Clutter.ActorAlign.END,
+                                      y_align: Clutter.ActorAlign.END,
+                                      // HACK: without these, ClutterBinLayout
+                                      // ignores alignment properties on the actor
+                                      x_expand: true,
+                                      y_expand: true });
+
+        this._iconBin = new St.Bin({ style_class: 'search-section-icon',
+                                     width: this.PROVIDER_ICON_SIZE,
+                                     height: this.PROVIDER_ICON_SIZE });
+
+        this._content.add_actor(this._iconBin);
+        this._content.add_actor(this.moreIcon);
+
+        this._createProviderIcon();
+    },
+
+    _createProviderIcon: function() {
+        let icon = new St.Icon({ icon_size: this.PROVIDER_ICON_SIZE });
+
+        if (this.provider.icon)
+            icon.gicon = this.provider.icon;
+        else
+            icon.icon_name = 'application-x-executable';
+
+        this._iconBin.set_child(icon);
+    },
+
+    activate: function() {
+        this.emit('launch-search');
+    },
+
+    _onIconClicked: function(actor) {
+        this.activate();
+    }
+});
+Signals.addSignalMethods(ProviderIcon.prototype);



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