viewSelector: merge SearchEntry into SearchTab

The division of labor between the two was quite muddled. Rather than
try to invent a clean distinction of what belongs where, just merge
them together.

https://bugzilla.gnome.org/show_bug.cgi?id=642502
This commit is contained in:
Dan Winship 2011-02-16 13:20:03 -05:00
parent 63be52e191
commit 5b8d3ba1d6

View File

@ -15,179 +15,6 @@ const Search = imports.ui.search;
const SearchDisplay = imports.ui.searchDisplay; const SearchDisplay = imports.ui.searchDisplay;
const Tweener = imports.ui.tweener; const Tweener = imports.ui.tweener;
function SearchEntry(focusBase) {
this._init(focusBase);
}
SearchEntry.prototype = {
_init : function(focusBase) {
this.actor = new St.Entry({ name: 'searchEntry',
/* Translators: this is the text displayed
in the search entry when no search is
active; it should not exceed ~30
characters */
hint_text: _("Type to search..."),
track_hover: true });
this.entry = this.actor.clutter_text;
this._inactiveIcon = new St.Icon({ style_class: 'search-entry-icon',
icon_name: 'edit-find',
icon_type: St.IconType.SYMBOLIC });
this._activeIcon = new St.Icon({ style_class: 'search-entry-icon',
icon_name: 'edit-clear',
icon_type: St.IconType.SYMBOLIC });
this.actor.set_secondary_icon(this._inactiveIcon);
this._iconClickedId = 0;
this.actor.clutter_text.connect('text-changed',
Lang.bind(this, this._onTextChanged));
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this.actor.connect('notify::mapped', Lang.bind(this, this._onMapped));
global.stage.connect('notify::key-focus', Lang.bind(this, this._updateCursorVisibility));
this.pane = null;
this._capturedEventId = 0;
this._focusBase = focusBase;
},
_updateCursorVisibility: function() {
let focus = global.stage.get_key_focus();
if (focus == this._focusBase || focus == this.entry)
this.entry.set_cursor_visible(true);
else
this.entry.set_cursor_visible(false);
},
_onMapped: function() {
if (this.actor.mapped) {
// Enable 'find-as-you-type'
this._capturedEventId = global.stage.connect('captured-event',
Lang.bind(this, this._onCapturedEvent));
this.entry.set_cursor_visible(true);
this.entry.set_selection(0, 0);
} else {
// Disable 'find-as-you-type'
if (this._capturedEventId > 0)
global.stage.disconnect(this._capturedEventId);
this._capturedEventId = 0;
}
},
reset: function () {
this.actor.sync_hover();
this.entry.text = '';
// Return focus to the viewSelector
global.stage.set_key_focus(this._focusBase);
this.entry.set_cursor_visible(true);
this.entry.set_selection(0, 0);
},
getText: function () {
return this.entry.get_text().replace(/^\s+/g, '').replace(/\s+$/g, '');
},
// some search term has been entered
isActive: function() {
return this.actor.get_text() != '';
},
// the entry does not show the hint
_isActivated: function() {
return this.entry.text == this.actor.get_text();
},
_onCapturedEvent: function(actor, event) {
let source = event.get_source();
let panelEvent = source && Main.panel.actor.contains(source);
switch (event.type()) {
case Clutter.EventType.BUTTON_PRESS:
// the user clicked outside after activating the entry, but
// with no search term entered - cancel the search
if (source != this.entry && this.entry.text == '') {
this.reset();
// allow only panel events to continue
return !panelEvent;
}
return false;
case Clutter.EventType.KEY_PRESS:
// If some "special" actor grabbed the focus (run
// dialog, looking glass); we don't want to interfere
// with that
let focus = global.stage.get_key_focus();
if (focus != this._focusBase && focus != this.entry)
return false;
let sym = event.get_key_symbol();
// If we have an active search, Escape cancels it - if we
// haven't, the key is ignored
if (sym == Clutter.Escape)
if (this._isActivated()) {
this.reset();
return true;
} else {
return false;
}
// Ignore non-printable keys
if (!Clutter.keysym_to_unicode(sym))
return false;
// Search started - move the key focus to the entry and
// "repeat" the event
if (!this._isActivated()) {
global.stage.set_key_focus(this.entry);
this.entry.event(event, false);
}
return false;
default:
// Suppress all other events outside the panel while the entry
// is activated and no search has been entered - any click
// outside the entry will cancel the search
return (this.entry.text == '' && !panelEvent);
}
},
_onTextChanged: function() {
if (this.isActive()) {
this.actor.set_secondary_icon(this._activeIcon);
if (this._iconClickedId == 0)
this._iconClickedId = this.actor.connect('secondary-icon-clicked',
Lang.bind(this, function() {
this.reset();
}));
} else {
if (this._iconClickedId > 0)
this.actor.disconnect(this._iconClickedId);
this._iconClickedId = 0;
this.actor.set_secondary_icon(this._inactiveIcon);
}
},
_onDestroy: function() {
if (this._capturedEventId > 0) {
global.stage.disconnect(this._capturedEventId);
this._capturedEventId = 0;
}
this._activeIcon = null;
this._inactiveIcon = null;
}
};
Signals.addSignalMethods(SearchEntry.prototype);
function BaseTab(titleActor, pageActor) { function BaseTab(titleActor, pageActor) {
this._init(titleActor, pageActor); this._init(titleActor, pageActor);
} }
@ -270,14 +97,32 @@ SearchTab.prototype = {
this._searchSystem = new Search.SearchSystem(); this._searchSystem = new Search.SearchSystem();
this._openSearchSystem = new Search.OpenSearchSystem(); this._openSearchSystem = new Search.OpenSearchSystem();
this._searchEntry = new SearchEntry(focusBase); this._entry = new St.Entry({ name: 'searchEntry',
/* Translators: this is the text displayed
in the search entry when no search is
active; it should not exceed ~30
characters. */
hint_text: _("Type to search..."),
track_hover: true });
this._text = this._entry.clutter_text;
this._inactiveIcon = new St.Icon({ style_class: 'search-entry-icon',
icon_name: 'edit-find',
icon_type: St.IconType.SYMBOLIC });
this._activeIcon = new St.Icon({ style_class: 'search-entry-icon',
icon_name: 'edit-clear',
icon_type: St.IconType.SYMBOLIC });
this._entry.set_secondary_icon(this._inactiveIcon);
this._iconClickedId = 0;
this._searchResults = new SearchDisplay.SearchResults(this._searchSystem, this._openSearchSystem); this._searchResults = new SearchDisplay.SearchResults(this._searchSystem, this._openSearchSystem);
BaseTab.prototype._init.call(this, BaseTab.prototype._init.call(this,
this._searchEntry.actor, this._entry,
this._searchResults.actor); this._searchResults.actor);
this._searchEntry.entry.connect('text-changed',
Lang.bind(this, this._onTextChanged)); this._text.connect('text-changed', Lang.bind(this, this._onTextChanged));
this._searchEntry.entry.connect('activate', Lang.bind(this, function (se) { this._text.connect('activate', Lang.bind(this, function (se) {
if (this._searchTimeoutId > 0) { if (this._searchTimeoutId > 0) {
Mainloop.source_remove(this._searchTimeoutId); Mainloop.source_remove(this._searchTimeoutId);
this._doSearch(); this._doSearch();
@ -285,24 +130,69 @@ SearchTab.prototype = {
this._searchResults.activateSelected(); this._searchResults.activateSelected();
return true; return true;
})); }));
this._entry.connect('secondary-icon-clicked', Lang.bind(this,
function() {
this._reset();
}));
this._entry.connect('notify::mapped', Lang.bind(this, this._onMapped));
global.stage.connect('notify::key-focus', Lang.bind(this, this._updateCursorVisibility));
this._capturedEventId = 0;
}, },
show: function() { show: function() {
BaseTab.prototype.show.call(this); BaseTab.prototype.show.call(this);
if (this._keyPressId == 0) if (this._keyPressId == 0)
this._keyPressId = this._searchEntry.entry.connect('key-press-event', this._keyPressId = this._text.connect('key-press-event',
Lang.bind(this, this._onKeyPress)); Lang.bind(this, this._onKeyPress));
}, },
hide: function() { hide: function() {
BaseTab.prototype.hide.call(this); BaseTab.prototype.hide.call(this);
if (this._keyPressId > 0) { if (this._keyPressId > 0) {
this._searchEntry.entry.disconnect(this._keyPressId); this._text.disconnect(this._keyPressId);
this._keyPressId = 0; this._keyPressId = 0;
} }
this._searchEntry.reset(); this._reset();
},
_reset: function () {
this._entry.sync_hover();
this._text.text = '';
// Return focus to the viewSelector
global.stage.set_key_focus(this._focusBase);
this._text.set_cursor_visible(true);
this._text.set_selection(0, 0);
},
_updateCursorVisibility: function() {
let focus = global.stage.get_key_focus();
if (focus == this._focusBase || focus == this._text)
this._text.set_cursor_visible(true);
else
this._text.set_cursor_visible(false);
},
_onMapped: function() {
if (this._entry.mapped) {
// Enable 'find-as-you-type'
this._capturedEventId = global.stage.connect('captured-event',
Lang.bind(this, this._onCapturedEvent));
this._text.set_cursor_visible(true);
this._text.set_selection(0, 0);
} else {
// Disable 'find-as-you-type'
if (this._capturedEventId > 0)
global.stage.disconnect(this._capturedEventId);
this._capturedEventId = 0;
}
}, },
addSearchProvider: function(provider) { addSearchProvider: function(provider) {
@ -310,16 +200,34 @@ SearchTab.prototype = {
this._searchResults.createProviderMeta(provider); this._searchResults.createProviderMeta(provider);
}, },
// the entry does not show the hint
_isActivated: function() {
return this._text.text == this._entry.get_text();
},
_onTextChanged: function (se, prop) { _onTextChanged: function (se, prop) {
let searchPreviouslyActive = this._searchActive; let searchPreviouslyActive = this._searchActive;
this._searchActive = this._searchEntry.isActive(); this._searchActive = this._entry.get_text() != '';
this._searchPending = this._searchActive && !searchPreviouslyActive; this._searchPending = this._searchActive && !searchPreviouslyActive;
if (this._searchPending) { if (this._searchPending) {
this._searchResults.startingSearch(); this._searchResults.startingSearch();
} }
if (this._searchActive) { if (this._searchActive) {
this._entry.set_secondary_icon(this._activeIcon);
if (this._iconClickedId == 0) {
this._iconClickedId = this._entry.connect('secondary-icon-clicked',
Lang.bind(this, function() {
this.reset();
}));
}
this._activate(); this._activate();
} else { } else {
if (this._iconClickedId > 0)
this._entry.disconnect(this._iconClickedId);
this._iconClickedId = 0;
this._entry.set_secondary_icon(this._inactiveIcon);
this.emit('search-cancelled'); this.emit('search-cancelled');
} }
if (!this._searchActive) { if (!this._searchActive) {
@ -352,9 +260,63 @@ SearchTab.prototype = {
return false; return false;
}, },
_onCapturedEvent: function(actor, event) {
let source = event.get_source();
let panelEvent = source && Main.panel.actor.contains(source);
switch (event.type()) {
case Clutter.EventType.BUTTON_PRESS:
// the user clicked outside after activating the entry, but
// with no search term entered - cancel the search
if (source != this._text && this._text.text == '') {
this._reset();
// allow only panel events to continue
return !panelEvent;
}
return false;
case Clutter.EventType.KEY_PRESS:
// If some "special" actor grabbed the focus (run
// dialog, looking glass); we don't want to interfere
// with that
let focus = global.stage.get_key_focus();
if (focus != this._focusBase && focus != this._text)
return false;
let sym = event.get_key_symbol();
// If we have an active search, Escape cancels it - if we
// haven't, the key is ignored
if (sym == Clutter.Escape)
if (this._isActivated()) {
this._reset();
return true;
} else {
return false;
}
// Ignore non-printable keys
if (!Clutter.keysym_to_unicode(sym))
return false;
// Search started - move the key focus to the entry and
// "repeat" the event
if (!this._isActivated()) {
global.stage.set_key_focus(this._text);
this._text.event(event, false);
}
return false;
default:
// Suppress all other events outside the panel while the entry
// is activated and no search has been entered - any click
// outside the entry will cancel the search
return (this._text.text == '' && !panelEvent);
}
},
_doSearch: function () { _doSearch: function () {
this._searchTimeoutId = 0; this._searchTimeoutId = 0;
let text = this._searchEntry.getText(); let text = this._text.get_text().replace(/^\s+/g, '').replace(/\s+$/g, '');
this._searchResults.updateSearch(text); this._searchResults.updateSearch(text);
return false; return false;