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
This commit is contained in:
Rui Matos 2011-11-14 03:13:26 +00:00
parent c7a37660ce
commit b864b03a65
2 changed files with 74 additions and 25 deletions

View File

@ -190,6 +190,13 @@ const GridSearchResults = new Lang.Class({
return; return;
let targetActor = this._grid.getItemAtIndex(this.selectionIndex); let targetActor = this._grid.getItemAtIndex(this.selectionIndex);
targetActor._delegate.activate(); 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._openSearchProviders = [];
this._openSearchSystem.connect('changed', Lang.bind(this, this._updateOpenSearchProviderButtons)); this._openSearchSystem.connect('changed', Lang.bind(this, this._updateOpenSearchProviderButtons));
this._updateOpenSearchProviderButtons(); this._updateOpenSearchProviderButtons();
this._highlightDefault = false;
this._defaultResult = null;
}, },
_updateOpenSearchProviderButtons: function() { _updateOpenSearchProviderButtons: function() {
@ -284,6 +294,16 @@ const SearchResults = new Lang.Class({
button.set_child(bin); button.set_child(bin);
provider.actor = button; 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); this._searchProvidersBox.add(button);
}, },
@ -364,17 +384,31 @@ const SearchResults = new Lang.Class({
if (this._selectedOpenSearchButton > -1 || this._selectedProvider > -1) if (this._selectedOpenSearchButton > -1 || this._selectedProvider > -1)
return; return;
let newDefaultResult = null;
for (let i = 0; i < this._providerMeta.length; i++) { for (let i = 0; i < this._providerMeta.length; i++) {
let meta = this._providerMeta[i]; let meta = this._providerMeta[i];
if (meta.hasPendingResults) if (meta.hasPendingResults)
return; return;
if (meta.actor.visible) let firstResult = meta.resultDisplay.getFirstResult();
if (firstResult && firstResult.actor.visible) {
newDefaultResult = firstResult;
break; // select this one! break; // select this one!
}
} }
this.selectDown(false); if (!newDefaultResult)
this._initialSelectionSet = true; 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) { _updateCurrentResults: function(searchSystem, results) {
@ -428,11 +462,9 @@ const SearchResults = new Lang.Class({
let terms = 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 when the first search
// of the selection when the first search result // result stays the same, we hide the content while filling in the
// stays the same, we hide the content while // results.
// filling in the results and setting the initial
// selection.
this._content.hide(); this._content.hide();
for (let i = 0; i < results.length; i++) { for (let i = 0; i < results.length; i++) {
@ -535,5 +567,27 @@ const SearchResults = new Lang.Class({
let resultDisplay = meta.resultDisplay; let resultDisplay = meta.resultDisplay;
resultDisplay.activateSelected(); resultDisplay.activateSelected();
Main.overview.hide(); 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);
}
} }
}); });

View File

@ -133,14 +133,14 @@ const SearchTab = new Lang.Class({
this._text.connect('text-changed', Lang.bind(this, this._onTextChanged)); this._text.connect('text-changed', Lang.bind(this, this._onTextChanged));
this._text.connect('key-press-event', Lang.bind(this, function (o, e) { this._text.connect('key-press-event', Lang.bind(this, function (o, e) {
// We can't connect to 'activate' here because search providers // 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(); let symbol = e.get_key_symbol();
if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) { if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
if (this._searchTimeoutId > 0) { if (this._searchTimeoutId > 0) {
Mainloop.source_remove(this._searchTimeoutId); Mainloop.source_remove(this._searchTimeoutId);
this._doSearch(); this._doSearch();
} }
this._searchResults.activateSelected(); this._searchResults.activateDefault();
return true; return true;
} }
return false; return false;
@ -152,6 +152,13 @@ const SearchTab = new Lang.Class({
this._capturedEventId = 0; 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 // Since the entry isn't inside the results container we install this
// dummy widget as the last results container child so that we can // dummy widget as the last results container child so that we can
// include the entry in the keynav tab path... // include the entry in the keynav tab path...
@ -271,30 +278,18 @@ const SearchTab = new Lang.Class({
_onKeyPress: function(entry, event) { _onKeyPress: function(entry, event) {
let symbol = event.get_key_symbol(); let symbol = event.get_key_symbol();
if (symbol == Clutter.Up) { if (symbol == Clutter.Escape) {
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 (this._isActivated()) { if (this._isActivated()) {
this._reset(); this._reset();
return true; return true;
} }
} else if (this.active) { } else if (this.active) {
if (symbol == Clutter.Tab) { if (symbol == Clutter.Tab) {
this._searchResults.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false); this._searchResults.navigateFocus(Gtk.DirectionType.TAB_FORWARD);
return true; return true;
} else if (symbol == Clutter.ISO_Left_Tab) { } else if (symbol == Clutter.ISO_Left_Tab) {
this._focusTrap.can_focus = false; 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; this._focusTrap.can_focus = true;
return true; return true;
} }