2 * Copyright (C) 2013,2015 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
21 import "../Components"
25 objectName: "pageHeader"
26 implicitHeight: headerContainer.height + signatureLineHeight
27 readonly property real signatureLineHeight: showSignatureLine ? units.gu(2) : 0
29 property int activeFiltersCount: 0
30 property bool scopeHasFilters: false
31 property bool showBackButton: false
32 property bool backIsClose: false
34 property var extraPanel
35 property string navigationTag
37 property bool storeEntryEnabled: false
38 property bool searchEntryEnabled: false
39 property bool settingsEnabled: false
40 property bool favoriteEnabled: false
41 property bool favorite: false
42 property ListModel searchHistory
43 property alias searchQuery: searchTextField.text
44 property alias searchHint: searchTextField.placeholderText
45 property bool showSignatureLine: true
47 property int paginationCount: 0
48 property int paginationIndex: -1
50 property var scopeStyle: null
52 signal clearSearch(bool keepPanelOpen)
55 signal settingsClicked()
56 signal favoriteClicked()
57 signal searchTextFieldFocused()
58 signal showFiltersPopup(var item)
60 onScopeStyleChanged: refreshLogo()
61 onSearchQueryChanged: {
62 // Make sure we are at the search page if the search query changes behind our feet
64 headerContainer.showSearch = true;
67 onNavigationTagChanged: {
68 // Make sure we are at the search page if the navigation tag changes behind our feet
70 headerContainer.showSearch = true;
74 function triggerSearch() {
75 if (searchEntryEnabled) {
76 headerContainer.showSearch = true;
77 searchTextField.forceActiveFocus();
81 function closePopup(keepFocus, keepSearch) {
82 if (extraPanel.visible) {
83 extraPanel.visible = false;
84 } else if (!keepFocus) {
87 if (!keepSearch && !searchTextField.text && !root.navigationTag && searchHistory.count == 0) {
88 headerContainer.showSearch = false;
92 function resetSearch(keepFocus) {
94 searchHistory.addQuery(searchTextField.text);
96 searchTextField.text = "";
97 closePopup(keepFocus);
100 function unfocus(keepSearch) {
101 searchTextField.focus = false;
102 if (!keepSearch && !searchTextField.text && !root.navigationTag) {
103 headerContainer.showSearch = false;
107 function openPopup() {
108 if (openSearchAnimation.running) {
109 openSearchAnimation.openPopup = true;
110 } else if (extraPanel.hasContents) {
112 extraPanel.visible = true;
116 function refreshLogo() {
117 if (root.scopeStyle ? root.scopeStyle.headerLogo != "" : false) {
118 header.contents = imageComponent.createObject();
119 } else if (header.contents) {
120 header.contents.destroy();
121 header.contents = null;
126 target: root.scopeStyle
127 onHeaderLogoChanged: root.refreshLogo()
131 anchors { fill: parent; margins: units.gu(1); bottomMargin: units.gu(3) + (extraPanel ? extraPanel.height : 0) }
132 visible: headerContainer.showSearch
134 extraPanel.visible = false;
135 closePopup(/* keepFocus */false);
136 mouse.accepted = false;
142 objectName: "headerContainer"
143 clip: contentY < height
144 anchors { left: parent.left; top: parent.top; right: parent.right }
145 height: header.__styleInstance.contentHeight
146 contentHeight: headersColumn.height
148 contentY: showSearch ? 0 : height
150 property bool showSearch: false
154 objectName: "headerBackground"
155 style: scopeStyle.headerBackground
158 Behavior on contentY {
159 UbuntuNumberAnimation {
160 id: openSearchAnimation
161 property bool openPopup: false
164 if (!running && openSearchAnimation.openPopup) {
165 openSearchAnimation.openPopup = false;
174 anchors { left: parent.left; right: parent.right }
178 anchors { left: parent.left; right: parent.right }
179 opacity: headerContainer.clip || headerContainer.showSearch ? 1 : 0 // setting visible false cause column to relayout
182 foregroundColor: root.scopeStyle ? root.scopeStyle.headerForeground : theme.palette.normal.baseText
183 backgroundColor: "transparent"
184 dividerColor: "transparent"
192 objectName: "searchTextField"
193 inputMethodHints: Qt.ImhNoPredictiveText
194 hasClearButton: false
197 topMargin: units.gu(1)
199 bottom: parent.bottom
200 bottomMargin: units.gu(1)
201 right: settingsButton.left
202 rightMargin: settingsButton.visible ? 0 : units.gu(2)
205 primaryItem: Rectangle {
207 width: root.navigationTag != "" ? tagLabel.width + units.gu(2) : 0
208 height: root.navigationTag != "" ? tagLabel.height + units.gu(1) : 0
209 radius: units.gu(0.5)
212 text: root.navigationTag
213 anchors.centerIn: parent
218 secondaryItem: AbstractButton {
220 height: searchTextField.height
222 enabled: searchTextField.text.length > 0 || root.navigationTag != ""
225 objectName: "clearIcon"
227 anchors.margins: units.gu(1)
228 source: "image://theme/clear"
229 opacity: parent.enabled
231 Behavior on opacity {
232 UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration }
237 root.clearSearch(true);
241 onActiveFocusChanged: {
243 root.searchTextFieldFocused();
250 closePopup(/* keepFocus */true);
257 objectName: "settingsButton"
259 width: root.scopeHasFilters ? height : 0
263 right: cancelButton.left
264 bottom: parent.bottom
265 rightMargin: units.gu(-1)
270 anchors.margins: units.gu(2)
272 color: root.activeFiltersCount > 0 ? theme.palette.normal.positive : header.__styleInstance.foregroundColor
276 root.showFiltersPopup(settingsButton);
282 objectName: "cancelButton"
283 width: cancelLabel.width + cancelLabel.anchors.rightMargin + cancelLabel.anchors.leftMargin
287 bottom: parent.bottom
290 root.clearSearch(false);
291 headerContainer.showSearch = false;
295 text: i18n.tr("Cancel")
296 color: header.__styleInstance.foregroundColor
297 verticalAlignment: Text.AlignVCenter
299 verticalCenter: parent.verticalCenter
301 rightMargin: units.gu(2)
302 leftMargin: units.gu(1)
311 objectName: "innerPageHeader"
312 anchors { left: parent.left; right: parent.right }
313 height: headerContainer.height
314 opacity: headerContainer.clip || !headerContainer.showSearch ? 1 : 0 // setting visible false cause column to relayout
318 foregroundColor: root.scopeStyle ? root.scopeStyle.headerForeground : theme.palette.normal.baseText
319 backgroundColor: "transparent"
320 dividerColor: "transparent"
323 leadingActionBar.actions: Action {
324 iconName: backIsClose ? "close" : "back"
325 visible: root.showBackButton
326 onTriggered: root.backClicked()
333 text: i18n.ctr("Button: Open the Ubuntu Store", "Store")
334 iconName: "ubuntu-store-symbolic"
335 visible: root.storeEntryEnabled
336 onTriggered: root.storeClicked();
340 text: i18n.ctr("Button: Start a search in the current dash scope", "Search")
342 visible: root.searchEntryEnabled
344 headerContainer.showSearch = true;
345 searchTextField.forceActiveFocus();
349 objectName: "settings"
350 text: i18n.ctr("Button: Show the current dash scope settings", "Settings")
352 visible: root.settingsEnabled
353 onTriggered: root.settingsClicked()
356 objectName: "favorite"
357 text: root.favorite ? i18n.tr("Remove from Favorites") : i18n.tr("Add to Favorites")
358 iconName: root.favorite ? "starred" : "non-starred"
359 visible: root.favoriteEnabled
360 onTriggered: root.favoriteClicked()
365 Component.onCompleted: root.refreshLogo()
371 anchors { fill: parent; topMargin: units.gu(1.5); bottomMargin: units.gu(1.5) }
374 objectName: "titleImage"
376 source: root.scopeStyle ? root.scopeStyle.headerLogo : ""
377 fillMode: Image.PreserveAspectFit
378 horizontalAlignment: Image.AlignLeft
379 sourceSize.height: height
389 visible: showSignatureLine
391 top: headerContainer.bottom
394 bottom: parent.bottom
397 color: root.scopeStyle ? root.scopeStyle.headerDividerColor : "#e0e0e0"
406 color: Qt.darker(parent.color, 1.1)
411 visible: bottomBorder.visible
412 spacing: units.gu(.5)
414 objectName: "paginationRepeater"
415 model: root.paginationCount
417 objectName: "paginationDots_" + index
420 source: (index == root.paginationIndex) ? "graphics/pagination_dot_on.png" : "graphics/pagination_dot_off.png"
424 top: headerContainer.bottom
425 horizontalCenter: headerContainer.horizontalCenter
426 topMargin: units.gu(.5)
430 // FIXME this doesn't work with solid scope backgrounds due to z-ordering
433 visible: bottomBorder.visible
445 color: if (root.scopeStyle) {
446 Qt.lighter(Qt.rgba(root.scopeStyle.background.r,
447 root.scopeStyle.background.g,
448 root.scopeStyle.background.b, 1.0), 1.2);