2 * Copyright (C) 2013,2015,2016 Canonical, Ltd.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 import Ubuntu.Components 1.3
19 import Ubuntu.Components.Popups 1.3
20 import Ubuntu.Components.ListItems 1.3
22 import "../Components"
26 objectName: "pageHeader"
27 implicitHeight: headerContainer.height + signatureLineHeight
28 readonly property real signatureLineHeight: showSignatureLine ? units.gu(2) : 0
29 readonly property real headerDividerLuminance: Style.luminance(bottomBorder.color)
31 property int activeFiltersCount: 0
32 property bool scopeHasFilters: false
33 property bool showBackButton: false
34 property bool backIsClose: false
36 property var extraPanel
37 property string navigationTag
39 property bool storeEntryEnabled: false
40 property bool searchEntryEnabled: false
41 property bool settingsEnabled: false
42 property bool favoriteEnabled: false
43 property bool favorite: false
44 property ListModel searchHistory
45 property alias searchQuery: searchTextField.text
46 property alias searchHint: searchTextField.placeholderText
47 property bool showSignatureLine: true
49 property int paginationCount: 0
50 property int paginationIndex: -1
52 property var scopeStyle: null
54 signal clearSearch(bool keepPanelOpen)
57 signal settingsClicked()
58 signal favoriteClicked()
59 signal searchTextFieldFocused()
60 signal showFiltersPopup(var item)
62 onScopeStyleChanged: refreshLogo()
63 onSearchQueryChanged: {
64 // Make sure we are at the search page if the search query changes behind our feet
66 headerContainer.showSearch = true;
69 onNavigationTagChanged: {
70 // Make sure we are at the search page if the navigation tag changes behind our feet
72 headerContainer.showSearch = true;
76 function triggerSearch() {
77 if (searchEntryEnabled) {
78 headerContainer.showSearch = true;
79 searchTextField.forceActiveFocus();
83 function closePopup(keepFocus, keepSearch) {
84 if (extraPanel.visible) {
85 extraPanel.visible = false;
90 if (!keepSearch && !searchTextField.text && !root.navigationTag && searchHistory.count == 0) {
91 headerContainer.showSearch = false;
95 function resetSearch(keepFocus) {
97 searchHistory.addQuery(searchTextField.text);
99 searchTextField.text = "";
100 closePopup(keepFocus);
103 function unfocus(keepSearch) {
104 searchTextField.focus = false;
105 if (!keepSearch && !searchTextField.text && !root.navigationTag) {
106 headerContainer.showSearch = false;
110 function openPopup() {
111 if (openSearchAnimation.running) {
112 openSearchAnimation.openPopup = true;
113 } else if (extraPanel.hasContents) {
115 extraPanel.visible = true;
119 function refreshLogo() {
120 if (root.scopeStyle ? root.scopeStyle.headerLogo != "" : false) {
121 header.contents = imageComponent.createObject();
122 } else if (header.contents) {
123 header.contents.destroy();
124 header.contents = null;
129 target: root.scopeStyle
130 onHeaderLogoChanged: root.refreshLogo()
134 anchors { fill: parent; margins: units.gu(1); bottomMargin: units.gu(3) + (extraPanel ? extraPanel.height : 0) }
135 visible: headerContainer.showSearch
137 closePopup(/* keepFocus */false);
138 mouse.accepted = false;
144 objectName: "headerContainer"
145 anchors { left: parent.left; top: parent.top; right: parent.right }
146 height: header.__styleInstance.contentHeight
148 property bool showSearch: false
150 state: headerContainer.showSearch ? "search" : ""
156 target: headersColumn
157 anchors.top: parent.top
158 anchors.bottom: undefined
162 transitions: Transition {
163 id: openSearchAnimation
165 duration: UbuntuAnimation.FastDuration
166 easing: UbuntuAnimation.StandardEasing
169 property bool openPopup: false
172 headerContainer.clip = running;
173 if (!running && openSearchAnimation.openPopup) {
174 openSearchAnimation.openPopup = false;
182 objectName: "headerBackground"
183 style: scopeStyle.headerBackground
191 bottom: parent.bottom
196 anchors { left: parent.left; right: parent.right }
197 opacity: headerContainer.clip || headerContainer.showSearch ? 1 : 0 // setting visible false cause column to relayout
200 foregroundColor: root.scopeStyle ? root.scopeStyle.headerForeground : theme.palette.normal.baseText
201 backgroundColor: "transparent"
202 dividerColor: "transparent"
208 Keys.onEscapePressed: { // clear the search text, dismiss the search in the second step
209 if (searchTextField.text != "") {
210 root.clearSearch(true);
212 root.clearSearch(false);
213 headerContainer.showSearch = false;
219 objectName: "searchTextField"
220 inputMethodHints: Qt.ImhNoPredictiveText
221 hasClearButton: false
224 topMargin: units.gu(1)
226 bottom: parent.bottom
227 bottomMargin: units.gu(1)
228 right: settingsButton.left
229 rightMargin: settingsButton.visible ? 0 : units.gu(2)
232 primaryItem: Rectangle {
234 width: root.navigationTag != "" ? tagLabel.width + units.gu(2) : 0
235 height: root.navigationTag != "" ? tagLabel.height + units.gu(1) : 0
236 radius: units.gu(0.5)
239 text: root.navigationTag
240 anchors.centerIn: parent
245 secondaryItem: AbstractButton {
247 height: searchTextField.height
249 enabled: searchTextField.text.length > 0 || root.navigationTag != ""
252 objectName: "clearIcon"
254 anchors.margins: units.gu(1)
255 source: "image://theme/clear"
256 sourceSize.width: width
257 sourceSize.height: height
258 opacity: parent.enabled
260 Behavior on opacity {
261 UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration }
266 root.clearSearch(true);
270 onActiveFocusChanged: {
272 root.searchTextFieldFocused();
279 closePopup(/* keepFocus */true);
286 objectName: "settingsButton"
288 width: root.scopeHasFilters ? height : 0
292 right: cancelButton.left
293 bottom: parent.bottom
294 rightMargin: units.gu(-1)
299 anchors.margins: units.gu(2)
301 color: root.activeFiltersCount > 0 ? theme.palette.normal.positive : header.__styleInstance.foregroundColor
305 root.showFiltersPopup(settingsButton);
311 objectName: "cancelButton"
312 width: cancelLabel.width + cancelLabel.anchors.rightMargin + cancelLabel.anchors.leftMargin
316 bottom: parent.bottom
319 root.clearSearch(false);
320 headerContainer.showSearch = false;
324 text: i18n.tr("Cancel")
325 color: header.__styleInstance.foregroundColor
326 verticalAlignment: Text.AlignVCenter
328 verticalCenter: parent.verticalCenter
330 rightMargin: units.gu(2)
331 leftMargin: units.gu(1)
340 objectName: "innerPageHeader"
341 anchors { left: parent.left; right: parent.right }
342 height: headerContainer.height
343 opacity: headerContainer.clip || !headerContainer.showSearch ? 1 : 0 // setting visible false cause column to relayout
347 foregroundColor: root.scopeStyle ? root.scopeStyle.headerForeground : theme.palette.normal.baseText
348 backgroundColor: "transparent"
349 dividerColor: "transparent"
352 leadingActionBar.actions: Action {
353 iconName: backIsClose ? "close" : "back"
354 visible: root.showBackButton
355 onTriggered: root.backClicked()
362 text: i18n.ctr("Button: Open the Ubuntu Store", "Store")
363 iconName: "ubuntu-store-symbolic"
364 visible: root.storeEntryEnabled
365 onTriggered: root.storeClicked();
369 text: i18n.ctr("Button: Start a search in the current dash scope", "Search")
371 visible: root.searchEntryEnabled
373 headerContainer.showSearch = true;
374 searchTextField.forceActiveFocus();
378 objectName: "settings"
379 text: i18n.ctr("Button: Show the current dash scope settings", "Settings")
381 visible: root.settingsEnabled
382 onTriggered: root.settingsClicked()
385 objectName: "favorite"
386 text: root.favorite ? i18n.tr("Remove from Favorites") : i18n.tr("Add to Favorites")
387 iconName: root.favorite ? "starred" : "non-starred"
388 visible: root.favoriteEnabled
389 onTriggered: root.favoriteClicked()
394 Component.onCompleted: root.refreshLogo()
400 anchors { fill: parent; topMargin: units.gu(1.5); bottomMargin: units.gu(1.5) }
403 objectName: "titleImage"
405 source: root.scopeStyle ? root.scopeStyle.headerLogo : ""
406 fillMode: Image.PreserveAspectFit
407 horizontalAlignment: Image.AlignLeft
408 sourceSize.height: height
418 visible: showSignatureLine
420 top: headerContainer.bottom
423 bottom: parent.bottom
426 color: root.scopeStyle ? root.scopeStyle.headerDividerColor : "#e0e0e0"
435 color: Qt.darker(parent.color, 1.1)
440 visible: bottomBorder.visible
441 spacing: units.gu(.5)
443 objectName: "paginationRepeater"
444 model: root.paginationCount
446 objectName: "paginationDots_" + index
449 source: (index == root.paginationIndex) ? "graphics/pagination_dot_on.png" : "graphics/pagination_dot_off.png"
453 top: headerContainer.bottom
454 horizontalCenter: headerContainer.horizontalCenter
455 topMargin: units.gu(.5)
459 // FIXME this doesn't work with solid scope backgrounds due to z-ordering
462 visible: bottomBorder.visible
474 color: if (root.scopeStyle) {
475 Qt.lighter(Qt.rgba(root.scopeStyle.background.r,
476 root.scopeStyle.background.g,
477 root.scopeStyle.background.b, 1.0), 1.2);