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.Themes.Ambiance 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) {
82 if (extraPanel.visible) {
83 extraPanel.visible = false;
84 } else if (!keepFocus) {
87 if (!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);
101 searchTextField.focus = false;
102 if (!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.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 }
177 // FIXME: Replace PageHeadStyle from the Ambiance theme by the new PageHeader from Ubuntu.Components 1.3.
179 anchors { left: parent.left; right: parent.right }
180 opacity: headerContainer.clip || headerContainer.showSearch ? 1 : 0 // setting visible false cause column to relayout
181 __separator_visible: false
182 // Required to keep PageHeadStyle noise down as it expects the Page's properties around.
183 property var styledItem: searchHeader
184 property color dividerColor: "transparent" // Doesn't matter as we don't have PageHeadSections
185 property color panelColor: background.topColor
186 panelForegroundColor: config.foregroundColor
187 backgroundColor: "transparent"
188 config: PageHeadConfiguration {
189 foregroundColor: root.scopeStyle ? root.scopeStyle.headerForeground : theme.palette.normal.baseText
191 property var contents: Item {
196 objectName: "searchTextField"
197 inputMethodHints: Qt.ImhNoPredictiveText
198 hasClearButton: false
201 topMargin: units.gu(1)
203 bottom: parent.bottom
204 bottomMargin: units.gu(1)
205 right: settingsButton.left
206 rightMargin: settingsButton.visible ? 0 : units.gu(2)
209 primaryItem: Rectangle {
211 width: root.navigationTag != "" ? tagLabel.width + units.gu(2) : 0
212 height: root.navigationTag != "" ? tagLabel.height + units.gu(1) : 0
213 radius: units.gu(0.5)
216 text: root.navigationTag
217 anchors.centerIn: parent
222 secondaryItem: AbstractButton {
224 height: searchTextField.height
226 enabled: searchTextField.text.length > 0 || root.navigationTag != ""
229 objectName: "clearIcon"
231 anchors.margins: units.gu(1)
232 source: "image://theme/clear"
233 opacity: parent.enabled
235 Behavior on opacity {
236 UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration }
241 root.clearSearch(true);
245 onActiveFocusChanged: {
247 root.searchTextFieldFocused();
254 closePopup(/* keepFocus */true);
261 objectName: "settingsButton"
263 width: root.scopeHasFilters ? height : 0
267 right: cancelButton.left
268 bottom: parent.bottom
269 rightMargin: units.gu(-1)
274 anchors.margins: units.gu(2)
276 color: root.activeFiltersCount > 0 ? UbuntuColors.orange : Qt.rgba(0.0, 0.0, 0.0, 0.0)
280 root.showFiltersPopup(settingsButton);
286 width: cancelLabel.width + cancelLabel.anchors.rightMargin + cancelLabel.anchors.leftMargin
290 bottom: parent.bottom
293 root.clearSearch(false);
294 headerContainer.showSearch = false;
298 text: i18n.tr("Cancel")
299 color: header.panelForegroundColor
300 verticalAlignment: Text.AlignVCenter
302 verticalCenter: parent.verticalCenter
304 rightMargin: units.gu(2)
305 leftMargin: units.gu(1)
313 // FIXME: Replace PageHeadStyle from the Ambiance theme by the new PageHeader from Ubuntu.Components 1.3.
315 objectName: "innerPageHeader"
316 anchors { left: parent.left; right: parent.right }
317 height: headerContainer.height
318 opacity: headerContainer.clip || !headerContainer.showSearch ? 1 : 0 // setting visible false cause column to relayout
319 __separator_visible: false
320 property var styledItem: header
321 property color dividerColor: "transparent" // Doesn't matter as we don't have PageHeadSections
322 property color panelColor: background.topColor
323 panelForegroundColor: config.foregroundColor
324 backgroundColor: "transparent"
325 config: PageHeadConfiguration {
327 foregroundColor: root.scopeStyle ? root.scopeStyle.headerForeground : theme.palette.normal.baseText
329 iconName: backIsClose ? "close" : "back"
330 visible: root.showBackButton
331 onTriggered: root.backClicked()
337 text: i18n.ctr("Button: Open the Ubuntu Store", "Store")
338 iconName: "ubuntu-store-symbolic"
339 visible: root.storeEntryEnabled
340 onTriggered: root.storeClicked();
344 text: i18n.ctr("Button: Start a search in the current dash scope", "Search")
346 visible: root.searchEntryEnabled
348 headerContainer.showSearch = true;
349 searchTextField.forceActiveFocus();
353 objectName: "settings"
354 text: i18n.ctr("Button: Show the current dash scope settings", "Settings")
356 visible: root.settingsEnabled
357 onTriggered: root.settingsClicked()
360 objectName: "favorite"
361 text: root.favorite ? i18n.tr("Remove from Favorites") : i18n.tr("Add to Favorites")
362 iconName: root.favorite ? "starred" : "non-starred"
363 visible: root.favoriteEnabled
364 onTriggered: root.favoriteClicked()
369 property var contents: null
370 Component.onCompleted: root.refreshLogo()
376 anchors { fill: parent; topMargin: units.gu(1.5); bottomMargin: units.gu(1.5) }
379 objectName: "titleImage"
381 source: root.scopeStyle ? root.scopeStyle.headerLogo : ""
382 fillMode: Image.PreserveAspectFit
383 horizontalAlignment: Image.AlignLeft
384 sourceSize.height: height
394 visible: showSignatureLine
396 top: headerContainer.bottom
399 bottom: parent.bottom
402 color: root.scopeStyle ? root.scopeStyle.headerDividerColor : "#e0e0e0"
411 color: Qt.darker(parent.color, 1.1)
416 visible: bottomBorder.visible
417 spacing: units.gu(.5)
419 objectName: "paginationRepeater"
420 model: root.paginationCount
422 objectName: "paginationDots_" + index
425 source: (index == root.paginationIndex) ? "graphics/pagination_dot_on.png" : "graphics/pagination_dot_off.png"
429 top: headerContainer.bottom
430 horizontalCenter: headerContainer.horizontalCenter
431 topMargin: units.gu(.5)
435 // FIXME this doesn't work with solid scope backgrounds due to z-ordering
438 visible: bottomBorder.visible
450 color: if (root.scopeStyle) {
451 Qt.lighter(Qt.rgba(root.scopeStyle.background.r,
452 root.scopeStyle.background.g,
453 root.scopeStyle.background.b, 1.0), 1.2);