gnome-shell/js/ui/searchDisplay.js
Florian Müllner e6bb06a7cc search-display: Move SearchResults to a separate file
With the new layout, search results will be displayed in an independent
view like window previews, applications and possible future additions;
it does not make much sense keeping it with the switching logic, so move
the code to its own file.

Also remove the dash-prefix from the relevant style classes.

https://bugzilla.gnome.org/show_bug.cgi?id=634948
2010-11-29 16:35:53 +01:00

305 lines
10 KiB
JavaScript

/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const DND = imports.ui.dnd;
const Main = imports.ui.main;
const Search = imports.ui.search;
// 25 search results (per result type) should be enough for everyone
const MAX_RENDERED_SEARCH_RESULTS = 25;
function SearchResult(provider, metaInfo, terms) {
this._init(provider, metaInfo, terms);
}
SearchResult.prototype = {
_init: function(provider, metaInfo, terms) {
this.provider = provider;
this.metaInfo = metaInfo;
this.actor = new St.Clickable({ style_class: 'search-result',
reactive: true,
x_align: St.Align.START,
x_fill: true,
y_fill: true });
this.actor._delegate = this;
let content = provider.createResultActor(metaInfo, terms);
if (content == null) {
content = new St.BoxLayout({ style_class: 'search-result-content' });
let title = new St.Label({ text: this.metaInfo['name'] });
let icon = this.metaInfo['icon'];
content.add(icon, { y_fill: false });
content.add(title, { expand: true, y_fill: false });
}
this._content = content;
this.actor.set_child(content);
this.actor.connect('clicked', Lang.bind(this, this._onResultClicked));
let draggable = DND.makeDraggable(this.actor);
draggable.connect('drag-begin',
Lang.bind(this, function() {
Main.overview.beginItemDrag(this);
}));
draggable.connect('drag-end',
Lang.bind(this, function() {
Main.overview.endItemDrag(this);
}));
},
setSelected: function(selected) {
if (selected)
this._content.add_style_pseudo_class('selected');
else
this._content.remove_style_pseudo_class('selected');
},
activate: function() {
this.provider.activateResult(this.metaInfo.id);
Main.overview.toggle();
},
_onResultClicked: function(actor, event) {
this.activate();
},
getDragActorSource: function() {
return this.metaInfo['icon'];
},
getDragActor: function(stageX, stageY) {
return new Clutter.Clone({ source: this.metaInfo['icon'] });
},
shellWorkspaceLaunch: function() {
if (this.provider.dragActivateResult)
this.provider.dragActivateResult(this.metaInfo.id);
else
this.provider.activateResult(this.metaInfo.id);
}
};
function OverflowSearchResults(provider) {
this._init(provider);
}
OverflowSearchResults.prototype = {
__proto__: Search.SearchResultDisplay.prototype,
_init: function(provider) {
Search.SearchResultDisplay.prototype._init.call(this, provider);
this.actor = new St.OverflowBox({ style_class: 'search-section-list-results' });
},
getVisibleResultCount: function() {
return this.actor.get_n_visible();
},
renderResults: function(results, terms) {
for (let i = 0; i < results.length && i < MAX_RENDERED_SEARCH_RESULTS; i++) {
let result = results[i];
let meta = this.provider.getResultMeta(result);
let display = new SearchResult(this.provider, meta, terms);
this.actor.add_actor(display.actor);
}
},
selectIndex: function(index) {
let nVisible = this.actor.get_n_visible();
let children = this.actor.get_children();
if (this.selectionIndex >= 0) {
let prevActor = children[this.selectionIndex];
prevActor._delegate.setSelected(false);
}
this.selectionIndex = -1;
if (index >= nVisible)
return false;
else if (index < 0)
return false;
let targetActor = children[index];
targetActor._delegate.setSelected(true);
this.selectionIndex = index;
return true;
},
activateSelected: function() {
let children = this.actor.get_children();
let targetActor = children[this.selectionIndex];
targetActor._delegate.activate();
}
};
function SearchResults(searchSystem) {
this._init(searchSystem);
}
SearchResults.prototype = {
_init: function(searchSystem) {
this._searchSystem = searchSystem;
this.actor = new St.BoxLayout({ name: 'searchResults',
vertical: true });
this._statusText = new St.Label({ style_class: 'search-statustext' });
this.actor.add(this._statusText);
this._selectedProvider = -1;
this._providers = this._searchSystem.getProviders();
this._providerMeta = [];
for (let i = 0; i < this._providers.length; i++)
this.createProviderMeta(this._providers[i]);
},
createProviderMeta: function(provider) {
let providerBox = new St.BoxLayout({ style_class: 'search-section',
vertical: true });
let titleButton = new St.Button({ style_class: 'search-section-header',
reactive: true,
x_fill: true,
y_fill: true });
titleButton.connect('clicked', Lang.bind(this, function () { this._onHeaderClicked(provider); }));
providerBox.add(titleButton);
let titleBox = new St.BoxLayout();
titleButton.set_child(titleBox);
let title = new St.Label({ text: provider.title });
let count = new St.Label();
titleBox.add(title, { expand: true });
titleBox.add(count);
let resultDisplayBin = new St.Bin({ style_class: 'search-section-results',
x_fill: true,
y_fill: true });
providerBox.add(resultDisplayBin, { expand: true });
let resultDisplay = provider.createResultContainerActor();
if (resultDisplay == null) {
resultDisplay = new OverflowSearchResults(provider);
}
resultDisplayBin.set_child(resultDisplay.actor);
this._providerMeta.push({ actor: providerBox,
resultDisplay: resultDisplay,
count: count });
this.actor.add(providerBox);
},
_clearDisplay: function() {
this._selectedProvider = -1;
this._visibleResultsCount = 0;
for (let i = 0; i < this._providerMeta.length; i++) {
let meta = this._providerMeta[i];
meta.resultDisplay.clear();
meta.actor.hide();
}
},
reset: function() {
this._searchSystem.reset();
this._statusText.hide();
this._clearDisplay();
},
startingSearch: function() {
this.reset();
this._statusText.set_text(_("Searching..."));
this._statusText.show();
},
_metaForProvider: function(provider) {
return this._providerMeta[this._providers.indexOf(provider)];
},
updateSearch: function (searchString) {
let results = this._searchSystem.updateSearch(searchString);
this._clearDisplay();
if (results.length == 0) {
this._statusText.set_text(_("No matching results."));
this._statusText.show();
return true;
} else {
this._statusText.hide();
}
let terms = this._searchSystem.getTerms();
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);
meta.count.set_text('' + providerResults.length);
}
this.selectDown(false);
return true;
},
_onHeaderClicked: function(provider) {
provider.expandSearch(this._searchSystem.getTerms());
},
_modifyActorSelection: function(resultDisplay, up) {
let success;
let index = resultDisplay.getSelectionIndex();
if (up && index == -1)
index = resultDisplay.getVisibleResultCount() - 1;
else if (up)
index = index - 1;
else
index = index + 1;
return resultDisplay.selectIndex(index);
},
selectUp: function(recursing) {
for (let i = this._selectedProvider; i >= 0; i--) {
let meta = this._providerMeta[i];
if (!meta.actor.visible)
continue;
let success = this._modifyActorSelection(meta.resultDisplay, true);
if (success) {
this._selectedProvider = i;
return;
}
}
if (this._providerMeta.length > 0 && !recursing) {
this._selectedProvider = this._providerMeta.length - 1;
this.selectUp(true);
}
},
selectDown: function(recursing) {
let current = this._selectedProvider;
if (current == -1)
current = 0;
for (let i = current; i < this._providerMeta.length; i++) {
let meta = this._providerMeta[i];
if (!meta.actor.visible)
continue;
let success = this._modifyActorSelection(meta.resultDisplay, false);
if (success) {
this._selectedProvider = i;
return;
}
}
if (this._providerMeta.length > 0 && !recursing) {
this._selectedProvider = 0;
this.selectDown(true);
}
},
activateSelected: function() {
let current = this._selectedProvider;
if (current < 0)
return;
let meta = this._providerMeta[current];
let resultDisplay = meta.resultDisplay;
resultDisplay.activateSelected();
Main.overview.hide();
}
};