Restructure the search results code to be able to support any number of sections

We will be adding more search results sections, so we should store the intended
order of the search results sections and their properties in an array of data
structures.

This information allows us to have generic code for creating the search results
sections, moving the selection between them and transitioning between showing
all sections and a single section.
This commit is contained in:
Marina Zhurakhinskaya 2009-09-11 16:42:54 -04:00
parent 5598de6543
commit 3029a4086b

View File

@ -70,6 +70,19 @@ const PANE_BORDER_WIDTH = 2;
const PANE_BACKGROUND_COLOR = new Clutter.Color(); const PANE_BACKGROUND_COLOR = new Clutter.Color();
PANE_BACKGROUND_COLOR.from_pixel(0x000000f4); PANE_BACKGROUND_COLOR.from_pixel(0x000000f4);
/*
* Returns the index in an array of a given length that is obtained
* if the provided index is incremented by an increment and the array
* is wrapped in if necessary.
*
* index: prior index, expects 0 <= index < length
* increment: the change in index, expects abs(increment) <= length
* length: the length of the array
*/
function _getIndexWrapped(index, increment, length) {
return (index + increment + length) % length;
}
function Pane() { function Pane() {
this._init(); this._init();
} }
@ -607,36 +620,36 @@ Dash.prototype = {
this._searchTimeoutId = 0; this._searchTimeoutId = 0;
let text = this._searchEntry.getText(); let text = this._searchEntry.getText();
text = text.replace(/^\s+/g, "").replace(/\s+$/g, ""); text = text.replace(/^\s+/g, "").replace(/\s+$/g, "");
this._appSearchResultArea.display.setSearch(text);
this._docSearchResultArea.display.setSearch(text);
let appsCount = this._appSearchResultArea.display.getMatchedItemsCount() + ""; let selectionSet = false;
let docsCount = this._docSearchResultArea.display.getMatchedItemsCount() + "";
this._appSearchHeader.countText.text = appsCount; for (var i = 0; i < this._searchSections.length; i++) {
this._docSearchHeader.countText.text = docsCount; let section = this._searchSections[i];
section.resultArea.display.setSearch(text);
let itemCount = section.resultArea.display.getMatchedItemsCount() + "";
section.header.countText.text = itemCount;
if (this._searchResultsSingleShownSection == section.type)
this._searchResultsSection.header.setCountText(itemCount);
if (this._appSearchResultsOnlyShown) // Refresh the selection when a new search is applied.
this._searchResultsSection.header.setCountText(appsCount); section.resultArea.display.unsetSelected();
else if (this._docSearchResultsOnlyShown) if (!selectionSet && section.resultArea.display.hasItems() &&
this._searchResultsSection.header.setCountText(docsCount); (this._searchResultsSingleShownSection == null || this._searchResultsSingleShownSection == section.type)) {
section.resultArea.display.selectFirstItem();
if (this._appSearchResultArea.display.hasItems() && !this._docSearchResultsOnlyShown) { selectionSet = true;
this._appSearchResultArea.display.selectFirstItem(); }
this._docSearchResultArea.display.unsetSelected();
} else if (this._docSearchResultArea.display.hasItems() && !this._appSearchResultsOnlyShown) {
this._docSearchResultArea.display.selectFirstItem();
this._appSearchResultArea.display.unsetSelected();
} }
return false; return false;
})); }));
})); }));
this._searchEntry.entry.connect('activate', Lang.bind(this, function (se) { this._searchEntry.entry.connect('activate', Lang.bind(this, function (se) {
// only one of the displays will have an item selected, so it's ok to // Only one of the displays will have an item selected, so it's ok to
// call activateSelected() on all of them // call activateSelected() on all of them.
this._appSearchResultArea.display.activateSelected(); for (var i = 0; i < this._searchSections.length; i++) {
this._docSearchResultArea.display.activateSelected(); let section = this._searchSections[i];
section.resultArea.display.activateSelected();
}
return true; return true;
})); }));
this._searchEntry.entry.connect('key-press-event', Lang.bind(this, function (se, e) { this._searchEntry.entry.connect('key-press-event', Lang.bind(this, function (se, e) {
@ -645,7 +658,7 @@ Dash.prototype = {
if (symbol == Clutter.Escape) { if (symbol == Clutter.Escape) {
// Escape will keep clearing things back to the desktop. // Escape will keep clearing things back to the desktop.
// If we are showing a particular section of search, go back to all sections. // If we are showing a particular section of search, go back to all sections.
if (this._appSearchResultsOnlyShown || this._docSearchResultsOnlyShown) if (this._searchResultsSingleShownSection != null)
this._showAllSearchSections(); this._showAllSearchSections();
// If we have an active search, we remove it. // If we have an active search, we remove it.
else if (this._searchActive) else if (this._searchActive)
@ -664,30 +677,38 @@ Dash.prototype = {
// too, but there doesn't seem to be any flickering if we first select // too, but there doesn't seem to be any flickering if we first select
// something in one display, but then unset the selection, and move // something in one display, but then unset the selection, and move
// it to the other display, so it's ok to do that. // it to the other display, so it's ok to do that.
if (this._appSearchResultArea.display.hasSelected()) { for (var i = 0; i < this._searchSections.length; i++) {
if (!this._appSearchResultArea.display.selectUp() && this._docSearchResultArea.display.hasItems() && !this._appSearchResultsOnlyShown) { let section = this._searchSections[i];
this._docSearchResultArea.display.selectLastItem(); if (section.resultArea.display.hasSelected() && !section.resultArea.display.selectUp()) {
this._appSearchResultArea.display.unsetSelected(); if (this._searchResultsSingleShownSection != section.type) {
// We need to move the selection to the next section above this section that has items,
// wrapping around at the bottom, if necessary.
let newSectionIndex = this._findAnotherSectionWithItems(i, -1);
if (newSectionIndex >= 0) {
this._searchSections[newSectionIndex].resultArea.display.selectLastItem();
section.resultArea.display.unsetSelected();
} }
} else if (this._docSearchResultArea.display.hasSelected()) { }
if (!this._docSearchResultArea.display.selectUp() && this._appSearchResultArea.display.hasItems() && !this._docSearchResultsOnlyShown) { break;
this._appSearchResultArea.display.selectLastItem();
this._docSearchResultArea.display.unsetSelected();
} }
} }
return true; return true;
} else if (symbol == Clutter.Down) { } else if (symbol == Clutter.Down) {
if (!this._searchActive) if (!this._searchActive)
return true; return true;
if (this._appSearchResultArea.display.hasSelected()) { for (var i = 0; i < this._searchSections.length; i++) {
if (!this._appSearchResultArea.display.selectDown() && this._docSearchResultArea.display.hasItems() && !this._appSearchResultsOnlyShown) { let section = this._searchSections[i];
this._docSearchResultArea.display.selectFirstItem(); if (section.resultArea.display.hasSelected() && !section.resultArea.display.selectDown()) {
this._appSearchResultArea.display.unsetSelected(); if (this._searchResultsSingleShownSection != section.type) {
// We need to move the selection to the next section below this section that has items,
// wrapping around at the top, if necessary.
let newSectionIndex = this._findAnotherSectionWithItems(i, 1);
if (newSectionIndex >= 0) {
this._searchSections[newSectionIndex].resultArea.display.selectFirstItem();
section.resultArea.display.unsetSelected();
} }
} else if (this._docSearchResultArea.display.hasSelected()) { }
if (!this._docSearchResultArea.display.selectDown() && this._appSearchResultArea.display.hasItems() && !this._docSearchResultsOnlyShown) { break;
this._appSearchResultArea.display.selectFirstItem();
this._docSearchResultArea.display.unsetSelected();
} }
} }
return true; return true;
@ -745,36 +766,40 @@ Dash.prototype = {
this._searchResultsSection = new Section(_("SEARCH RESULTS"), true); this._searchResultsSection = new Section(_("SEARCH RESULTS"), true);
this._searchResultsSingleShownSection = null;
this._searchResultsSection.header.connect('back-link-activated', Lang.bind(this, function () { this._searchResultsSection.header.connect('back-link-activated', Lang.bind(this, function () {
if (this._appSearchResultsOnlyShown) this._showAllSearchSections();
this._toggleOnlyAppSearchShown();
else if (this._docSearchResultsOnlyShown)
this._toggleOnlyDocSearchShown();
})); }));
this._appSearchResultsOnlyShown = false; this._searchSections = [
this._appSearchHeader = new SearchSectionHeader(_("APPLICATIONS"), { type: "apps",
Lang.bind(this, title: _("APPLICATIONS"),
function () { header: null,
this._toggleOnlyAppSearchShown(); resultArea: null,
})); displayClass: AppDisplay.AppDisplay
this._searchResultsSection.content.append(this._appSearchHeader.actor, Big.BoxPackFlags.NONE); },
this._appSearchResultArea = new ResultArea(AppDisplay.AppDisplay, false); { type: "docs",
this._appSearchResultArea.controlBox.hide(); title: _("RECENT DOCUMENTS"),
this._searchResultsSection.content.append(this._appSearchResultArea.actor, Big.BoxPackFlags.EXPAND); header: null,
createPaneForDetails(this, this._appSearchResultArea.display); resultArea: null,
displayClass: DocDisplay.DocDisplay
}
];
this._docSearchResultsOnlyShown = false; for (var i = 0; i < this._searchSections.length; i++) {
this._docSearchHeader = new SearchSectionHeader(_("RECENT DOCUMENTS"), let section = this._searchSections[i];
section.header = new SearchSectionHeader(section.title,
Lang.bind(this, Lang.bind(this,
function () { function () {
this._toggleOnlyDocSearchShown(); this._showSingleSearchSection(section.type);
})); }));
this._searchResultsSection.content.append(this._docSearchHeader.actor, Big.BoxPackFlags.NONE); this._searchResultsSection.content.append(section.header.actor, Big.BoxPackFlags.NONE);
this._docSearchResultArea = new ResultArea(DocDisplay.DocDisplay, false); section.resultArea = new ResultArea(section.displayClass, false);
this._docSearchResultArea.controlBox.hide(); section.resultArea.controlBox.hide();
this._searchResultsSection.content.append(this._docSearchResultArea.actor, Big.BoxPackFlags.EXPAND); this._searchResultsSection.content.append(section.resultArea.actor, Big.BoxPackFlags.EXPAND);
createPaneForDetails(this, this._docSearchResultArea.display); createPaneForDetails(this, section.resultArea.display);
}
this.sectionArea.append(this._searchResultsSection.actor, Big.BoxPackFlags.EXPAND); this.sectionArea.append(this._searchResultsSection.actor, Big.BoxPackFlags.EXPAND);
this._searchResultsSection.actor.hide(); this._searchResultsSection.actor.hide();
@ -825,77 +850,63 @@ Dash.prototype = {
} }
}, },
_toggleOnlyAppSearchShown: function() { _showSingleSearchSection: function(type) {
if (this._appSearchResultsOnlyShown) { // We currently don't allow going from showing one section to showing another section.
this._setDocSearchShown(true); if (this._searchResultsSingleShownSection != null) {
} else { throw new Error("We were already showing a single search section: '" + this._searchResultsSingleShownSection
this._setDocSearchShown(false); + "' when _showSingleSearchSection() was called for '" + type + "'");
} }
}, for (var i = 0; i < this._searchSections.length; i++) {
let section = this._searchSections[i];
_toggleOnlyDocSearchShown: function() { if (section.type == type) {
if (this._docSearchResultsOnlyShown) { // This will be the only section shown.
this._setAppSearchShown(true); section.resultArea.display.selectFirstItem();
} else { section.resultArea.controlBox.show();
this._setAppSearchShown(false); let itemCount = section.resultArea.display.getMatchedItemsCount() + "";
} section.header.actor.hide();
}, this._searchResultsSection.header.setTitle(section.title);
_setAppSearchShown: function(show) {
if (show) {
this._appSearchHeader.actor.show();
this._appSearchResultArea.actor.show();
this._docSearchResultArea.display.displayPage(0);
this._docSearchResultArea.controlBox.hide();
this._searchResultsSection.header.setTitle(_("SEARCH RESULTS"));
this._searchResultsSection.header.setBackLinkVisible(false);
this._searchResultsSection.header.setCountText("");
this._docSearchHeader.actor.show();
this._docSearchResultsOnlyShown = false;
} else {
this._appSearchHeader.actor.hide();
this._appSearchResultArea.actor.hide();
this._appSearchResultArea.display.unsetSelected();
this._docSearchResultArea.display.selectFirstItem();
this._docSearchResultArea.controlBox.show();
this._searchResultsSection.header.setTitle(_("RECENT DOCUMENTS"));
this._searchResultsSection.header.setBackLinkVisible(true); this._searchResultsSection.header.setBackLinkVisible(true);
let docsCount = this._docSearchResultArea.display.getMatchedItemsCount() + ""; this._searchResultsSection.header.setCountText(itemCount);
this._searchResultsSection.header.setCountText(docsCount);
this._docSearchHeader.actor.hide();
this._docSearchResultsOnlyShown = true;
}
},
_setDocSearchShown: function(show) {
if (show) {
this._docSearchHeader.actor.show();
this._docSearchResultArea.actor.show();
this._appSearchResultArea.display.displayPage(0);
this._appSearchResultArea.controlBox.hide();
this._searchResultsSection.header.setTitle(_("SEARCH RESULTS"));
this._searchResultsSection.header.setBackLinkVisible(false);
this._searchResultsSection.header.setCountText("");
this._appSearchHeader.actor.show();
this._appSearchResultsOnlyShown = false;
} else { } else {
this._docSearchHeader.actor.hide(); // We need to hide this section.
this._docSearchResultArea.actor.hide(); section.header.actor.hide();
this._docSearchResultArea.display.unsetSelected(); section.resultArea.actor.hide();
this._appSearchResultArea.display.selectFirstItem(); section.resultArea.display.unsetSelected();
this._appSearchResultArea.controlBox.show();
this._searchResultsSection.header.setTitle(_("APPLICATIONS"));
this._searchResultsSection.header.setBackLinkVisible(true);
let appsCount = this._appSearchResultArea.display.getMatchedItemsCount() + "";
this._searchResultsSection.header.setCountText(appsCount);
this._appSearchHeader.actor.hide();
this._appSearchResultsOnlyShown = true;
} }
}
this._searchResultsSingleShownSection = type;
}, },
_showAllSearchSections: function() { _showAllSearchSections: function() {
this._setAppSearchShown(true); if (this._searchResultsSingleShownSection != null) {
this._setDocSearchShown(true); for (var i = 0; i < this._searchSections.length; i++) {
let section = this._searchSections[i];
if (section.type == this._searchResultsSingleShownSection) {
// This will no longer be the only section shown.
section.resultArea.display.displayPage(0);
section.resultArea.controlBox.hide();
section.header.actor.show();
this._searchResultsSection.header.setTitle(_("SEARCH RESULTS"));
this._searchResultsSection.header.setBackLinkVisible(false);
this._searchResultsSection.header.setCountText("");
} else {
// We need to restore this section.
section.header.actor.show();
section.resultArea.actor.show();
}
}
this._searchResultsSingleShownSection = null;
}
},
_findAnotherSectionWithItems: function(index, increment) {
let pos = _getIndexWrapped(index, increment, this._searchSections.length);
while (pos != index) {
if (this._searchSections[pos].resultArea.display.hasItems())
return pos;
pos = _getIndexWrapped(pos, increment, this._searchSections.length);
}
return -1;
} }
}; };
Signals.addSignalMethods(Dash.prototype); Signals.addSignalMethods(Dash.prototype);