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.5) : headerBottomLine.height
30 property int activeFiltersCount: 0
31 property bool scopeHasFilters: false
32 property bool showBackButton: false
33 property bool backIsClose: false
35 property var extraPanel
36 property string navigationTag
38 property bool storeEntryEnabled: false
39 property bool searchEntryEnabled: false
40 property bool settingsEnabled: false
41 property bool favoriteEnabled: false
42 property bool favorite: false
43 property ListModel searchHistory
44 property alias searchQuery: searchTextField.text
45 property alias searchHint: searchTextField.placeholderText
46 property bool showSignatureLine: false
48 property int paginationCount: 0
49 property int paginationIndex: -1
51 property var scopeStyle: null
53 signal clearSearch(bool keepPanelOpen)
56 signal settingsClicked()
57 signal favoriteClicked()
58 signal searchTextFieldFocused()
59 signal showFiltersPopup(var item)
61 onScopeStyleChanged: refreshLogo()
62 onSearchQueryChanged: {
63 // Make sure we are at the search page if the search query changes behind our feet
65 headerContainer.showSearch = true;
68 onNavigationTagChanged: {
69 // Make sure we are at the search page if the navigation tag changes behind our feet
71 headerContainer.showSearch = true;
75 function triggerSearch() {
76 if (searchEntryEnabled) {
77 headerContainer.showSearch = true;
78 searchTextField.forceActiveFocus();
82 function closePopup(keepFocus, keepSearch) {
83 if (extraPanel.visible) {
84 extraPanel.visible = false;
89 if (!keepSearch && !searchTextField.text && !root.navigationTag && searchHistory.count == 0) {
90 headerContainer.showSearch = false;
94 function resetSearch(keepFocus) {
96 searchHistory.addQuery(searchTextField.text);
98 searchTextField.text = "";
99 closePopup(keepFocus);
102 function unfocus(keepSearch) {
103 searchTextField.focus = false;
104 if (!keepSearch && !searchTextField.text && !root.navigationTag) {
105 headerContainer.showSearch = false;
109 function openPopup() {
110 if (openSearchAnimation.running) {
111 openSearchAnimation.openPopup = true;
112 } else if (extraPanel.hasContents) {
114 extraPanel.visible = true;
118 function refreshLogo() {
119 if (root.scopeStyle ? root.scopeStyle.headerLogo != "" : false) {
120 header.contents = imageComponent.createObject();
121 } else if (header.contents) {
122 header.contents.destroy();
123 header.contents = null;
128 target: root.scopeStyle
129 onHeaderLogoChanged: root.refreshLogo()
133 anchors { fill: parent; margins: units.gu(1); bottomMargin: units.gu(3) + (extraPanel ? extraPanel.height : 0) }
134 visible: headerContainer.showSearch
136 closePopup(/* keepFocus */false);
137 mouse.accepted = false;
143 objectName: "headerContainer"
144 anchors { left: parent.left; top: parent.top; right: parent.right }
145 height: header.__styleInstance.contentHeight
147 property bool showSearch: false
149 state: headerContainer.showSearch ? "search" : ""
155 target: headersColumn
156 anchors.top: parent.top
157 anchors.bottom: undefined
161 transitions: Transition {
162 id: openSearchAnimation
164 duration: UbuntuAnimation.FastDuration
165 easing: UbuntuAnimation.StandardEasing
168 property bool openPopup: false
171 headerContainer.clip = running;
172 if (!running && openSearchAnimation.openPopup) {
173 openSearchAnimation.openPopup = false;
181 objectName: "headerBackground"
182 style: scopeStyle.headerBackground
187 objectName: "headersColumn"
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 leftMargin: units.gu(1)
339 objectName: "innerPageHeader"
340 anchors { left: parent.left; right: parent.right }
341 height: headerContainer.height
342 opacity: headerContainer.clip || !headerContainer.showSearch ? 1 : 0 // setting visible false cause column to relayout
346 foregroundColor: root.scopeStyle ? root.scopeStyle.headerForeground : theme.palette.normal.baseText
347 backgroundColor: "transparent"
348 dividerColor: "transparent"
351 leadingActionBar.actions: Action {
352 iconName: backIsClose ? "close" : "back"
353 visible: root.showBackButton
354 onTriggered: root.backClicked()
361 text: i18n.ctr("Button: Open the Ubuntu Store", "Store")
362 iconName: "ubuntu-store-symbolic"
363 visible: root.storeEntryEnabled
364 onTriggered: root.storeClicked();
368 text: i18n.ctr("Button: Start a search in the current dash scope", "Search")
370 visible: root.searchEntryEnabled
372 headerContainer.showSearch = true;
373 searchTextField.forceActiveFocus();
377 objectName: "settings"
378 text: i18n.ctr("Button: Show the current dash scope settings", "Settings")
380 visible: root.settingsEnabled
381 onTriggered: root.settingsClicked()
384 objectName: "favorite"
385 text: root.favorite ? i18n.tr("Remove from Favorites") : i18n.tr("Add to Favorites")
386 iconName: root.favorite ? "starred" : "non-starred"
387 visible: root.favoriteEnabled
388 onTriggered: root.favoriteClicked()
393 Component.onCompleted: root.refreshLogo()
399 anchors { fill: parent; topMargin: units.gu(1.5); bottomMargin: units.gu(1.5) }
402 objectName: "titleImage"
404 source: root.scopeStyle ? root.scopeStyle.headerLogo : ""
405 fillMode: Image.PreserveAspectFit
406 horizontalAlignment: Image.AlignLeft
407 sourceSize.height: height
418 top: headerContainer.bottom
423 color: theme.palette.normal.base
428 top: headerContainer.bottom
429 horizontalCenter: headerContainer.horizontalCenter
430 topMargin: units.gu(1)
432 visible: showSignatureLine
433 spacing: units.gu(.5)
435 objectName: "paginationRepeater"
436 model: root.paginationCount
438 objectName: "paginationDots_" + index
442 color: index == root.paginationIndex ? UbuntuColors.blue : "transparent"
443 border.width: index == root.paginationIndex ? 0 : 1 // yes, one pixel and not 1dp
444 border.color: theme.palette.normal.baseText