Merge lp:~unity-team/unity8/rtm-expanded-panel-design into lp:unity8/rtm-14.09

Proposed by Michał Sawicz
Status: Merged
Approved by: Michał Sawicz
Approved revision: 1326
Merged at revision: 1358
Proposed branch: lp:~unity-team/unity8/rtm-expanded-panel-design
Merge into: lp:unity8/rtm-14.09
Prerequisite: lp:~unity-team/unity8/rtm-sharedunitymenumodel
Diff against target: 5058 lines (+1883/-2006)
45 files modified
plugins/Unity/Indicators/Indicators.qmltypes (+2/-4)
plugins/Unity/Indicators/indicators.h (+0/-2)
plugins/Unity/Indicators/indicatorsmodel.cpp (+0/-6)
plugins/Unity/Indicators/visibleindicatorsmodel.cpp (+0/-2)
qml/Components/DragHandle.qml (+6/-1)
qml/Components/ListItems/VerticalThinDivider.qml (+0/-26)
qml/Components/ScrollCalculator.qml (+81/-0)
qml/Panel/Handle.qml (+43/-0)
qml/Panel/IndicatorItem.qml (+0/-53)
qml/Panel/IndicatorItemRow.qml (+256/-0)
qml/Panel/IndicatorPage.qml (+2/-6)
qml/Panel/IndicatorRow.qml (+0/-162)
qml/Panel/Indicators.qml (+0/-415)
qml/Panel/Indicators/DefaultIndicatorWidget.qml (+0/-119)
qml/Panel/Indicators/IndicatorBase.qml (+1/-3)
qml/Panel/Indicators/VisibleIndicators.qml (+4/-5)
qml/Panel/Indicators/client/IndicatorRepresentation.qml (+22/-11)
qml/Panel/Indicators/client/IndicatorsList.qml (+2/-2)
qml/Panel/Indicators/client/IndicatorsTree.qml (+5/-27)
qml/Panel/IndicatorsBar.qml (+260/-0)
qml/Panel/IndicatorsMenu.qml (+285/-0)
qml/Panel/MenuContent.qml (+25/-82)
qml/Panel/Panel.qml (+0/-191)
qml/Panel/PanelVelocityCalculator.qml (+54/-0)
qml/Shell.qml (+15/-4)
tests/autopilot/unity8/indicators/tests/test_indicators.py (+1/-1)
tests/autopilot/unity8/shell/emulators/main_window.py (+6/-6)
tests/mocks/Unity/Indicators/Indicators.qmltypes (+2/-4)
tests/mocks/Unity/Indicators/IndicatorsModel.qml (+23/-17)
tests/mocks/Unity/Indicators/fakeindicatorsmodel.cpp (+0/-2)
tests/qmltests/CMakeLists.txt (+5/-5)
tests/qmltests/Panel/IndicatorTest.qml (+67/-0)
tests/qmltests/Panel/Indicators/tst_DefaultIndicatorWidget.qml (+0/-52)
tests/qmltests/Panel/tst_ActiveCallHint.qml (+0/-1)
tests/qmltests/Panel/tst_IndicatorItem.qml (+0/-50)
tests/qmltests/Panel/tst_IndicatorItemRow.qml (+279/-0)
tests/qmltests/Panel/tst_IndicatorPage.qml (+4/-4)
tests/qmltests/Panel/tst_IndicatorRow.qml (+0/-158)
tests/qmltests/Panel/tst_Indicators.qml (+0/-231)
tests/qmltests/Panel/tst_IndicatorsBar.qml (+178/-0)
tests/qmltests/Panel/tst_IndicatorsMenu.qml (+247/-0)
tests/qmltests/Panel/tst_MenuContent.qml (+6/-14)
tests/qmltests/Panel/tst_Panel.qml (+0/-337)
tests/qmltests/Panel/tst_SearchIndicator.qml (+0/-1)
tests/qmltests/tst_Shell.qml (+2/-2)
To merge this branch: bzr merge lp:~unity-team/unity8/rtm-expanded-panel-design
Reviewer Review Type Date Requested Status
Michał Sawicz Approve
Review via email: mp+238244@code.launchpad.net

Commit message

Implementation of expandable panel design

Description of the change

New Panel design described in:
https://docs.google.com/a/canonical.com/document/d/1jHIGzAzf7kFELgOiU9J0Hd9mOa3NzTsnEglLmx_qEfk/edit#heading=h.lo6wjg7251og

 * Are there any related MPs required for this MP to build/function as expected? Please list.
No

 * Did you perform an exploratory manual test run of your code change and any related functionality?
No

 * Did you make sure that your branch does not contain spurious tags?
Yes

 * If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
N/A

 * If you changed the UI, has there been a design review?
No

To post a comment you must log in.
1323. By Nick Dedekind

sync indicator page delegate loader

1324. By Nick Dedekind

remove previouslyStopped

1325. By Nick Dedekind

full screen notifications don't include panel

Revision history for this message
Ted Gould (ted) wrote :

Playing with this some in silo 6 there are a few things I'm noticing:

* Indicators that are marked as not visible aren't showing up in the expanded panel
* Selecting an expanded item that is partially on screen doesn't pull it to be completely on screen
* Putting your finger on the bottom bar allows you to slide between the indicators. So if you grab the bar and close, you probably change indicators along the way (which is odd)

Otherwise I really love it :-)

1326. By Nick Dedekind

remove/add item fixes

Revision history for this message
Michał Sawicz (saviq) wrote :

This has been tested extensively for going into rtm.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/Unity/Indicators/Indicators.qmltypes'
2--- plugins/Unity/Indicators/Indicators.qmltypes 2014-10-15 16:33:45 +0000
3+++ plugins/Unity/Indicators/Indicators.qmltypes 2014-10-15 16:33:46 +0000
4@@ -99,10 +99,8 @@
5 values: {
6 "Identifier": 0,
7 "Position": 1,
8- "WidgetSource": 2,
9- "PageSource": 3,
10- "IndicatorProperties": 4,
11- "IsVisible": 5
12+ "IndicatorProperties": 2,
13+ "IsVisible": 3
14 }
15 }
16 }
17
18=== modified file 'plugins/Unity/Indicators/indicators.h'
19--- plugins/Unity/Indicators/indicators.h 2013-09-17 12:31:19 +0000
20+++ plugins/Unity/Indicators/indicators.h 2014-10-15 16:33:46 +0000
21@@ -74,8 +74,6 @@
22 enum Roles {
23 Identifier = 0,
24 Position,
25- WidgetSource,
26- PageSource,
27 IndicatorProperties,
28 IsVisible
29 };
30
31=== modified file 'plugins/Unity/Indicators/indicatorsmodel.cpp'
32--- plugins/Unity/Indicators/indicatorsmodel.cpp 2014-01-30 14:54:01 +0000
33+++ plugins/Unity/Indicators/indicatorsmodel.cpp 2014-10-15 16:33:46 +0000
34@@ -202,8 +202,6 @@
35 {
36 roles[IndicatorsModelRole::Identifier] = "identifier";
37 roles[IndicatorsModelRole::Position] = "position";
38- roles[IndicatorsModelRole::WidgetSource] = "widgetSource";
39- roles[IndicatorsModelRole::PageSource] = "pageSource";
40 roles[IndicatorsModelRole::IndicatorProperties] = "indicatorProperties";
41 }
42 return roles;
43@@ -248,10 +246,6 @@
44 return QVariant(indicator->indicatorProperties());
45 }
46 break;
47- case IndicatorsModelRole::WidgetSource:
48- return qmlDirectory()+"/Panel/Indicators/DefaultIndicatorWidget.qml";
49- case IndicatorsModelRole::PageSource:
50- return qmlDirectory()+"/Panel/Indicators/DefaultIndicatorPage.qml";
51 default:
52 break;
53 }
54
55=== modified file 'plugins/Unity/Indicators/visibleindicatorsmodel.cpp'
56--- plugins/Unity/Indicators/visibleindicatorsmodel.cpp 2013-09-17 12:31:19 +0000
57+++ plugins/Unity/Indicators/visibleindicatorsmodel.cpp 2014-10-15 16:33:46 +0000
58@@ -33,8 +33,6 @@
59 {
60 roles[IndicatorsModelRole::Identifier] = "identifier";
61 roles[IndicatorsModelRole::Position] = "position";
62- roles[IndicatorsModelRole::WidgetSource] = "widgetSource";
63- roles[IndicatorsModelRole::PageSource] = "pageSource";
64 roles[IndicatorsModelRole::IndicatorProperties] = "indicatorProperties";
65 roles[IndicatorsModelRole::IsVisible] = "isVisible";
66 }
67
68=== modified file 'qml/Components/DragHandle.qml'
69--- qml/Components/DragHandle.qml 2014-02-12 18:51:36 +0000
70+++ qml/Components/DragHandle.qml 2014-10-15 16:33:46 +0000
71@@ -68,6 +68,7 @@
72 }
73
74 property real hintDisplacement: 0
75+ property var overrideStartValue: undefined
76 SmoothedAnimation {
77 id: hintingAnimation
78 target: hintingAnimation
79@@ -196,7 +197,11 @@
80 } else /* Undecided || Recognized */ {
81 if (d.previousStatus === DirectionalDragArea.WaitingForTouch) {
82 dragEvaluator.reset();
83- d.startValue = parent[d.targetProp];
84+ if (overrideStartValue !== undefined) {
85+ d.startValue = overrideStartValue;
86+ } else {
87+ d.startValue = parent[d.targetProp];
88+ }
89
90 if (hintDisplacement > 0) {
91 hintingAnimation.targetValue = d.startValue;
92
93=== removed file 'qml/Components/ListItems/VerticalThinDivider.qml'
94--- qml/Components/ListItems/VerticalThinDivider.qml 2013-06-05 22:03:08 +0000
95+++ qml/Components/ListItems/VerticalThinDivider.qml 1970-01-01 00:00:00 +0000
96@@ -1,26 +0,0 @@
97-/*
98- * Copyright (C) 2012 Canonical, Ltd.
99- *
100- * This program is free software; you can redistribute it and/or modify
101- * it under the terms of the GNU General Public License as published by
102- * the Free Software Foundation; version 3.
103- *
104- * This program is distributed in the hope that it will be useful,
105- * but WITHOUT ANY WARRANTY; without even the implied warranty of
106- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
107- * GNU General Public License for more details.
108- *
109- * You should have received a copy of the GNU General Public License
110- * along with this program. If not, see <http://www.gnu.org/licenses/>.
111- */
112-
113-import QtQuick 2.0
114-
115-Image {
116- anchors {
117- top: (parent) ? parent.top : null
118- bottom: (parent) ? parent.bottom : null
119- }
120- width: (visible) ? units.dp(2) : 0
121- source: "graphics/ListItemDividerVertical.png"
122-}
123
124=== removed file 'qml/Components/ListItems/graphics/ListItemDividerVertical@18.png'
125Binary files qml/Components/ListItems/graphics/ListItemDividerVertical@18.png 2013-06-05 22:03:08 +0000 and qml/Components/ListItems/graphics/ListItemDividerVertical@18.png 1970-01-01 00:00:00 +0000 differ
126=== added file 'qml/Components/ScrollCalculator.qml'
127--- qml/Components/ScrollCalculator.qml 1970-01-01 00:00:00 +0000
128+++ qml/Components/ScrollCalculator.qml 2014-10-15 16:33:46 +0000
129@@ -0,0 +1,81 @@
130+/*
131+ * Copyright (C) 2014 Canonical, Ltd.
132+ *
133+ * This program is free software; you can redistribute it and/or modify
134+ * it under the terms of the GNU General Public License as published by
135+ * the Free Software Foundation; version 3.
136+ *
137+ * This program is distributed in the hope that it will be useful,
138+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
139+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
140+ * GNU General Public License for more details.
141+ *
142+ * You should have received a copy of the GNU General Public License
143+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
144+ */
145+
146+import QtQuick 2.2
147+import Ubuntu.Components 1.1
148+
149+Item {
150+ id: scrollArea
151+
152+ readonly property bool areaActive: lateralPosition >= 0
153+ property real stopScrollThreshold: units.gu(2)
154+ property int direction: Qt.LeftToRight
155+ property real baseScrollAmount: units.dp(3)
156+ property real maximumScrollAmount: units.dp(8)
157+ property real lateralPosition: -1
158+ property real forceScrollingPercentage: 0.4
159+
160+ signal scroll(real scrollAmount)
161+
162+ width: units.gu(5)
163+ rotation: direction === Qt.LeftToRight ? 0 : 180
164+
165+ onAreaActiveChanged: areaActive ? handleEnter() : handleExit()
166+
167+ function handleEnter() {
168+ d.thresholdAreaX = -scrollArea.stopScrollThreshold;
169+ scrollTimer.restart();
170+ }
171+
172+ function handleExit() {
173+ d.thresholdAreaX = -scrollArea.stopScrollThreshold;
174+ scrollTimer.stop();
175+ }
176+
177+ onLateralPositionChanged: {
178+ if (scrollArea.areaActive) {
179+ if (lateralPosition > width * (1 - forceScrollingPercentage)) {
180+ d.thresholdAreaX = width * (1 - forceScrollingPercentage);
181+ if (!scrollTimer.running) scrollTimer.restart();
182+ } else if (lateralPosition > d.thresholdAreaX + scrollArea.stopScrollThreshold) {
183+ d.thresholdAreaX = lateralPosition - scrollArea.stopScrollThreshold;
184+ if (!scrollTimer.running) scrollTimer.restart();
185+ } else if (lateralPosition < d.thresholdAreaX) {
186+ d.thresholdAreaX = lateralPosition;
187+ scrollTimer.stop();
188+ }
189+
190+ d.progression = lateralPosition / width;
191+ }
192+ }
193+
194+ Timer {
195+ id: scrollTimer
196+ interval: 16
197+ repeat: true
198+
199+ onTriggered: {
200+ var scrollAmount = scrollArea.baseScrollAmount + scrollArea.maximumScrollAmount * d.progression;
201+ scrollArea.scroll(scrollAmount);
202+ }
203+ }
204+
205+ QtObject {
206+ id: d
207+ property real progression: 0
208+ property real thresholdAreaX: -scrollArea.stopScrollThreshold
209+ }
210+}
211
212=== added file 'qml/Panel/Handle.qml'
213--- qml/Panel/Handle.qml 1970-01-01 00:00:00 +0000
214+++ qml/Panel/Handle.qml 2014-10-15 16:33:46 +0000
215@@ -0,0 +1,43 @@
216+/*
217+ * Copyright (C) 2014 Canonical, Ltd.
218+ *
219+ * This program is free software; you can redistribute it and/or modify
220+ * it under the terms of the GNU General Public License as published by
221+ * the Free Software Foundation; version 3.
222+ *
223+ * This program is distributed in the hope that it will be useful,
224+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
225+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
226+ * GNU General Public License for more details.
227+ *
228+ * You should have received a copy of the GNU General Public License
229+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
230+ */
231+
232+import QtQuick 2.2
233+import Ubuntu.Components 1.1
234+
235+Rectangle {
236+ id: handle
237+ color: "#333333"
238+ height: units.gu(2)
239+ property bool active: false
240+
241+ Row {
242+ id: dots
243+ width: childrenRect.width
244+ height: childrenRect.height
245+ anchors.centerIn: parent
246+ spacing: units.gu(0.5)
247+ Repeater {
248+ model: 3
249+ delegate: Rectangle {
250+ id: dot
251+ width: units.dp(3)
252+ height: width
253+ color: handle.active ? "#de4814" : "#717171"
254+ radius: units.dp(1)
255+ }
256+ }
257+ }
258+}
259
260=== removed file 'qml/Panel/IndicatorItem.qml'
261--- qml/Panel/IndicatorItem.qml 2014-09-29 10:24:58 +0000
262+++ qml/Panel/IndicatorItem.qml 1970-01-01 00:00:00 +0000
263@@ -1,53 +0,0 @@
264-/*
265- * Copyright (C) 2013 Canonical, Ltd.
266- *
267- * This program is free software; you can redistribute it and/or modify
268- * it under the terms of the GNU General Public License as published by
269- * the Free Software Foundation; version 3.
270- *
271- * This program is distributed in the hope that it will be useful,
272- * but WITHOUT ANY WARRANTY; without even the implied warranty of
273- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
274- * GNU General Public License for more details.
275- *
276- * You should have received a copy of the GNU General Public License
277- * along with this program. If not, see <http://www.gnu.org/licenses/>.
278- */
279-
280-import QtQuick 2.0
281-import Ubuntu.Components 0.1
282-import Unity.Indicators 0.1 as Indicators
283-import "../Components"
284-
285-Loader {
286- id: root
287-
288- property alias widgetSource: root.source
289- property bool dimmed: false
290- property var indicatorProperties: undefined
291- property bool indicatorVisible: item ? item.enabled : false
292- property string identifier
293-
294- opacity: dimmed ? 0.4 : 1
295- Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.BriskDuration } }
296-
297- onLoaded: {
298- for(var pName in indicatorProperties) {
299- if (item.hasOwnProperty(pName)) {
300- item[pName] = indicatorProperties[pName];
301- }
302- }
303- }
304-
305- Binding {
306- target: item
307- property: "identifier"
308- value: identifier
309- }
310-
311- Binding {
312- target: item
313- property: "objectName"
314- value: identifier + "-widget"
315- }
316-}
317
318=== added file 'qml/Panel/IndicatorItemRow.qml'
319--- qml/Panel/IndicatorItemRow.qml 1970-01-01 00:00:00 +0000
320+++ qml/Panel/IndicatorItemRow.qml 2014-10-15 16:33:46 +0000
321@@ -0,0 +1,256 @@
322+/*
323+ * Copyright (C) 2013-2014 Canonical, Ltd.
324+ *
325+ * This program is free software; you can redistribute it and/or modify
326+ * it under the terms of the GNU General Public License as published by
327+ * the Free Software Foundation; version 3.
328+ *
329+ * This program is distributed in the hope that it will be useful,
330+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
331+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
332+ * GNU General Public License for more details.
333+ *
334+ * You should have received a copy of the GNU General Public License
335+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
336+ */
337+
338+import QtQuick 2.2
339+import Ubuntu.Components 1.1
340+
341+Item {
342+ id: root
343+ width: row.width
344+ height: units.gu(3)
345+
346+ property QtObject indicatorsModel: null
347+ property real overFlowWidth: width
348+ property bool expanded: false
349+ property var currentItem
350+ readonly property int currentItemIndex: currentItem ? currentItem.ownIndex : -1
351+
352+ property real unitProgress: 0.0
353+ property real selectionChangeBuffer: units.gu(2)
354+ property bool enableLateralChanges: false
355+ property color hightlightColor: "#ededed"
356+
357+ property real lateralPosition: -1
358+ onLateralPositionChanged: {
359+ updateItemFromLateralPosition();
360+ }
361+
362+ onEnableLateralChangesChanged: {
363+ updateItemFromLateralPosition();
364+ }
365+
366+ function updateItemFromLateralPosition() {
367+ if (currentItem && !enableLateralChanges) return;
368+ if (lateralPosition === -1) return;
369+
370+ if (!currentItem) {
371+ selectItemAt(lateralPosition);
372+ return;
373+ }
374+
375+ var maximumBufferOffset = selectionChangeBuffer * unitProgress;
376+ var proposedItem = indicatorAt(lateralPosition, 0);
377+ if (proposedItem) {
378+ var bufferExceeded = false;
379+
380+ if (proposedItem !== currentItem) {
381+ // Proposed item is not directly adjacent to current?
382+ if (Math.abs(proposedItem.ownIndex - currentItem.ownIndex) > 1) {
383+ bufferExceeded = true;
384+ } else { // no
385+ var currentItemLateralPosition = root.mapToItem(proposedItem, lateralPosition, 0).x;
386+
387+ // Is the distance into proposed item greater than max buffer?
388+ // Proposed item is before current item
389+ if (proposedItem.x < currentItem.x) {
390+ bufferExceeded = (proposedItem.width - currentItemLateralPosition) > maximumBufferOffset;
391+ } else { // After
392+ bufferExceeded = currentItemLateralPosition > maximumBufferOffset;
393+ }
394+ }
395+ if (bufferExceeded) {
396+ selectItemAt(lateralPosition);
397+ }
398+ }
399+ } else {
400+ selectItemAt(lateralPosition);
401+ }
402+ }
403+
404+ function indicatorAt(x, y) {
405+ var item = row.childAt(x, y);
406+ return item && item.hasOwnProperty("ownIndex") ? item : null;
407+ }
408+
409+ function resetCurrentItem() {
410+ d.firstItemSwitch = true;
411+ d.previousItem = undefined;
412+ currentItem = undefined;
413+ }
414+
415+ function setCurrentItemIndex(index) {
416+ for (var i = 0; i < row.children.length; i++) {
417+ var item = row.children[i];
418+ if (item.hasOwnProperty("ownIndex") && item.ownIndex === index) {
419+ if (currentItem !== item) currentItem = item;
420+ break;
421+ }
422+ }
423+ }
424+
425+ function selectItemAt(lateralPosition) {
426+ var item = indicatorAt(lateralPosition, 0);
427+ if (item && item.opacity > 0) {
428+ currentItem = item;
429+ } else {
430+ // Select default item.
431+ var searchIndex = lateralPosition > width ? repeater.count - 1 : 0;
432+
433+ for (var i = 0; i < row.children.length; i++) {
434+ if (row.children[i].hasOwnProperty("ownIndex") && row.children[i].ownIndex === searchIndex) {
435+ item = row.children[i];
436+ break;
437+ }
438+ }
439+ if (currentItem !== item) currentItem = item;
440+ }
441+ }
442+
443+ QtObject {
444+ id: d
445+ property bool firstItemSwitch: true
446+ property var previousItem
447+ }
448+
449+ onCurrentItemChanged: {
450+ if (d.previousItem) {
451+ d.firstItemSwitch = false;
452+ }
453+ d.previousItem = currentItem;
454+ }
455+
456+ Row {
457+ id: row
458+ anchors {
459+ top: parent.top
460+ bottom: parent.bottom
461+ }
462+
463+ Repeater {
464+ id: repeater
465+ model: indicatorsModel
466+ visible: false
467+
468+ onItemRemoved: {
469+ // current item removed.
470+ if (currentItem === item) {
471+ var i = 0;
472+ while (i < row.children.length) {
473+ var childItem = row.children[i];
474+ if (childItem !== item) {
475+ setCurrentItemIndex(i);
476+ break;
477+ }
478+ i++;
479+ }
480+ }
481+ }
482+
483+ delegate: IndicatorItem {
484+ id: item
485+ objectName: identifier+"-panelItem"
486+
487+ property int ownIndex: index
488+ property bool overflow: row.width - x > overFlowWidth
489+ property bool hidden: !item.expanded && overflow
490+
491+ height: row.height
492+ expanded: root.expanded
493+ selected: currentItem === this
494+
495+ identifier: model.identifier
496+ busName: indicatorProperties.busName
497+ actionsObjectPath: indicatorProperties.actionsObjectPath
498+ menuObjectPath: indicatorProperties.menuObjectPath
499+
500+ opacity: hidden ? 0.0 : 1.0
501+ Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.SnapDuration } }
502+ }
503+ }
504+ }
505+
506+ Rectangle {
507+ id: highlight
508+ objectName: "highlight"
509+
510+ anchors.bottom: row.bottom
511+ height: units.dp(2)
512+ color: root.hightlightColor
513+ visible: currentItem !== undefined
514+ opacity: 0.0
515+
516+ width: currentItem ? currentItem.width : 0
517+ Behavior on width {
518+ enabled: !d.firstItemSwitch && expanded
519+ UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration; easing: UbuntuAnimation.StandardEasing }
520+ }
521+
522+ // micromovements of the highlight line when user moves the finger across the items while pulling
523+ // the handle downwards.
524+ property real highlightCenterOffset: {
525+ if (!currentItem || lateralPosition == -1 || !enableLateralChanges) return 0;
526+
527+ var itemMapped = root.mapToItem(currentItem, lateralPosition, 0);
528+
529+ var distanceFromCenter = itemMapped.x - currentItem.width / 2;
530+ if (distanceFromCenter > 0) {
531+ distanceFromCenter = Math.max(0, distanceFromCenter - currentItem.width / 8);
532+ } else {
533+ distanceFromCenter = Math.min(0, distanceFromCenter + currentItem.width / 8);
534+ }
535+
536+ if (currentItem && currentItem.ownIndex === 0 && distanceFromCenter < 0) {
537+ return 0;
538+ } else if (currentItem && currentItem.ownIndex === repeater.count-1 & distanceFromCenter > 0) {
539+ return 0;
540+ }
541+ return (distanceFromCenter / (currentItem.width / 4)) * units.gu(1);
542+ }
543+ Behavior on highlightCenterOffset {
544+ NumberAnimation { duration: UbuntuAnimation.FastDuration; easing: UbuntuAnimation.StandardEasing }
545+ }
546+
547+ property real currentItemX: currentItem ? currentItem.x : 0
548+ Behavior on currentItemX {
549+ id: currentItemXBehavior
550+ enabled: !d.firstItemSwitch && expanded
551+ NumberAnimation { duration: UbuntuAnimation.FastDuration; easing: UbuntuAnimation.StandardEasing }
552+ }
553+ x: currentItemX + highlightCenterOffset
554+ }
555+
556+ states: [
557+ State {
558+ name: "minimised"
559+ when: !expanded
560+ },
561+ State {
562+ name: "expanded"
563+ when: expanded
564+ PropertyChanges { target: highlight; opacity: 0.9 }
565+ }
566+ ]
567+
568+ transitions: [
569+ Transition {
570+ PropertyAnimation {
571+ properties: "opacity";
572+ duration: UbuntuAnimation.SnapDuration
573+ easing: UbuntuAnimation.StandardEasing
574+ }
575+ }
576+ ]
577+}
578
579=== renamed file 'qml/Panel/Indicators/DefaultIndicatorPage.qml' => 'qml/Panel/IndicatorPage.qml'
580--- qml/Panel/Indicators/DefaultIndicatorPage.qml 2014-09-29 10:24:58 +0000
581+++ qml/Panel/IndicatorPage.qml 2014-10-15 16:33:46 +0000
582@@ -1,5 +1,5 @@
583 /*
584- * Copyright 2013 Canonical Ltd.
585+ * Copyright 2013-2014 Canonical Ltd.
586 *
587 * This program is free software; you can redistribute it and/or modify
588 * it under the terms of the GNU Lesser General Public License as published by
589@@ -12,15 +12,12 @@
590 *
591 * You should have received a copy of the GNU Lesser General Public License
592 * along with this program. If not, see <http://www.gnu.org/licenses/>.
593- *
594- * Authors:
595- * Renato Araujo Oliveira Filho <renato@canonical.com>
596- * Nick Dedekind <nick.dedekind@canonical.com>
597 */
598
599 import QtQuick 2.0
600 import Ubuntu.Components 0.1 as Components
601 import Unity.Indicators 0.1 as Indicators
602+import "Indicators"
603
604 IndicatorBase {
605 id: main
606@@ -125,7 +122,6 @@
607 delegate: Loader {
608 id: loader
609 objectName: "menuItem" + index
610- asynchronous: true
611 width: ListView.view.width
612 visible: status == Loader.Ready
613
614
615=== removed file 'qml/Panel/IndicatorRow.qml'
616--- qml/Panel/IndicatorRow.qml 2014-05-07 13:59:58 +0000
617+++ qml/Panel/IndicatorRow.qml 1970-01-01 00:00:00 +0000
618@@ -1,162 +0,0 @@
619-/*
620- * Copyright (C) 2013 Canonical, Ltd.
621- *
622- * This program is free software; you can redistribute it and/or modify
623- * it under the terms of the GNU General Public License as published by
624- * the Free Software Foundation; version 3.
625- *
626- * This program is distributed in the hope that it will be useful,
627- * but WITHOUT ANY WARRANTY; without even the implied warranty of
628- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
629- * GNU General Public License for more details.
630- *
631- * You should have received a copy of the GNU General Public License
632- * along with this program. If not, see <http://www.gnu.org/licenses/>.
633- */
634-
635-import QtQuick 2.0
636-import Ubuntu.Components 0.1
637-import Unity.Indicators 0.1 as Indicators
638-import "../Components"
639-
640-Item {
641- id: indicatorRow
642-
643- readonly property alias currentItem : itemView.currentItem
644- readonly property alias currentItemIndex: itemView.currentIndex
645- readonly property alias row: itemView
646- property QtObject indicatorsModel: null
647- property int overFlowWidth: width
648- property bool showAll: false
649- property real currentItemOffset: 0.0
650- property real unitProgress: 0.0
651-
652- width: units.gu(40)
653- height: units.gu(3)
654-
655- function setDefaultItem() {
656- // The leftmost indicator
657- setCurrentItemIndex(0);
658- }
659-
660- function setCurrentItemIndex(index) {
661- itemView.currentIndex = index;
662- }
663-
664- function setCurrentItem(item) {
665- if (item && item.hasOwnProperty("ownIndex")) {
666- itemView.currentIndex = item.ownIndex;
667- } else {
668- itemView.currentIndex = -1;
669- }
670- }
671-
672- Timer {
673- id: allVisible
674- interval: 1000
675-
676- onTriggered: {
677- showAll = false;
678- }
679- }
680-
681- ListView {
682- id: itemView
683- objectName: "indicatorRowItems"
684- interactive: false
685- model: indicatorsModel ? indicatorsModel : null
686-
687- width: childrenRect.width
688- height: indicatorRow.height
689- anchors.right: parent.right
690- orientation: ListView.Horizontal
691-
692- property int lastCount: 0
693- onCountChanged: {
694- if (lastCount < count) {
695- showAll = true;
696- allVisible.start();
697- }
698- lastCount = count;
699- }
700-
701- delegate: Item {
702- id: itemWrapper
703- objectName: "item" + index
704- height: indicatorRow.height
705- width: indicatorItem.width
706- opacity: 1 - indicatorRow.unitProgress
707- y: 0
708- state: "standard"
709-
710- property int ownIndex: index
711- property bool highlighted: indicatorRow.unitProgress > 0 ? ListView.isCurrentItem : false
712- property bool dimmed: indicatorRow.unitProgress > 0 ? !ListView.isCurrentItem : false
713-
714- property bool hidden: !showAll && !highlighted && (indicatorRow.state == "locked" || indicatorRow.state == "commit")
715- property bool overflow: row.width - itemWrapper.x > overFlowWidth
716-
717- IndicatorItem {
718- id: indicatorItem
719- identifier: model.identifier
720- height: parent.height
721-
722- dimmed: itemWrapper.dimmed
723-
724- widgetSource: model.widgetSource
725- indicatorProperties : model.indicatorProperties
726- }
727-
728- states: [
729- State {
730- name: "standard"
731- when: !hidden && !overflow && !highlighted
732- },
733- State {
734- name: "highlighted"
735- when: highlighted
736- PropertyChanges { target: itemWrapper; opacity: 1.0 }
737- },
738- State {
739- name: "hidden"
740- when: hidden || overflow
741- PropertyChanges { target: itemWrapper; opacity: 0.0 }
742- }
743- ]
744-
745- Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.BriskDuration } }
746- }
747- }
748-
749-
750- Rectangle {
751- id: highlight
752- color: Theme.palette.selected.foreground
753- objectName: "highlight"
754- height: units.dp(2)
755- anchors.top: row.bottom
756- visible: indicatorRow.currentItem != null
757-
758- property real intendedX: row.x + (indicatorRow.currentItem != null ? (indicatorRow.currentItem.x - row.originX) + centerOffset : 0)
759- x: intendedX >= row.x ? (intendedX + width <= row.x + row.width ? intendedX : row.x + row.width - width) : row.x // listview boundaries
760- width: indicatorRow.currentItem != null ? indicatorRow.currentItem.width : 0
761-
762- property real centerOffset: {
763- if (indicatorRow.currentItemOffset > 0.1) {
764- return (indicatorRow.currentItemOffset - 0.1) * units.gu(0.4);
765- } else if (indicatorRow.currentItemOffset < -0.1) {
766- return (indicatorRow.currentItemOffset + 0.1) * units.gu(0.4);
767- }
768- return 0.0;
769- }
770-
771- Behavior on width {
772- enabled: unitProgress > 0;
773- UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration }
774- }
775- Behavior on x {
776- enabled: unitProgress > 0;
777- UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration }
778- }
779- }
780-}
781
782=== removed file 'qml/Panel/Indicators.qml'
783--- qml/Panel/Indicators.qml 2014-09-09 13:40:41 +0000
784+++ qml/Panel/Indicators.qml 1970-01-01 00:00:00 +0000
785@@ -1,415 +0,0 @@
786-/*
787- * Copyright (C) 2013 Canonical, Ltd.
788- *
789- * This program is free software; you can redistribute it and/or modify
790- * it under the terms of the GNU General Public License as published by
791- * the Free Software Foundation; version 3.
792- *
793- * This program is distributed in the hope that it will be useful,
794- * but WITHOUT ANY WARRANTY; without even the implied warranty of
795- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
796- * GNU General Public License for more details.
797- *
798- * You should have received a copy of the GNU General Public License
799- * along with this program. If not, see <http://www.gnu.org/licenses/>.
800- */
801-
802-import QtQuick 2.0
803-import Ubuntu.Components 0.1
804-import Ubuntu.Gestures 0.1
805-import Unity.Indicators 0.1 as Indicators
806-
807-import "../Components"
808-import "../Components/ListItems"
809-import "Indicators"
810-
811-Showable {
812- id: indicators
813-
814- property real openedHeight: units.gu(71)
815- property int panelHeight: units.gu(3)
816- property alias overFlowWidth: indicatorRow.overFlowWidth
817- property alias showAll: indicatorRow.showAll
818- // TODO: This should be sourced by device type (eg "desktop", "tablet", "phone"...)
819- property string profile: indicatorProfile
820-
821- readonly property real hintValue: panelHeight + menuContent.headerHeight
822- readonly property int lockThreshold: openedHeight / 2
823- property bool fullyOpened: height == openedHeight
824- property bool partiallyOpened: height > panelHeight && !fullyOpened
825- property bool fullyClosed: height <= panelHeight
826- property bool contentEnabled: true
827- property bool initalizeItem: true
828- readonly property alias content: menuContent
829- property real unitProgress: (height - panelHeight) / (openedHeight - panelHeight)
830- property bool enableHint: true
831- property real showHintBottomMargin: 0
832-
833- signal showTapped(point position)
834-
835- // TODO: Perhaps we need a animation standard for showing/hiding? Each showable seems to
836- // use its own values. Need to ask design about this.
837- showAnimation: StandardAnimation {
838- property: "height"
839- to: openedHeight
840- }
841-
842- hideAnimation: StandardAnimation {
843- property: "height"
844- duration: 350
845- to: panelHeight
846- easing.type: Easing.OutCubic
847- }
848-
849- onOpenedHeightChanged: {
850- if (showAnimation.running) {
851- showAnimation.restart();
852- } else if (indicators.shown) {
853- height = openedHeight;
854- }
855- }
856-
857- height: panelHeight
858- onHeightChanged: updateRevealProgressState(indicators.height - panelHeight - showHintBottomMargin, true)
859-
860- function updateRevealProgressState(revealProgress, enableRelease) {
861- if (!showAnimation.running && !hideAnimation.running) {
862- if (revealProgress === 0) {
863- indicators.state = "initial";
864- } else if (enableHint && revealProgress > 0 && revealProgress <= hintValue) {
865- indicators.state = "hint";
866- } else if ((!enableHint || revealProgress > hintValue) && revealProgress < lockThreshold) {
867- indicators.state = "reveal";
868- } else if (revealProgress >= lockThreshold && lockThreshold > 0) {
869- indicators.state = "locked";
870- }
871- }
872- }
873-
874- function calculateCurrentItem(xValue, useBuffer) {
875- var rowCoordinates;
876- var itemCoordinates;
877- var currentItem;
878- var distanceFromRightEdge;
879- var bufferExceeded = false;
880-
881- if (indicators.state == "commit" || indicators.state == "locked" || showAnimation.running || hideAnimation.running) return;
882-
883- /*
884- If user drags the indicator handle bar down a distance hintValue or less, this is 0.
885- If bar is dragged down a distance greater than or equal to lockThreshold, this is 1.
886- Otherwise it contains the bar's location as a fraction of the distance between hintValue (is 0) and lockThreshold (is 1).
887- */
888- var verticalProgress =
889- MathUtils.clamp((indicators.height - handle.height - hintValue) /
890- (lockThreshold - hintValue), 0, 1);
891-
892- /*
893- Vertical velocity check. Don't change the indicator if we're moving too quickly.
894- */
895- var verticalSpeed = Math.abs(yVelocityCalculator.calculate());
896- if (verticalSpeed >= 0.05 && !initalizeItem) {
897- return;
898- }
899-
900- /*
901- Percentage of an indicator icon's width the user's press can stray horizontally from the
902- focused icon before we change focus to another icon. E.g. a value of 0.5 means you must
903- go right a distance of half an icon's width before focus moves to the icon on the right
904- */
905- var maxBufferThreshold = 0.5;
906-
907- /*
908- To help users find the indicator of their choice while opening the indicators, we add logic to add a
909- left/right buffer to each icon so it is harder for the focus to be moved accidentally to another icon,
910- as the user moves their finger down, but yet allows them to switch indicator if they want.
911- This buffer is wider the further the user's finger is from the top of the screen.
912- */
913- var effectiveBufferThreshold = maxBufferThreshold * verticalProgress;
914-
915- rowCoordinates = indicatorRow.mapToItem(indicatorRow.row, xValue, 0);
916- // get the current delegate
917- currentItem = indicatorRow.row.itemAt(rowCoordinates.x, 0);
918- if (currentItem) {
919- itemCoordinates = indicatorRow.row.mapToItem(currentItem, rowCoordinates.x, 0);
920- distanceFromRightEdge = (currentItem.width - itemCoordinates.x) / (currentItem.width);
921- if (currentItem != indicatorRow.currentItem) {
922- if (Math.abs(currentItem.ownIndex - indicatorRow.currentItemIndex) > 1) {
923- bufferExceeded = true;
924- } else {
925- if (indicatorRow.currentItemIndex < currentItem.ownIndex && distanceFromRightEdge < (1 - effectiveBufferThreshold)) {
926- bufferExceeded = true;
927- } else if (indicatorRow.currentItemIndex > currentItem.ownIndex && distanceFromRightEdge > effectiveBufferThreshold) {
928- bufferExceeded = true;
929- }
930- }
931- if ((!useBuffer || (useBuffer && bufferExceeded)) || indicatorRow.currentItemIndex < 0 || indicatorRow.currentItem == null) {
932- indicatorRow.setCurrentItem(currentItem);
933- }
934-
935- // need to re-init the distanceFromRightEdge for offset calculation
936- itemCoordinates = indicatorRow.row.mapToItem(indicatorRow.currentItem, rowCoordinates.x, 0);
937- distanceFromRightEdge = (indicatorRow.currentItem.width - itemCoordinates.x) / (indicatorRow.currentItem.width);
938- }
939- indicatorRow.currentItemOffset = 1 - (distanceFromRightEdge * 2);
940- } else if (initalizeItem) {
941- indicatorRow.setDefaultItem();
942- indicatorRow.currentItemOffset = 0;
943- }
944- initalizeItem = indicatorRow.currentItem == null;
945- }
946-
947- // eater
948- MouseArea {
949- anchors {
950- top: parent.top
951- bottom: handle.bottom
952- left: parent.left
953- right: parent.right
954- }
955- }
956-
957- VisibleIndicators {
958- id: visibleIndicators
959- }
960-
961- MenuContent {
962- id: menuContent
963- objectName: "menuContent"
964-
965- anchors {
966- left: parent.left
967- right: parent.right
968- top: indicatorRow.bottom
969- bottom: handle.top
970- }
971- indicatorsModel: visibleIndicators.model
972- visible: indicators.partiallyOpened || indicators.fullyOpened
973- clip: indicators.partiallyOpened
974- enabled: contentEnabled
975-
976- //small shadow gradient at bottom of menu
977- Rectangle {
978- anchors {
979- left: parent.left
980- right: parent.right
981- bottom: parent.bottom
982- }
983- height: units.gu(0.5)
984- gradient: Gradient {
985- GradientStop { position: 0.0; color: "transparent" }
986- GradientStop { position: 1.0; color: "black" }
987- }
988- opacity: 0.4
989- }
990- }
991-
992- Rectangle {
993- id: handle
994-
995- color: menuContent.color
996-
997- anchors {
998- left: parent.left
999- right: parent.right
1000- bottom: parent.bottom
1001- }
1002- height: Math.max(Math.min(handleImage.height, indicators.height - handleImage.height), 0)
1003- clip: height < handleImage.height
1004- visible: menuContent.visible
1005-
1006- BorderImage {
1007- id: handleImage
1008- source: "graphics/handle.sci"
1009- height: panelHeight
1010- anchors {
1011- left: parent.left
1012- right: parent.right
1013- bottom: parent.bottom
1014- }
1015- }
1016- MouseArea { //prevent clicks passing through
1017- anchors.fill: parent
1018- }
1019- }
1020-
1021- IndicatorRow {
1022- id: indicatorRow
1023- objectName: "indicatorRow"
1024- anchors {
1025- left: parent.left
1026- right: parent.right
1027- }
1028- height: indicators.panelHeight
1029- indicatorsModel: visibleIndicators.model
1030- state: indicators.state
1031- unitProgress: indicators.unitProgress
1032-
1033- EdgeDragArea {
1034- id: rowDragArea
1035- anchors.fill: indicatorRow
1036- direction: Direction.Downwards
1037- maxSilenceTime: 2000
1038- distanceThreshold: 0
1039-
1040- enabled: fullyOpened
1041- onDraggingChanged: {
1042- if (dragging) {
1043- initalizeItem = true;
1044- updateRevealProgressState(Math.max(touchSceneY - panelHeight, hintValue), false);
1045- indicators.calculateCurrentItem(touchX, false);
1046- } else {
1047- indicators.state = "commit";
1048- indicatorRow.currentItemOffset = 0;
1049- }
1050- }
1051-
1052- onTouchXChanged: {
1053- indicators.calculateCurrentItem(touchX, true);
1054- }
1055- onTouchSceneYChanged: {
1056- updateRevealProgressState(Math.max(touchSceneY - panelHeight, hintValue), false);
1057- yVelocityCalculator.trackedPosition = touchSceneY;
1058- }
1059- }
1060- }
1061-
1062- Connections {
1063- target: showAnimation
1064- onRunningChanged: {
1065- if (showAnimation.running) {
1066- indicators.state = "commit";
1067- indicatorRow.currentItemOffset = 0;
1068- }
1069- }
1070- }
1071-
1072- Connections {
1073- target: hideAnimation
1074- onRunningChanged: {
1075- if (hideAnimation.running) {
1076- indicators.state = "initial";
1077- initalizeItem = true;
1078- indicatorRow.currentItemOffset = 0;
1079- }
1080- }
1081- }
1082-
1083- QtObject {
1084- id: d
1085- property bool enableIndexChangeSignal: true
1086- property var activeDragHandle: showDragHandle.dragging ? showDragHandle : hideDragHandle.dragging ? hideDragHandle : null
1087- }
1088-
1089- Connections {
1090- target: menuContent
1091- onCurrentMenuIndexChanged: {
1092- var oldActive = d.enableIndexChangeSignal;
1093- if (!oldActive) return;
1094- d.enableIndexChangeSignal = false;
1095-
1096- indicatorRow.setCurrentItemIndex(menuContent.currentMenuIndex);
1097-
1098- d.enableIndexChangeSignal = oldActive;
1099- }
1100- }
1101-
1102- Connections {
1103- target: indicatorRow
1104- onCurrentItemIndexChanged: {
1105- var oldActive = d.enableIndexChangeSignal;
1106- if (!oldActive) return;
1107- d.enableIndexChangeSignal = false;
1108-
1109- menuContent.setCurrentMenuIndex(indicatorRow.currentItemIndex, fullyOpened || partiallyOpened);
1110-
1111- d.enableIndexChangeSignal = oldActive;
1112- }
1113- }
1114- // connections to the active drag handle
1115- Connections {
1116- target: d.activeDragHandle
1117- onTouchXChanged: {
1118- indicators.calculateCurrentItem(d.activeDragHandle.touchX, true);
1119- }
1120- onTouchSceneYChanged: {
1121- yVelocityCalculator.trackedPosition = d.activeDragHandle.touchSceneY;
1122- }
1123- }
1124-
1125- DragHandle {
1126- id: showDragHandle
1127- anchors.bottom: parent.bottom
1128- // go beyond parent so that it stays reachable, at the top of the screen.
1129- anchors.bottomMargin: showHintBottomMargin
1130- anchors.left: parent.left
1131- anchors.right: parent.right
1132- height: panelHeight
1133- direction: Direction.Downwards
1134- enabled: !indicators.shown && indicators.available
1135- hintDisplacement: enableHint ? indicators.hintValue : 0
1136- autoCompleteDragThreshold: maxTotalDragDistance / 2
1137- stretch: true
1138- maxTotalDragDistance: openedHeight - panelHeight
1139- distanceThreshold: panelHeight
1140-
1141- onTapped: showTapped(Qt.point(touchSceneX, touchSceneY));
1142- }
1143-
1144- DragHandle {
1145- id: hideDragHandle
1146- anchors.fill: handle
1147- direction: Direction.Upwards
1148- enabled: indicators.shown && indicators.available
1149- hintDisplacement: indicators.hintValue
1150- autoCompleteDragThreshold: maxTotalDragDistance / 6
1151- stretch: true
1152- maxTotalDragDistance: openedHeight - panelHeight
1153- distanceThreshold: 0
1154- }
1155-
1156- AxisVelocityCalculator {
1157- id: yVelocityCalculator
1158- }
1159-
1160- states: [
1161- State {
1162- name: "initial"
1163- },
1164- State {
1165- name: "hint"
1166- StateChangeScript {
1167- script: {
1168- if (d.activeDragHandle) {
1169- calculateCurrentItem(d.activeDragHandle.touchX, false);
1170- }
1171- }
1172- }
1173- },
1174- State {
1175- name: "reveal"
1176- extend: "hint"
1177- },
1178- State {
1179- name: "locked"
1180- extend: "hint"
1181- },
1182- State {
1183- name: "commit"
1184- extend: "hint"
1185- }
1186- ]
1187- state: "initial"
1188-
1189- transitions: [
1190- Transition {
1191- NumberAnimation {targets: [indicatorRow, menuContent]; property: "y"; duration: 300; easing.type: Easing.OutCubic}
1192- }
1193- ]
1194-
1195- Component.onCompleted: initialise();
1196- function initialise() {
1197- visibleIndicators.load(profile);
1198- indicatorRow.setDefaultItem();
1199- }
1200-}
1201
1202=== removed file 'qml/Panel/Indicators/DefaultIndicatorWidget.qml'
1203--- qml/Panel/Indicators/DefaultIndicatorWidget.qml 2014-08-20 08:39:09 +0000
1204+++ qml/Panel/Indicators/DefaultIndicatorWidget.qml 1970-01-01 00:00:00 +0000
1205@@ -1,119 +0,0 @@
1206-/*
1207- * Copyright 2013 Canonical Ltd.
1208- *
1209- * This program is free software; you can redistribute it and/or modify
1210- * it under the terms of the GNU Lesser General Public License as published by
1211- * the Free Software Foundation; version 3.
1212- *
1213- * This program is distributed in the hope that it will be useful,
1214- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1215- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1216- * GNU Lesser General Public License for more details.
1217- *
1218- * You should have received a copy of the GNU Lesser General Public License
1219- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1220- *
1221- * Authors:
1222- * Nick Dedekind <nick.dedekind@canonical.com>
1223- */
1224-
1225-import QtQuick 2.0
1226-import Ubuntu.Components 0.1
1227-import Ubuntu.Settings.Components 0.1
1228-
1229-IndicatorBase {
1230- id: indicatorWidget
1231-
1232- property int iconSize: units.gu(2)
1233- property alias leftLabel: itemLeftLabel.text
1234- property alias rightLabel: itemRightLabel.text
1235- property var icons: undefined
1236-
1237- width: itemRow.width
1238- enabled: false
1239-
1240- // FIXME: For now we will enable led indicator support only for messaging indicator
1241- // in the future we should export a led API insted of doing that,
1242- Loader {
1243- id: indicatorLed
1244- // only load source Component if the icons contains the new message icon
1245- source: (indicatorWidget.icons && (String(indicatorWidget.icons).indexOf("indicator-messages-new") != -1)) ? Qt.resolvedUrl("IndicatorsLight.qml") : ""
1246- }
1247-
1248- Row {
1249- id: itemRow
1250- objectName: "itemRow"
1251- anchors {
1252- top: parent.top
1253- bottom: parent.bottom
1254- horizontalCenter: parent.horizontalCenter
1255- }
1256-
1257- Label {
1258- id: itemLeftLabel
1259- width: contentWidth + units.gu(1)
1260- objectName: "leftLabel"
1261- color: Theme.palette.selected.backgroundText
1262- opacity: 0.8
1263- font.family: "Ubuntu"
1264- fontSize: "medium"
1265- anchors.verticalCenter: parent.verticalCenter
1266- visible: text != ""
1267- horizontalAlignment: Text.AlignHCenter
1268- }
1269-
1270- Row {
1271- id: iconRow
1272- anchors {
1273- top: parent.top
1274- bottom: parent.bottom
1275- }
1276-
1277- Repeater {
1278- model: indicatorWidget.icons
1279-
1280- Item {
1281- width: itemImage.width + units.gu(1)
1282- height: iconRow.height
1283-
1284- StatusIcon {
1285- id: itemImage
1286- height: indicatorWidget.iconSize
1287- anchors.centerIn: parent
1288- source: modelData
1289- sets: ["status", "actions"]
1290- color: "#CCCCCC"
1291- }
1292- }
1293- }
1294- }
1295-
1296- Label {
1297- id: itemRightLabel
1298- width: contentWidth + units.gu(1)
1299- objectName: "rightLabel"
1300- color: Theme.palette.selected.backgroundText
1301- opacity: 0.8
1302- font.family: "Ubuntu"
1303- fontSize: "medium"
1304- anchors.verticalCenter: parent.verticalCenter
1305- visible: text != ""
1306- horizontalAlignment: Text.AlignHCenter
1307- }
1308- }
1309-
1310- onRootActionStateChanged: {
1311- if (rootActionState == undefined) {
1312- leftLabel = "";
1313- rightLabel = "";
1314- icons = undefined;
1315- enabled = false;
1316- return;
1317- }
1318-
1319- leftLabel = rootActionState.leftLabel ? rootActionState.leftLabel : "";
1320- rightLabel = rootActionState.rightLabel ? rootActionState.rightLabel : "";
1321- icons = rootActionState.icons;
1322- enabled = rootActionState.visible;
1323- }
1324-}
1325
1326=== modified file 'qml/Panel/Indicators/IndicatorBase.qml'
1327--- qml/Panel/Indicators/IndicatorBase.qml 2014-10-15 16:33:45 +0000
1328+++ qml/Panel/Indicators/IndicatorBase.qml 2014-10-15 16:33:46 +0000
1329@@ -32,8 +32,6 @@
1330 property string menuObjectPath
1331 property string rootMenuType: "com.canonical.indicator.root"
1332
1333- property string deviceMenuObjectPath: menuObjectPath
1334-
1335 property alias menuModel: cachedModel.model
1336 property alias rootActionState: rootAction
1337
1338@@ -41,7 +39,7 @@
1339 id: cachedModel
1340 busName: indicatorItem.busName
1341 actions: { "indicator": indicatorItem.actionsObjectPath }
1342- menuObjectPath: indicatorItem.deviceMenuObjectPath
1343+ menuObjectPath: indicatorItem.menuObjectPath
1344 }
1345
1346 RootActionState {
1347
1348=== modified file 'qml/Panel/Indicators/VisibleIndicators.qml'
1349--- qml/Panel/Indicators/VisibleIndicators.qml 2014-09-29 10:24:58 +0000
1350+++ qml/Panel/Indicators/VisibleIndicators.qml 2014-10-15 16:33:46 +0000
1351@@ -24,6 +24,10 @@
1352 Item {
1353 property SortFilterProxyModel model: filterModel
1354
1355+ function initialise(profile) {
1356+ indicatorsModel.load(profile);
1357+ }
1358+
1359 SortFilterProxyModel {
1360 id: filterModel
1361 filterRole: Indicators.IndicatorsModelRole.IsVisible
1362@@ -36,7 +40,6 @@
1363 }
1364 }
1365
1366-
1367 Indicators.IndicatorsModel {
1368 id: indicatorsModel
1369 }
1370@@ -78,8 +81,4 @@
1371 }
1372 }
1373 }
1374-
1375- function load(profile) {
1376- indicatorsModel.load(profile);
1377- }
1378 }
1379
1380=== renamed file 'qml/Panel/Indicators/client/IndicatorsPage.qml' => 'qml/Panel/Indicators/client/IndicatorRepresentation.qml'
1381--- qml/Panel/Indicators/client/IndicatorsPage.qml 2013-08-14 09:07:45 +0000
1382+++ qml/Panel/Indicators/client/IndicatorRepresentation.qml 2014-10-15 16:33:46 +0000
1383@@ -21,13 +21,13 @@
1384 import QtQuick 2.0
1385 import Ubuntu.Components 0.1
1386 import Ubuntu.Components.ListItems 0.1 as ListItem
1387+import "../.."
1388
1389 Page {
1390- id: page
1391+ id: root
1392
1393 title: indicatorProperties && indicatorProperties.title ? indicatorProperties.title : ""
1394 property variant indicatorProperties
1395- property string pageSource : pageLoader.source
1396
1397 anchors.fill: parent
1398
1399@@ -44,6 +44,7 @@
1400 id: pageLoader
1401 objectName: "pageLoader"
1402 clip:true
1403+ asynchronous: true
1404
1405 Rectangle {
1406 anchors.fill: pageLoader
1407@@ -58,15 +59,25 @@
1408 topMargin: units.gu(2)
1409 bottomMargin: units.gu(2)
1410 }
1411- source : visualCheck.checked ? page.pageSource : "IndicatorsTree.qml"
1412+ sourceComponent: visualCheck.checked ? page : tree
1413
1414- onLoaded: {
1415- for(var pName in indicatorProperties) {
1416- if (item.hasOwnProperty(pName)) {
1417- item[pName] = indicatorProperties[pName];
1418- }
1419- }
1420- item.start();
1421+ Component {
1422+ id: page
1423+ IndicatorPage {
1424+ identifier: model.identifier
1425+ busName: indicatorProperties.busName
1426+ actionsObjectPath: indicatorProperties.actionsObjectPath
1427+ menuObjectPath: indicatorProperties.menuObjectPath
1428+ }
1429+ }
1430+ Component {
1431+ id: tree
1432+ IndicatorsTree {
1433+ identifier: model.identifier
1434+ busName: indicatorProperties.busName
1435+ actionsObjectPath: indicatorProperties.actionsObjectPath
1436+ menuObjectPath: indicatorProperties.menuObjectPath
1437+ }
1438 }
1439 }
1440
1441@@ -85,7 +96,7 @@
1442 left: parent.left
1443 }
1444 text: "Back"
1445- onClicked: page.pageStack.reset()
1446+ onClicked: root.pageStack.reset()
1447 }
1448 }
1449 }
1450
1451=== modified file 'qml/Panel/Indicators/client/IndicatorsList.qml'
1452--- qml/Panel/Indicators/client/IndicatorsList.qml 2014-01-30 14:54:01 +0000
1453+++ qml/Panel/Indicators/client/IndicatorsList.qml 2014-10-15 16:33:46 +0000
1454@@ -57,8 +57,8 @@
1455 text: identifier
1456
1457 onClicked: {
1458- var new_page = Qt.createComponent("IndicatorsPage.qml");
1459- page.pageStack.push(new_page.createObject(pages), {"indicatorProperties" : model.indicatorProperties, "pageSource" : model.pageSource});
1460+ var new_page = Qt.createComponent("IndicatorRepresentation.qml");
1461+ page.pageStack.push(new_page.createObject(pages), {"indicatorProperties" : model.indicatorProperties });
1462 }
1463 }
1464 }
1465
1466=== modified file 'qml/Panel/Indicators/client/IndicatorsTree.qml'
1467--- qml/Panel/Indicators/client/IndicatorsTree.qml 2013-11-24 02:23:56 +0000
1468+++ qml/Panel/Indicators/client/IndicatorsTree.qml 2014-10-15 16:33:46 +0000
1469@@ -20,36 +20,14 @@
1470 import QtQuick 2.0
1471 import Ubuntu.Components 0.1
1472 import Unity.Indicators 0.1 as Indicators
1473-import QMenuModel 0.1
1474-import Ubuntu.Components.ListItems 0.1 as ListItem
1475-
1476-Page {
1477- id: page
1478- anchors.fill: parent
1479-
1480- property string busName: unityModel.busName
1481- property string actionsObjectPath
1482- property string menuObjectPath
1483-
1484- property string deviceMenuObjectPath: menuObjectPath
1485-
1486- function start() {
1487- }
1488-
1489- UnityMenuModel {
1490- id: unityModel
1491- busName: page.busName
1492- actions: { "indicator": page.actionsObjectPath }
1493- menuObjectPath: page.deviceMenuObjectPath
1494- }
1495-
1496- Indicators.RootActionState {
1497- menu: unityModel
1498- }
1499+import ".."
1500+
1501+IndicatorBase {
1502+ id: root
1503
1504 Indicators.ModelPrinter {
1505 id: printer
1506- model: unityModel
1507+ model: root.menuModel
1508 }
1509
1510 Flickable {
1511
1512=== added file 'qml/Panel/IndicatorsBar.qml'
1513--- qml/Panel/IndicatorsBar.qml 1970-01-01 00:00:00 +0000
1514+++ qml/Panel/IndicatorsBar.qml 2014-10-15 16:33:46 +0000
1515@@ -0,0 +1,260 @@
1516+/*
1517+ * Copyright (C) 2014 Canonical, Ltd.
1518+ *
1519+ * This program is free software; you can redistribute it and/or modify
1520+ * it under the terms of the GNU General Public License as published by
1521+ * the Free Software Foundation; version 3.
1522+ *
1523+ * This program is distributed in the hope that it will be useful,
1524+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1525+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1526+ * GNU General Public License for more details.
1527+ *
1528+ * You should have received a copy of the GNU General Public License
1529+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1530+ */
1531+
1532+import QtQuick 2.2
1533+import Ubuntu.Components 1.1
1534+import "../Components"
1535+
1536+Item {
1537+ id: root
1538+ property alias expanded: row.expanded
1539+ property alias interactive: flickable.interactive
1540+ property alias indicatorsModel: row.indicatorsModel
1541+ property alias unitProgress: row.unitProgress
1542+ property alias enableLateralChanges: row.enableLateralChanges
1543+ property alias overFlowWidth: row.overFlowWidth
1544+ readonly property alias currentItemIndex: row.currentItemIndex
1545+ property real lateralPosition: -1
1546+
1547+ function selectItemAt(lateralPosition) {
1548+ if (!expanded) {
1549+ row.resetCurrentItem();
1550+ }
1551+ var mapped = root.mapToItem(row, lateralPosition, 0);
1552+ row.selectItemAt(mapped.x);
1553+ }
1554+
1555+ function setCurrentItemIndex(index) {
1556+ if (!expanded) {
1557+ row.resetCurrentItem();
1558+ }
1559+ row.setCurrentItemIndex(index);
1560+ }
1561+
1562+ function addScrollOffset(scrollAmmout) {
1563+ if (scrollAmmout < 0) { // left scroll
1564+ if (flickable.contentX < 0) return; // already off the left.
1565+ if (flickable.contentX + scrollAmmout < 0) scrollAmmout = -flickable.contentX; // going to be off the left
1566+ } else { // right scroll
1567+ if (flickable.contentX + flickable.width > row.width) return; // already off the right.
1568+ if (flickable.contentX + flickable.width + scrollAmmout > row.width) { // going to be off the right
1569+ scrollAmmout = row.width - (flickable.contentX + flickable.width);
1570+ }
1571+ }
1572+ d.scrollOffset = d.scrollOffset + scrollAmmout;
1573+ }
1574+
1575+ QtObject {
1576+ id: d
1577+ property var initialItem
1578+ // the non-expanded distance from row offset to center of initial item
1579+ property real originalDistanceFromRight: -1
1580+
1581+ // calculate the distance from row offset to center of initial item
1582+ property real distanceFromRight: {
1583+ if (originalDistanceFromRight == -1) return 0;
1584+ if (!initialItem) return 0;
1585+ return row.width - initialItem.x - initialItem.width /2;
1586+ }
1587+
1588+ // offset to the intially selected expanded item
1589+ property real rowOffset: 0
1590+ property real scrollOffset: 0
1591+ property real alignmentAdjustment: 0
1592+ property real combinedOffset: 0
1593+
1594+ // when the scroll offset changes, we need to reclaculate the relative lateral position
1595+ onScrollOffsetChanged: root.lateralPositionChanged()
1596+
1597+ onInitialItemChanged: {
1598+ originalDistanceFromRight = initialItem ? (row.width - initialItem.x - initialItem.width/2) : -1;
1599+ }
1600+
1601+ Behavior on alignmentAdjustment {
1602+ NumberAnimation { duration: UbuntuAnimation.BriskDuration; easing: UbuntuAnimation.StandardEasing}
1603+ }
1604+
1605+ function alignIndicators() {
1606+ flickable.resetContentXComponents();
1607+
1608+ if (expanded && !flickable.moving) {
1609+ // gap between left and row?
1610+ if (row.width > flickable.width && flickable.contentX < 0) {
1611+ d.alignmentAdjustment += flickable.contentX;
1612+ // current item overlap on left
1613+ } else if (row.currentItem.x < flickable.contentX) {
1614+ d.alignmentAdjustment -= (row.currentItem.x - flickable.contentX);
1615+ // current item overlap on right
1616+ } else if (row.currentItem.x + row.currentItem.width > flickable.contentX + flickable.width) {
1617+ d.alignmentAdjustment -= ((row.currentItem.x + row.currentItem.width) - (flickable.contentX + flickable.width));
1618+ }
1619+ }
1620+ }
1621+ }
1622+
1623+ Rectangle {
1624+ id: grayLine
1625+ height: units.dp(2)
1626+ width: parent.width
1627+ anchors.bottom: parent.bottom
1628+
1629+ color: "#4c4c4c"
1630+ opacity: expanded ? 1.0 : 0.0
1631+ Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.SnapDuration } }
1632+ }
1633+
1634+ Item {
1635+ id: rowContainer
1636+ anchors.fill: parent
1637+ clip: expanded || row.width > rowContainer.width
1638+
1639+ Flickable {
1640+ id: flickable
1641+ objectName: "flickable"
1642+
1643+ anchors.fill: parent
1644+ contentWidth: row.width
1645+ interactive: false
1646+ // align right + offset from row selection + scrolling
1647+ contentX: row.width - flickable.width - d.combinedOffset
1648+
1649+ // contentX can change by user interaction as well as user offset changes
1650+ // This function re-aligns the offsets so that the offsets match the contentX
1651+ function resetContentXComponents() {
1652+ d.scrollOffset += (flickable.contentX - (row.width - flickable.width - d.combinedOffset));
1653+ }
1654+
1655+ rebound: Transition {
1656+ NumberAnimation {
1657+ properties: "x"
1658+ duration: 600
1659+ easing.type: Easing.OutCubic
1660+ }
1661+ }
1662+
1663+ IndicatorItemRow {
1664+ id: row
1665+ objectName: "indicatorItemRow"
1666+ anchors {
1667+ top: parent.top
1668+ bottom: parent.bottom
1669+ }
1670+
1671+ lateralPosition: {
1672+ if (root.lateralPosition == -1) return -1;
1673+
1674+ var mapped = root.mapToItem(row, root.lateralPosition, 0);
1675+ return Math.min(Math.max(mapped.x, 0), row.width);
1676+ }
1677+
1678+ onCurrentItemChanged: {
1679+ if (!currentItem) d.initialItem = undefined;
1680+ else if (!d.initialItem) d.initialItem = currentItem;
1681+ }
1682+
1683+ MouseArea {
1684+ anchors.fill: parent
1685+ enabled: root.expanded
1686+ onClicked: {
1687+ row.selectItemAt(mouse.x);
1688+ d.alignIndicators();
1689+ }
1690+ }
1691+ }
1692+
1693+ }
1694+ }
1695+
1696+ Timer {
1697+ id: alignmentTimer
1698+ interval: UbuntuAnimation.FastDuration // enough for row animation.
1699+ repeat: false
1700+
1701+ onTriggered: d.alignIndicators();
1702+ }
1703+
1704+ states: [
1705+ State {
1706+ name: "minimized"
1707+ when: !expanded
1708+ PropertyChanges {
1709+ target: d
1710+ rowOffset: 0
1711+ scrollOffset: 0
1712+ alignmentAdjustment: 0
1713+ combinedOffset: 0
1714+ restoreEntryValues: false
1715+ }
1716+ },
1717+ State {
1718+ name: "expanded"
1719+ when: expanded && !interactive
1720+
1721+ PropertyChanges {
1722+ target: d
1723+ combinedOffset: rowOffset + alignmentAdjustment - scrollOffset
1724+ }
1725+ PropertyChanges {
1726+ target: d
1727+ rowOffset: {
1728+ if (!initialItem) return 0;
1729+ if (distanceFromRight - initialItem.width <= 0) return 0;
1730+
1731+ var rowOffset = distanceFromRight - originalDistanceFromRight;
1732+ return rowOffset;
1733+ }
1734+ restoreEntryValues: false
1735+ }
1736+ }
1737+ , State {
1738+ name: "interactive"
1739+ when: expanded && interactive
1740+
1741+ StateChangeScript {
1742+ script: {
1743+ // don't use row offset anymore.
1744+ d.scrollOffset -= d.rowOffset;
1745+ d.rowOffset = 0;
1746+ d.initialItem = undefined;
1747+ alignmentTimer.start();
1748+ }
1749+ }
1750+ PropertyChanges {
1751+ target: d
1752+ combinedOffset: rowOffset + alignmentAdjustment - scrollOffset
1753+ restoreEntryValues: false
1754+ }
1755+ }
1756+ ]
1757+
1758+ transitions: [
1759+ Transition {
1760+ from: "expanded"
1761+ to: "minimized"
1762+ PropertyAction {
1763+ target: d
1764+ properties: "rowOffset, scrollOffset, alignmentAdjustment"
1765+ value: 0
1766+ }
1767+ PropertyAnimation {
1768+ target: d
1769+ properties: "combinedOffset"
1770+ duration: UbuntuAnimation.SnapDuration
1771+ easing: UbuntuAnimation.StandardEasing
1772+ }
1773+ }
1774+ ]
1775+}
1776
1777=== added file 'qml/Panel/IndicatorsMenu.qml'
1778--- qml/Panel/IndicatorsMenu.qml 1970-01-01 00:00:00 +0000
1779+++ qml/Panel/IndicatorsMenu.qml 2014-10-15 16:33:46 +0000
1780@@ -0,0 +1,285 @@
1781+/*
1782+ * Copyright (C) 2014 Canonical, Ltd.
1783+ *
1784+ * This program is free software; you can redistribute it and/or modify
1785+ * it under the terms of the GNU General Public License as published by
1786+ * the Free Software Foundation; version 3.
1787+ *
1788+ * This program is distributed in the hope that it will be useful,
1789+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1790+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1791+ * GNU General Public License for more details.
1792+ *
1793+ * You should have received a copy of the GNU General Public License
1794+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1795+ */
1796+
1797+import QtQuick 2.2
1798+import Ubuntu.Components 1.1
1799+import Ubuntu.Gestures 0.1
1800+import "../Components"
1801+
1802+Showable {
1803+ id: root
1804+ property alias indicatorsModel: bar.indicatorsModel
1805+ property alias showDragHandle: __showDragHandle
1806+ property alias hideDragHandle: __hideDragHandle
1807+ property alias overFlowWidth: bar.overFlowWidth
1808+ property alias verticalVelocityThreshold: yVelocityCalculator.velocityThreshold
1809+ property int minimizedPanelHeight: units.gu(3)
1810+ property int expandedPanelHeight: units.gu(7)
1811+ property real openedHeight: units.gu(71)
1812+ readonly property real unitProgress: Math.max(0, (height - minimizedPanelHeight) / (openedHeight - minimizedPanelHeight))
1813+ readonly property bool fullyOpened: unitProgress >= 1
1814+ readonly property bool partiallyOpened: unitProgress > 0 && unitProgress < 1.0
1815+ readonly property bool fullyClosed: unitProgress == 0
1816+ property bool enableHint: true
1817+ property bool contentEnabled: true
1818+ property color panelColor: "black"
1819+
1820+ signal showTapped(point position)
1821+
1822+ // TODO: Perhaps we need a animation standard for showing/hiding? Each showable seems to
1823+ // use its own values. Need to ask design about this.
1824+ showAnimation: StandardAnimation {
1825+ property: "height"
1826+ to: openedHeight
1827+ duration: UbuntuAnimation.BriskDuration
1828+ easing.type: Easing.OutCubic
1829+ }
1830+
1831+ hideAnimation: StandardAnimation {
1832+ property: "height"
1833+ to: minimizedPanelHeight
1834+ duration: UbuntuAnimation.BriskDuration
1835+ easing.type: Easing.OutCubic
1836+ }
1837+
1838+ height: minimizedPanelHeight
1839+ onHeightChanged: {
1840+ var revealProgress = root.height - minimizedPanelHeight;
1841+
1842+ if (!showAnimation.running && !hideAnimation.running) {
1843+ if (revealProgress <= 0) {
1844+ root.state = "initial";
1845+ } else {
1846+ root.state = "reveal";
1847+ }
1848+ }
1849+ }
1850+ clip: root.partiallyOpened
1851+
1852+ // eater
1853+ MouseArea {
1854+ anchors.fill: parent
1855+ }
1856+
1857+ MenuContent {
1858+ id: content
1859+ objectName: "menuContent"
1860+
1861+ anchors {
1862+ left: parent.left
1863+ right: parent.right
1864+ top: bar.bottom
1865+ }
1866+ height: openedHeight - bar.height - handle.height
1867+ indicatorsModel: root.indicatorsModel
1868+ visible: root.unitProgress > 0
1869+ enabled: contentEnabled
1870+ currentMenuIndex: bar.currentItemIndex
1871+ }
1872+
1873+ Handle {
1874+ id: handle
1875+ anchors {
1876+ left: parent.left
1877+ right: parent.right
1878+ bottom: parent.bottom
1879+ }
1880+ height: units.gu(2)
1881+ active: d.activeDragHandle ? true : false
1882+
1883+ //small shadow gradient at bottom of menu
1884+ Rectangle {
1885+ anchors {
1886+ left: parent.left
1887+ right: parent.right
1888+ bottom: parent.top
1889+ }
1890+ height: units.gu(0.5)
1891+ gradient: Gradient {
1892+ GradientStop { position: 0.0; color: "transparent" }
1893+ GradientStop { position: 1.0; color: "black" }
1894+ }
1895+ opacity: 0.3
1896+ }
1897+ }
1898+
1899+ Rectangle {
1900+ anchors.fill: bar
1901+ color: panelColor
1902+ }
1903+
1904+ IndicatorsBar {
1905+ id: bar
1906+ objectName: "indicatorsBar"
1907+
1908+ anchors {
1909+ left: parent.left
1910+ right: parent.right
1911+ }
1912+ expanded: false
1913+ enableLateralChanges: false
1914+ lateralPosition: -1
1915+ unitProgress: root.unitProgress
1916+
1917+ height: expanded ? expandedPanelHeight : minimizedPanelHeight
1918+ Behavior on height { NumberAnimation { duration: UbuntuAnimation.SnapDuration; easing: UbuntuAnimation.StandardEasing } }
1919+ }
1920+
1921+ ScrollCalculator {
1922+ id: leftScroller
1923+ width: units.gu(5)
1924+ anchors.left: bar.left
1925+ height: bar.height
1926+
1927+ forceScrollingPercentage: 0.33
1928+ stopScrollThreshold: units.gu(0.75)
1929+ direction: Qt.RightToLeft
1930+ lateralPosition: -1
1931+
1932+ onScroll: bar.addScrollOffset(-scrollAmount);
1933+ }
1934+
1935+ ScrollCalculator {
1936+ id: rightScroller
1937+ width: units.gu(5)
1938+ anchors.right: bar.right
1939+ height: bar.height
1940+
1941+ forceScrollingPercentage: 0.33
1942+ stopScrollThreshold: units.gu(0.75)
1943+ direction: Qt.LeftToRight
1944+ lateralPosition: -1
1945+
1946+ onScroll: bar.addScrollOffset(scrollAmount);
1947+ }
1948+
1949+ DragHandle {
1950+ id: __showDragHandle
1951+ anchors.bottom: parent.bottom
1952+ anchors.left: parent.left
1953+ anchors.right: parent.right
1954+ height: minimizedPanelHeight
1955+ direction: Direction.Downwards
1956+ enabled: !root.shown && root.available
1957+ autoCompleteDragThreshold: maxTotalDragDistance / 2
1958+ stretch: true
1959+ distanceThreshold: minimizedPanelHeight
1960+ onTapped: showTapped(Qt.point(touchSceneX, touchSceneY));
1961+
1962+ // using hint regulates minimum to hint displacement, but in fullscreen mode, we need to do it manually.
1963+ overrideStartValue: enableHint ? minimizedPanelHeight : expandedPanelHeight + handle.height
1964+ maxTotalDragDistance: openedHeight - (enableHint ? minimizedPanelHeight : expandedPanelHeight + handle.height)
1965+ hintDisplacement: enableHint ? expandedPanelHeight - minimizedPanelHeight + handle.height : 0
1966+ }
1967+
1968+ DragHandle {
1969+ id: __hideDragHandle
1970+ anchors.fill: handle
1971+ direction: Direction.Upwards
1972+ enabled: root.shown && root.available
1973+ hintDisplacement: units.gu(3)
1974+ autoCompleteDragThreshold: maxTotalDragDistance / 6
1975+ stretch: true
1976+ maxTotalDragDistance: openedHeight - expandedPanelHeight - handle.height
1977+ distanceThreshold: 0
1978+ }
1979+
1980+ PanelVelocityCalculator {
1981+ id: yVelocityCalculator
1982+ velocityThreshold: 0.5
1983+ trackedValue: d.activeDragHandle ? d.activeDragHandle.touchSceneY : 0
1984+ }
1985+
1986+ Connections {
1987+ target: showAnimation
1988+ onRunningChanged: {
1989+ if (showAnimation.running) {
1990+ root.state = "commit";
1991+ }
1992+ }
1993+ }
1994+
1995+ Connections {
1996+ target: hideAnimation
1997+ onRunningChanged: {
1998+ if (hideAnimation.running) {
1999+ root.state = "initial";
2000+ }
2001+ }
2002+ }
2003+
2004+ QtObject {
2005+ id: d
2006+ property var activeDragHandle: showDragHandle.dragging ? showDragHandle : hideDragHandle.dragging ? hideDragHandle : null
2007+
2008+ property real rowMappedLateralPosition: {
2009+ if (!d.activeDragHandle) return -1;
2010+ return d.activeDragHandle.mapToItem(bar, d.activeDragHandle.touchX, 0).x;
2011+ }
2012+ }
2013+
2014+ states: [
2015+ State {
2016+ name: "initial"
2017+ },
2018+ State {
2019+ name: "reveal"
2020+ StateChangeScript {
2021+ script: {
2022+ yVelocityCalculator.reset();
2023+ // initial item selection
2024+ bar.selectItemAt(d.activeDragHandle ? d.activeDragHandle.touchX : -1);
2025+ }
2026+ }
2027+ PropertyChanges {
2028+ target: bar
2029+ expanded: true
2030+ // changes to lateral touch position effect which indicator is selected
2031+ lateralPosition: d.rowMappedLateralPosition
2032+ // vertical velocity determines if changes in lateral position has an effect
2033+ enableLateralChanges: d.activeDragHandle &&
2034+ !yVelocityCalculator.velocityAboveThreshold
2035+ }
2036+ // left scroll bar handling
2037+ PropertyChanges {
2038+ target: leftScroller
2039+ lateralPosition: {
2040+ if (!d.activeDragHandle) return -1;
2041+ var mapped = d.activeDragHandle.mapToItem(leftScroller, d.activeDragHandle.touchX, 0);
2042+ return mapped.x;
2043+ }
2044+ }
2045+ // right scroll bar handling
2046+ PropertyChanges {
2047+ target: rightScroller
2048+ lateralPosition: {
2049+ if (!d.activeDragHandle) return -1;
2050+ var mapped = d.activeDragHandle.mapToItem(rightScroller, d.activeDragHandle.touchX, 0);
2051+ return mapped.x;
2052+ }
2053+ }
2054+ },
2055+ State {
2056+ name: "commit"
2057+ PropertyChanges {
2058+ target: bar
2059+ expanded: true
2060+ interactive: true
2061+ }
2062+ }
2063+ ]
2064+ state: "initial"
2065+}
2066
2067=== modified file 'qml/Panel/MenuContent.qml'
2068--- qml/Panel/MenuContent.qml 2014-09-29 10:24:58 +0000
2069+++ qml/Panel/MenuContent.qml 2014-10-15 16:33:46 +0000
2070@@ -1,5 +1,5 @@
2071 /*
2072- * Copyright (C) 2013 Canonical, Ltd.
2073+ * Copyright (C) 2013-2014 Canonical, Ltd.
2074 *
2075 * This program is free software; you can redistribute it and/or modify
2076 * it under the terms of the GNU General Public License as published by
2077@@ -14,125 +14,68 @@
2078 * along with this program. If not, see <http://www.gnu.org/licenses/>.
2079 */
2080
2081-import QtQuick 2.0
2082+import QtQuick 2.2
2083 import QtQuick.Layouts 1.1
2084 import Ubuntu.Components 1.1
2085 import Unity.Indicators 0.1 as Indicators
2086 import Utils 0.1
2087 import "../Components"
2088-import "Indicators"
2089
2090 Rectangle {
2091 id: content
2092
2093 property QtObject indicatorsModel: null
2094- readonly property alias currentMenuIndex: listViewHeader.currentIndex
2095+ property int currentMenuIndex: -1
2096 color: "#221e1c" // FIXME not in palette yet
2097- property real headerHeight: listViewHeader.height
2098
2099 width: units.gu(40)
2100 height: units.gu(42)
2101
2102- function setCurrentMenuIndex(index, animate) {
2103- // FIXME - https://bugreports.qt-project.org/browse/QTBUG-41229
2104- listViewHeader.currentIndex = -1;
2105- listViewHeader.currentIndex = index;
2106- }
2107-
2108- ListView {
2109- id: listViewHeader
2110- objectName: "indicatorsHeaderListView"
2111- model: content.indicatorsModel
2112- clip: true
2113-
2114- anchors {
2115- left: parent.left
2116- right: parent.right
2117- }
2118- height: units.gu(8.5)
2119-
2120- highlightFollowsCurrentItem: true
2121- highlightMoveDuration: 0
2122-
2123- orientation: ListView.Horizontal
2124- snapMode: ListView.SnapOneItem
2125- highlightRangeMode: ListView.StrictlyEnforceRange
2126- boundsBehavior: Flickable.StopAtBounds
2127- // Load all the indicator menus (a big number)
2128- cacheBuffer: 1073741823
2129-
2130- delegate: Header {
2131- width: ListView.view.width
2132- height: implicitHeight
2133-
2134- title: indicatorDelegate.title !== "" ? indicatorDelegate.title : identifier
2135-
2136- IndicatorDelegate {
2137- id: indicatorDelegate
2138- Component.onCompleted: {
2139- for(var pName in indicatorProperties) {
2140- if (indicatorDelegate.hasOwnProperty(pName)) {
2141- indicatorDelegate[pName] = indicatorProperties[pName];
2142- }
2143- }
2144- }
2145- }
2146- }
2147+ onCurrentMenuIndexChanged: {
2148+ listViewContent.currentIndex = currentMenuIndex;
2149 }
2150
2151 ListView {
2152 id: listViewContent
2153 objectName: "indicatorsContentListView"
2154- anchors {
2155- left: parent.left
2156- right: parent.right
2157- top: listViewHeader.bottom
2158- bottom: parent.bottom
2159- }
2160+ anchors.fill: parent
2161 model: content.indicatorsModel
2162 clip: true
2163
2164- currentIndex: listViewHeader.currentIndex
2165+ highlightFollowsCurrentItem: true
2166 interactive: false
2167 highlightMoveDuration: 0
2168 orientation: ListView.Horizontal
2169 // Load all the indicator menus (a big number)
2170 cacheBuffer: 1073741823
2171
2172+ // for additions/removals.
2173+ onCountChanged: {
2174+ listViewContent.currentIndex = content.currentMenuIndex;
2175+ }
2176+
2177 delegate: Loader {
2178 id: loader
2179+
2180 width: ListView.view.width
2181 height: ListView.view.height
2182 objectName: identifier
2183-
2184- source: pageSource
2185 asynchronous: true
2186
2187+ sourceComponent: IndicatorPage {
2188+ objectName: identifier + "-page"
2189+
2190+ identifier: model.identifier
2191+ busName: indicatorProperties.busName
2192+ actionsObjectPath: indicatorProperties.actionsObjectPath
2193+ menuObjectPath: indicatorProperties.menuObjectPath
2194+ }
2195+
2196 onVisibleChanged: {
2197 // Reset the indicator states
2198- if (!visible && item && item["reset"]) {
2199- item.reset()
2200- }
2201- }
2202-
2203- onLoaded: {
2204- for(var pName in indicatorProperties) {
2205- if (item.hasOwnProperty(pName)) {
2206- item[pName] = indicatorProperties[pName]
2207- }
2208- }
2209- }
2210-
2211- Binding {
2212- target: loader.item
2213- property: "identifier"
2214- value: identifier
2215- }
2216-
2217- Binding {
2218- target: loader.item
2219- property: "objectName"
2220- value: identifier + "-page"
2221+ if (!visible && status == Loader.Ready) {
2222+ item.reset();
2223+ }
2224 }
2225 }
2226 }
2227
2228=== removed file 'qml/Panel/Panel.qml'
2229--- qml/Panel/Panel.qml 2014-07-10 13:36:41 +0000
2230+++ qml/Panel/Panel.qml 1970-01-01 00:00:00 +0000
2231@@ -1,191 +0,0 @@
2232-/*
2233- * Copyright (C) 2013 Canonical, Ltd.
2234- *
2235- * This program is free software; you can redistribute it and/or modify
2236- * it under the terms of the GNU General Public License as published by
2237- * the Free Software Foundation; version 3.
2238- *
2239- * This program is distributed in the hope that it will be useful,
2240- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2241- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2242- * GNU General Public License for more details.
2243- *
2244- * You should have received a copy of the GNU General Public License
2245- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2246- */
2247-
2248-import QtQuick 2.0
2249-import Ubuntu.Components 0.1
2250-import Unity.Application 0.1
2251-import "../Components"
2252-import "../Components/ListItems"
2253-
2254-Item {
2255- id: root
2256- readonly property real panelHeight: indicatorArea.y + d.indicatorHeight
2257- property alias indicators: __indicators
2258- property alias callHint: __callHint
2259- property bool fullscreenMode: false
2260-
2261- Rectangle {
2262- id: darkenedArea
2263- property real darkenedOpacity: 0.6
2264- anchors {
2265- top: parent.top
2266- topMargin: panelHeight
2267- left: parent.left
2268- right: parent.right
2269- bottom: parent.bottom
2270- }
2271- color: "black"
2272- opacity: indicators.unitProgress * darkenedOpacity
2273-
2274- MouseArea {
2275- anchors.fill: parent
2276- enabled: indicators.shown
2277- onClicked: if (indicators.fullyOpened) indicators.hide();
2278- }
2279- }
2280-
2281- Item {
2282- id: indicatorArea
2283- objectName: "indicatorArea"
2284-
2285- anchors.fill: parent
2286-
2287- Behavior on anchors.topMargin { StandardAnimation {} }
2288-
2289- BorderImage {
2290- id: dropShadow
2291- anchors {
2292- fill: indicators
2293- leftMargin: -units.gu(1)
2294- bottomMargin: -units.gu(1)
2295- }
2296- visible: indicators.height > indicators.panelHeight
2297- source: "graphics/rectangular_dropshadow.sci"
2298- }
2299-
2300- VerticalThinDivider {
2301- id: indicatorDividor
2302- anchors {
2303- top: indicators.top
2304- bottom: indicators.bottom
2305- right: indicators.left
2306-
2307- topMargin: indicatorArea.anchors.topMargin + indicators.panelHeight
2308- }
2309-
2310- width: units.dp(2)
2311- source: "graphics/VerticalDivider.png"
2312- }
2313-
2314- Rectangle {
2315- id: indicatorAreaBackground
2316- color: callHint.visible ? "green" : "black"
2317- anchors {
2318- top: parent.top
2319- left: parent.left
2320- right: parent.right
2321- }
2322- height: indicators.panelHeight
2323-
2324- Behavior on color { ColorAnimation { duration: UbuntuAnimation.FastDuration } }
2325- }
2326-
2327- PanelSeparatorLine {
2328- id: nonIndicatorAreaSeparatorLine
2329- anchors {
2330- top: indicatorAreaBackground.bottom
2331- left: parent.left
2332- right: indicators.left
2333- }
2334- saturation: 1 - indicators.unitProgress
2335- }
2336-
2337- MouseArea {
2338- anchors {
2339- top: parent.top
2340- left: parent.left
2341- right: indicators.left
2342- }
2343- height: indicators.panelHeight
2344- enabled: callHint.visible
2345- onClicked: callHint.showLiveCall()
2346- }
2347-
2348- Indicators {
2349- id: __indicators
2350- objectName: "indicators"
2351-
2352- anchors {
2353- top: parent.top
2354- right: parent.right
2355- }
2356-
2357- width: root.width
2358- shown: false
2359- panelHeight: units.gu(3)
2360- openedHeight: root.height
2361- overFlowWidth: {
2362- if (callHint.visible) {
2363- return Math.max(root.width - (callHint.width + units.gu(2)), 0)
2364- }
2365- return root.width
2366- }
2367-
2368- enableHint: !callHint.active && !fullscreenMode
2369- showHintBottomMargin: fullscreenMode ? -panelHeight : 0
2370-
2371- onShowTapped: {
2372- if (callHint.active) {
2373- callHint.showLiveCall();
2374- }
2375- }
2376- }
2377-
2378- ActiveCallHint {
2379- id: __callHint
2380- anchors {
2381- top: parent.top
2382- left: parent.left
2383- }
2384- height: indicators.panelHeight
2385- visible: active && indicators.state == "initial"
2386- }
2387-
2388- PanelSeparatorLine {
2389- id: indicatorsSeparatorLine
2390- visible: true
2391- anchors {
2392- top: indicators.bottom
2393- left: indicatorDividor.left
2394- right: indicators.right
2395- }
2396- }
2397- }
2398-
2399- QtObject {
2400- id: d
2401- readonly property real indicatorHeight: indicators.panelHeight + indicatorsSeparatorLine.height
2402- }
2403-
2404- states: [
2405- State {
2406- name: "onscreen" //fully opaque and visible at top edge of screen
2407- when: !fullscreenMode
2408- PropertyChanges {
2409- target: indicatorArea;
2410- anchors.topMargin: 0
2411- }
2412- },
2413- State {
2414- name: "offscreen" //pushed off screen
2415- when: fullscreenMode
2416- PropertyChanges {
2417- target: indicatorArea;
2418- anchors.topMargin: indicators.state === "initial" ? -d.indicatorHeight : 0
2419- }
2420- }
2421- ]
2422-}
2423
2424=== added file 'qml/Panel/PanelVelocityCalculator.qml'
2425--- qml/Panel/PanelVelocityCalculator.qml 1970-01-01 00:00:00 +0000
2426+++ qml/Panel/PanelVelocityCalculator.qml 2014-10-15 16:33:46 +0000
2427@@ -0,0 +1,54 @@
2428+/*
2429+ * Copyright (C) 2014 Canonical, Ltd.
2430+ *
2431+ * This program is free software; you can redistribute it and/or modify
2432+ * it under the terms of the GNU General Public License as published by
2433+ * the Free Software Foundation; version 3.
2434+ *
2435+ * This program is distributed in the hope that it will be useful,
2436+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2437+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2438+ * GNU General Public License for more details.
2439+ *
2440+ * You should have received a copy of the GNU General Public License
2441+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2442+ */
2443+
2444+import QtQuick 2.2
2445+import Ubuntu.Gestures 0.1
2446+
2447+Item {
2448+ id: root
2449+ property real trackedValue: 0
2450+ property bool velocityAboveThreshold: false
2451+ property real velocityThreshold: 0.4
2452+
2453+ function reset() {
2454+ velocityTimer.stop();
2455+ velocityAboveThreshold = false;
2456+ calc.reset();
2457+ }
2458+
2459+ function update() {
2460+ calc.trackedPosition = trackedValue;
2461+ velocityAboveThreshold = Math.abs(calc.calculate()) > velocityThreshold;
2462+
2463+ if (velocityAboveThreshold) { // only start timer if we're above the threshold.
2464+ velocityTimer.start();
2465+ } else {
2466+ velocityTimer.stop();
2467+ }
2468+ }
2469+
2470+ onTrackedValueChanged: update();
2471+
2472+ AxisVelocityCalculator {
2473+ id: calc
2474+ }
2475+
2476+ Timer {
2477+ id: velocityTimer
2478+ interval: 50
2479+ onTriggered: update();
2480+ }
2481+}
2482
2483=== modified file 'qml/Shell.qml'
2484--- qml/Shell.qml 2014-10-08 20:36:48 +0000
2485+++ qml/Shell.qml 2014-10-15 16:33:46 +0000
2486@@ -36,6 +36,7 @@
2487 import "Components"
2488 import "Notifications"
2489 import "Stages"
2490+import "Panel/Indicators"
2491 import Unity.Notifications 1.0 as NotificationBackend
2492 import Unity.Session 0.1
2493 import Unity.DashCommunicator 0.1
2494@@ -235,7 +236,7 @@
2495 target: applicationsDisplayLoader.item
2496 property: "maximizedAppTopMargin"
2497 // Not just using panel.panelHeight as that changes depending on the focused app.
2498- value: panel.indicators.panelHeight
2499+ value: panel.indicators.minimizedPanelHeight + units.dp(2) // dp(2) for orange line
2500 }
2501 Binding {
2502 target: applicationsDisplayLoader.item
2503@@ -613,7 +614,17 @@
2504 available: edgeDemo.panelEnabled && (!shell.locked || AccountsService.enableIndicatorsWhileLocked) && !greeter.hasLockedApp
2505 contentEnabled: edgeDemo.panelContentEnabled
2506 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
2507- panelHeight: units.gu(3)
2508+
2509+ minimizedPanelHeight: units.gu(3)
2510+ expandedPanelHeight: units.gu(7)
2511+
2512+ indicatorsModel: visibleIndicators.model
2513+ }
2514+
2515+ VisibleIndicators {
2516+ id: visibleIndicators
2517+ // TODO: This should be sourced by device type (eg "desktop", "tablet", "phone"...)
2518+ Component.onCompleted: initialise(indicatorProfile)
2519 }
2520
2521 property bool topmostApplicationIsFullscreen:
2522@@ -676,9 +687,9 @@
2523 model: NotificationBackend.Model
2524 margin: units.gu(1)
2525
2526- y: panel.panelHeight
2527+ y: topmostIsFullscreen ? 0 : panel.panelHeight
2528 width: parent.width
2529- height: parent.height - panel.panelHeight
2530+ height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight)
2531
2532 states: [
2533 State {
2534
2535=== modified file 'tests/autopilot/unity8/indicators/tests/test_indicators.py'
2536--- tests/autopilot/unity8/indicators/tests/test_indicators.py 2014-10-09 13:57:46 +0000
2537+++ tests/autopilot/unity8/indicators/tests/test_indicators.py 2014-10-15 16:33:46 +0000
2538@@ -61,7 +61,7 @@
2539 self.skipTest('Nexus 10 does not have bluetooth at the moment.')
2540
2541 def test_indicator_exists(self):
2542- self.main_window._get_indicator_widget(
2543+ self.main_window._get_indicator_panel_item(
2544 self.indicator_name
2545 )
2546
2547
2548=== modified file 'tests/autopilot/unity8/shell/emulators/main_window.py'
2549--- tests/autopilot/unity8/shell/emulators/main_window.py 2014-08-12 17:30:05 +0000
2550+++ tests/autopilot/unity8/shell/emulators/main_window.py 2014-10-15 16:33:46 +0000
2551@@ -75,15 +75,15 @@
2552 def get_pinentryField(self):
2553 return self.select_single(objectName="pinentryField")
2554
2555- def _get_indicator_widget(self, indicator_name):
2556+ def _get_indicator_panel_item(self, indicator_name):
2557 return self.select_single(
2558- 'DefaultIndicatorWidget',
2559- objectName=indicator_name+'-widget'
2560+ 'IndicatorItem',
2561+ objectName=indicator_name+'-panelItem'
2562 )
2563
2564 def _get_indicator_page(self, indicator_name):
2565 return self.select_single(
2566- 'DefaultIndicatorPage',
2567+ 'IndicatorPage',
2568 objectName=indicator_name+'-page'
2569 )
2570
2571@@ -93,12 +93,12 @@
2572
2573 :returns: The indicator page.
2574 """
2575- widget = self._get_indicator_widget(indicator_name)
2576+ widget = self._get_indicator_panel_item(indicator_name)
2577 start_x, start_y = input.get_center_point(widget)
2578 end_x = start_x
2579 end_y = self.height
2580 self.pointing_device.drag(start_x, start_y, end_x, end_y)
2581- self.wait_select_single('Indicators', fullyOpened=True)
2582+ self.wait_select_single('IndicatorsMenu', fullyOpened=True)
2583 return self._get_indicator_page(indicator_name)
2584
2585 @autopilot_logging.log_action(logger.info)
2586
2587=== modified file 'tests/mocks/Unity/Indicators/Indicators.qmltypes'
2588--- tests/mocks/Unity/Indicators/Indicators.qmltypes 2014-10-15 16:33:45 +0000
2589+++ tests/mocks/Unity/Indicators/Indicators.qmltypes 2014-10-15 16:33:46 +0000
2590@@ -105,10 +105,8 @@
2591 values: {
2592 "Identifier": 0,
2593 "Position": 1,
2594- "WidgetSource": 2,
2595- "PageSource": 3,
2596- "IndicatorProperties": 4,
2597- "IsVisible": 5
2598+ "IndicatorProperties": 2,
2599+ "IsVisible": 3
2600 }
2601 }
2602 }
2603
2604=== modified file 'tests/mocks/Unity/Indicators/IndicatorsModel.qml'
2605--- tests/mocks/Unity/Indicators/IndicatorsModel.qml 2014-10-15 16:33:45 +0000
2606+++ tests/mocks/Unity/Indicators/IndicatorsModel.qml 2014-10-15 16:33:46 +0000
2607@@ -38,14 +38,14 @@
2608 Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake3",
2609 "/com/canonical/indicators/fake3",
2610 "/com/canonical/indicators/fake3",
2611- getUnityMenuModelData("fake-indicator-sound",
2612+ getUnityMenuModelData("fake-indicator-messages",
2613 "Messages (F)",
2614 "",
2615 [ "image://theme/messages-new" ]));
2616 Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake4",
2617 "/com/canonical/indicators/fake4",
2618 "/com/canonical/indicators/fake4",
2619- getUnityMenuModelData("fake-indicator-power",
2620+ getUnityMenuModelData("fake-indicator-sound",
2621 "Sound (F)",
2622 "",
2623 [ "image://theme/audio-volume-high" ]));
2624@@ -56,6 +56,13 @@
2625 "Battery (F)",
2626 "",
2627 [ "image://theme/battery-020" ]));
2628+ Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake6",
2629+ "/com/canonical/indicators/fake6",
2630+ "/com/canonical/indicators/fake6",
2631+ getUnityMenuModelData("fake-indicator-datetime",
2632+ "Upcoming Events (F)",
2633+ "12:04",
2634+ []));
2635 }
2636
2637 function getUnityMenuModelData(identifier, title, label, icons) {
2638@@ -105,9 +112,7 @@
2639
2640 property var originalModelData: [
2641 {
2642- "identifier": "indicator-fake1",
2643- "widgetSource": "Indicators/DefaultIndicatorWidget.qml",
2644- "pageSource": "Indicators/DefaultIndicatorPage.qml",
2645+ "identifier": "fake-indicator-bluetooth",
2646 "indicatorProperties": {
2647 "enabled": true,
2648 "busName": "com.canonical.indicators.fake1",
2649@@ -116,9 +121,7 @@
2650 }
2651 },
2652 {
2653- "identifier": "indicator-fake2",
2654- "widgetSource": "Indicators/DefaultIndicatorWidget.qml",
2655- "pageSource": "Indicators/DefaultIndicatorPage.qml",
2656+ "identifier": "fake-indicator-network",
2657 "indicatorProperties": {
2658 "enabled": true,
2659 "busName": "com.canonical.indicators.fake2",
2660@@ -127,9 +130,7 @@
2661 }
2662 },
2663 {
2664- "identifier": "indicator-fake3",
2665- "widgetSource": "Indicators/DefaultIndicatorWidget.qml",
2666- "pageSource": "Indicators/DefaultIndicatorPage.qml",
2667+ "identifier": "fake-indicator-messages",
2668 "indicatorProperties": {
2669 "enabled": true,
2670 "busName": "com.canonical.indicators.fake3",
2671@@ -138,9 +139,7 @@
2672 }
2673 },
2674 {
2675- "identifier": "indicator-fake4",
2676- "widgetSource": "Indicators/DefaultIndicatorWidget.qml",
2677- "pageSource": "Indicators/DefaultIndicatorPage.qml",
2678+ "identifier": "fake-indicator-sound",
2679 "indicatorProperties": {
2680 "enabled": true,
2681 "busName": "com.canonical.indicators.fake4",
2682@@ -149,15 +148,22 @@
2683 }
2684 },
2685 {
2686- "identifier": "indicator-fake5",
2687- "widgetSource": "Indicators/DefaultIndicatorWidget.qml",
2688- "pageSource": "Indicators/DefaultIndicatorPage.qml",
2689+ "identifier": "fake-indicator-power",
2690 "indicatorProperties": {
2691 "enabled": true,
2692 "busName": "com.canonical.indicators.fake5",
2693 "menuObjectPath": "/com/canonical/indicators/fake5",
2694 "actionsObjectPath": "/com/canonical/indicators/fake5"
2695 }
2696+ },
2697+ {
2698+ "identifier": "fake-indicator-datetime",
2699+ "indicatorProperties": {
2700+ "enabled": true,
2701+ "busName": "com.canonical.indicators.fake6",
2702+ "menuObjectPath": "/com/canonical/indicators/fake6",
2703+ "actionsObjectPath": "/com/canonical/indicators/fake6"
2704+ }
2705 }
2706 ]
2707
2708
2709=== modified file 'tests/mocks/Unity/Indicators/fakeindicatorsmodel.cpp'
2710--- tests/mocks/Unity/Indicators/fakeindicatorsmodel.cpp 2014-10-15 16:33:45 +0000
2711+++ tests/mocks/Unity/Indicators/fakeindicatorsmodel.cpp 2014-10-15 16:33:46 +0000
2712@@ -110,8 +110,6 @@
2713 {
2714 roles[IndicatorsModelRole::Identifier] = "identifier";
2715 roles[IndicatorsModelRole::Position] = "position";
2716- roles[IndicatorsModelRole::WidgetSource] = "widgetSource";
2717- roles[IndicatorsModelRole::PageSource] = "pageSource";
2718 roles[IndicatorsModelRole::IndicatorProperties] = "indicatorProperties";
2719 }
2720 return roles;
2721
2722=== modified file 'tests/qmltests/CMakeLists.txt'
2723--- tests/qmltests/CMakeLists.txt 2014-10-15 16:33:45 +0000
2724+++ tests/qmltests/CMakeLists.txt 2014-10-15 16:33:46 +0000
2725@@ -12,7 +12,6 @@
2726 set(qmltest_DEFAULT_TARGETS qmlunittests)
2727 set(qmltest_DEFAULT_NO_ADD_TEST FALSE)
2728 set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
2729-add_qml_test(Panel IndicatorItem)
2730 add_qml_test(utils/Unity/Test UnityTest)
2731
2732 set(qmltest_DEFAULT_TARGETS qmluitests)
2733@@ -72,13 +71,14 @@
2734 add_qml_test(Notifications Notifications)
2735 add_qml_test(Notifications VisualSnapDecisionsQueue)
2736 add_qml_test(Panel ActiveCallHint)
2737-add_qml_test(Panel IndicatorRow ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
2738-add_qml_test(Panel Indicators ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
2739+add_qml_test(Panel IndicatorItem)
2740+add_qml_test(Panel IndicatorItemRow ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
2741+add_qml_test(Panel IndicatorPage ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
2742+add_qml_test(Panel IndicatorsBar ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
2743+add_qml_test(Panel IndicatorsMenu ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
2744 add_qml_test(Panel MenuContent ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
2745 add_qml_test(Panel Panel ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
2746 add_qml_test(Panel SearchIndicator)
2747-add_qml_test(Panel/Indicators DefaultIndicatorWidget ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
2748-add_qml_test(Panel/Indicators DefaultIndicatorPage ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
2749 # These MenuItemFactory tests need the test/mocks/ to come before plugins/
2750 add_qml_test(Panel/Indicators MenuItemFactory IMPORT_PATHS ${CMAKE_BINARY_DIR}/tests/mocks ${qmltest_DEFAULT_IMPORT_PATHS})
2751 add_qml_test(Panel/Indicators MessageMenuItemFactory IMPORT_PATHS ${CMAKE_BINARY_DIR}/tests/mocks ${qmltest_DEFAULT_IMPORT_PATHS})
2752
2753=== added file 'tests/qmltests/Panel/IndicatorTest.qml'
2754--- tests/qmltests/Panel/IndicatorTest.qml 1970-01-01 00:00:00 +0000
2755+++ tests/qmltests/Panel/IndicatorTest.qml 2014-10-15 16:33:46 +0000
2756@@ -0,0 +1,67 @@
2757+/*
2758+ * Copyright 2014 Canonical Ltd.
2759+ *
2760+ * This program is free software; you can redistribute it and/or modify
2761+ * it under the terms of the GNU General Public License as published by
2762+ * the Free Software Foundation; version 3.
2763+ *
2764+ * This program is distributed in the hope that it will be useful,
2765+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2766+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2767+ * GNU General Public License for more details.
2768+ *
2769+ * You should have received a copy of the GNU General Public License
2770+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2771+ */
2772+
2773+import QtQuick 2.1
2774+import QtQuick.Layouts 1.1
2775+import QtTest 1.0
2776+import "../../../qml/Panel"
2777+import Ubuntu.Components 0.1
2778+import Unity.Test 0.1 as UT
2779+import Unity.Indicators 0.1 as Indicators
2780+
2781+Rectangle {
2782+ id: root
2783+ color: "white"
2784+
2785+ property alias indicatorsModel: __indicatorsModel
2786+ Indicators.IndicatorsModel {
2787+ id: __indicatorsModel
2788+ Component.onCompleted: load()
2789+ }
2790+
2791+ function insertIndicator(index) {
2792+ var i;
2793+ var insertIndex = 0;
2794+ var done = false;
2795+ for (i = index; !done && i >= 1; i--) {
2796+
2797+ var lookFor = indicatorsModel.originalModelData[i-1]["identifier"]
2798+
2799+ var j;
2800+ for (j = indicatorsModel.modelData.length-1; !done && j >= 0; j--) {
2801+ if (indicatorsModel.modelData[j]["identifier"] === lookFor) {
2802+ insertIndex = j+1;
2803+ done = true;
2804+ }
2805+ }
2806+ }
2807+ indicatorsModel.insert(insertIndex, indicatorsModel.originalModelData[index]);
2808+ }
2809+
2810+ function removeIndicator(index) {
2811+ var i;
2812+ for (i = 0; i < indicatorsModel.modelData.length; i++) {
2813+ if (indicatorsModel.modelData[i]["identifier"] === indicatorsModel.originalModelData[index]["identifier"]) {
2814+ indicatorsModel.remove(i);
2815+ break;
2816+ }
2817+ }
2818+ }
2819+
2820+ function resetData() {
2821+ indicatorsModel.load();
2822+ }
2823+}
2824
2825=== removed file 'tests/qmltests/Panel/Indicators/tst_DefaultIndicatorWidget.qml'
2826--- tests/qmltests/Panel/Indicators/tst_DefaultIndicatorWidget.qml 2014-10-15 16:33:45 +0000
2827+++ tests/qmltests/Panel/Indicators/tst_DefaultIndicatorWidget.qml 1970-01-01 00:00:00 +0000
2828@@ -1,52 +0,0 @@
2829-/*
2830- * Copyright 2013 Canonical Ltd.
2831- *
2832- * This program is free software; you can redistribute it and/or modify
2833- * it under the terms of the GNU General Public License as published by
2834- * the Free Software Foundation; version 3.
2835- *
2836- * This program is distributed in the hope that it will be useful,
2837- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2838- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2839- * GNU General Public License for more details.
2840- *
2841- * You should have received a copy of the GNU General Public License
2842- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2843- */
2844-
2845-import QtQuick 2.0
2846-import QtTest 1.0
2847-import Unity.Test 0.1 as UT
2848-import QMenuModel 0.1
2849-import "../../../../qml/Panel/Indicators"
2850-
2851-Item {
2852- id: testView
2853- width: units.gu(40)
2854- height: units.gu(70)
2855-
2856- DefaultIndicatorWidget {
2857- id: widget
2858-
2859- anchors {
2860- left: parent.left
2861- top: parent.top
2862- }
2863-
2864- busName: "test"
2865- actionsObjectPath: "test"
2866- deviceMenuObjectPath: "test"
2867-
2868- rootMenuType: ""
2869-
2870- iconSize: units.gu(3.2)
2871- height: units.gu(3)
2872- }
2873-
2874- UT.UnityTestCase {
2875- name: "DefaultIndicatorWidget"
2876- when: windowShown
2877-
2878- // FIXME: add tests
2879- }
2880-}
2881
2882=== modified file 'tests/qmltests/Panel/tst_ActiveCallHint.qml'
2883--- tests/qmltests/Panel/tst_ActiveCallHint.qml 2014-09-11 14:53:35 +0000
2884+++ tests/qmltests/Panel/tst_ActiveCallHint.qml 2014-10-15 16:33:46 +0000
2885@@ -19,7 +19,6 @@
2886 import Unity.Test 0.1 as UT
2887 import Ubuntu.Telephony 0.1 as Telephony
2888 import Unity.Application 0.1
2889-import ".."
2890 import "../../../qml/Panel"
2891
2892 Item {
2893
2894=== added file 'tests/qmltests/Panel/tst_IndicatorItem.qml'
2895--- tests/qmltests/Panel/tst_IndicatorItem.qml 1970-01-01 00:00:00 +0000
2896+++ tests/qmltests/Panel/tst_IndicatorItem.qml 2014-10-15 16:33:46 +0000
2897@@ -0,0 +1,205 @@
2898+/*
2899+ * Copyright 2013-2014 Canonical Ltd.
2900+ *
2901+ * This program is free software; you can redistribute it and/or modify
2902+ * it under the terms of the GNU General Public License as published by
2903+ * the Free Software Foundation; version 3.
2904+ *
2905+ * This program is distributed in the hope that it will be useful,
2906+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2907+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2908+ * GNU General Public License for more details.
2909+ *
2910+ * You should have received a copy of the GNU General Public License
2911+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2912+ */
2913+
2914+import QtQuick 2.1
2915+import QtQuick.Layouts 1.1
2916+import QtTest 1.0
2917+import Ubuntu.Components 0.1
2918+import Unity.Test 0.1 as UT
2919+import "../../../qml/Panel"
2920+
2921+Rectangle {
2922+ width: units.gu(80)
2923+ height: units.gu(30)
2924+ color: "white"
2925+
2926+ RowLayout {
2927+ anchors.fill: parent
2928+ anchors.margins: units.gu(1)
2929+
2930+ Rectangle {
2931+ id: itemArea
2932+ color: "blue"
2933+ Layout.fillWidth: true
2934+ Layout.fillHeight: true
2935+
2936+ Rectangle {
2937+ color: "black"
2938+ anchors.fill: indicatorItem
2939+ }
2940+
2941+ IndicatorItem {
2942+ id: indicatorItem
2943+ height: expanded ? units.gu(7) : units.gu(3)
2944+ anchors.centerIn: parent
2945+ identifier: "indicator-test"
2946+
2947+ rootActionState {
2948+ title: titleLabel.text
2949+ leftLabel : leftLabel.text
2950+ rightLabel : rightLabel.text
2951+ icons : {
2952+ var icons = [];
2953+ var i = 0;
2954+ if (iconEnabled.checked) {
2955+ for (i = 0; i < String(iconCount.text); i++) {
2956+ icons.push("image://theme/audio-volume-high");
2957+ }
2958+ }
2959+ return icons;
2960+ }
2961+ }
2962+
2963+ Behavior on height {
2964+ NumberAnimation {
2965+ id: heightAnimation
2966+ duration: UbuntuAnimation.SnapDuration; easing: UbuntuAnimation.StandardEasing
2967+ }
2968+ }
2969+ }
2970+ }
2971+
2972+ ColumnLayout {
2973+ Layout.alignment: Qt.AlignTop
2974+ Layout.fillWidth: false
2975+
2976+ Button {
2977+ id: expandButton
2978+ Layout.fillWidth: true
2979+ text: indicatorItem.expanded ? "Collapse" : "Expand"
2980+ onClicked: indicatorItem.expanded = !indicatorItem.expanded
2981+ }
2982+
2983+ Button {
2984+ id: selectButton
2985+ Layout.fillWidth: true
2986+ text: indicatorItem.selected ? "Unselect" : "Select"
2987+ onClicked: indicatorItem.selected = !indicatorItem.selected
2988+ }
2989+
2990+ Rectangle {
2991+ Layout.preferredHeight: units.dp(1);
2992+ Layout.fillWidth: true;
2993+ color: "black"
2994+ }
2995+
2996+ RowLayout {
2997+ CheckBox { id: iconEnabled; checked: true }
2998+ Label { text: "icons Count:" }
2999+ TextField { id: iconCount; text: "1"; enabled: iconEnabled.checked }
3000+ }
3001+
3002+ RowLayout {
3003+ Label { text: "Left Label:" }
3004+ TextField { id: leftLabel; text: "Left"}
3005+ }
3006+
3007+ RowLayout {
3008+ Label { text: "Right Label:" }
3009+ TextField { id: rightLabel; text: "Right"}
3010+ }
3011+
3012+ RowLayout {
3013+ Label { text: "Title:" }
3014+ TextField { id: titleLabel; text: "Title"}
3015+ }
3016+ }
3017+ }
3018+
3019+ UT.UnityTestCase {
3020+ name: "IndicatorItem"
3021+ when: windowShown
3022+
3023+ function init() {
3024+ indicatorItem.selected = false;
3025+ indicatorItem.expanded = false;
3026+ indicatorItem.rootActionState.title = "Test Title";
3027+ indicatorItem.rootActionState.leftLabel = "TestLeftLabel";
3028+ indicatorItem.rootActionState.rightLabel = "TestRightLabel";
3029+ indicatorItem.rootActionState.icons = [ "image://theme/audio-volume-high" ];
3030+
3031+ tryCompare(heightAnimation, "running", false);
3032+ }
3033+
3034+ function test_expand() {
3035+ indicatorItem.expanded = true;
3036+ tryCompare(indicatorItem, "height", units.gu(7));
3037+ indicatorItem.expanded = false;
3038+ tryCompare(indicatorItem, "height", units.gu(3));
3039+ }
3040+
3041+ function test_minimizedVisibility() {
3042+ compare(findChild(indicatorItem, "leftLabel").opacity, 1.0);
3043+ compare(findChild(indicatorItem, "rightLabel").opacity, 1.0);
3044+ compare(findChild(indicatorItem, "icons").opacity, 1.0);
3045+ compare(findChild(indicatorItem, "indicatorName").opacity, 0.0);
3046+ }
3047+
3048+ function test_expandIcon() {
3049+ indicatorItem.expanded = true;
3050+
3051+ tryCompare(findChild(indicatorItem, "leftLabel"), "opacity", 0.0);
3052+ tryCompare(findChild(indicatorItem, "rightLabel"), "opacity", 0.0);
3053+ tryCompare(findChild(indicatorItem, "icons"), "opacity", 1.0);
3054+ tryCompare(findChild(indicatorItem, "indicatorName"), "opacity", 1.0);
3055+ }
3056+
3057+ function test_expandRightLabel() {
3058+ indicatorItem.expanded = true;
3059+
3060+ indicatorItem.rootActionState.icons = [];
3061+
3062+ tryCompare(findChild(indicatorItem, "leftLabel"), "opacity", 0.0);
3063+ tryCompare(findChild(indicatorItem, "rightLabel"), "opacity", 1.0);
3064+ tryCompare(findChild(indicatorItem, "icons"), "opacity", 0.0);
3065+ tryCompare(findChild(indicatorItem, "indicatorName"), "opacity", 1.0);
3066+ }
3067+
3068+ function test_expandLeftLabel() {
3069+ indicatorItem.expanded = true;
3070+
3071+ indicatorItem.rootActionState.rightLabel = "";
3072+ indicatorItem.rootActionState.icons = [];
3073+
3074+ tryCompare(findChild(indicatorItem, "rightLabel"), "opacity", 0.0);
3075+ tryCompare(findChild(indicatorItem, "leftLabel"), "opacity", 1.0);
3076+ tryCompare(findChild(indicatorItem, "icons"), "opacity", 0.0);
3077+ tryCompare(findChild(indicatorItem, "indicatorName"), "opacity", 1.0);
3078+ }
3079+
3080+ function test_select() {
3081+ tryCompare(findChild(indicatorItem, "icon0"), "color", "#ededed");
3082+ tryCompare(findChild(indicatorItem, "icon0"), "opacity", 1.0);
3083+ tryCompare(findChild(indicatorItem, "leftLabel"), "color", "#ededed");
3084+ tryCompare(findChild(indicatorItem, "rightLabel"), "color", "#ededed");
3085+ tryCompare(findChild(indicatorItem, "indicatorName"), "color", "#ededed");
3086+
3087+ indicatorItem.expanded = true;
3088+ tryCompare(findChild(indicatorItem, "icon0"), "color", "#4c4c4c");
3089+ tryCompare(findChild(indicatorItem, "icon0"), "opacity", 0.6);
3090+ tryCompare(findChild(indicatorItem, "leftLabel"), "color", "#4c4c4c");
3091+ tryCompare(findChild(indicatorItem, "rightLabel"), "color", "#4c4c4c");
3092+ tryCompare(findChild(indicatorItem, "indicatorName"), "color", "#4c4c4c");
3093+
3094+ indicatorItem.selected = true;
3095+ tryCompare(findChild(indicatorItem, "icon0"), "color", "#ededed");
3096+ tryCompare(findChild(indicatorItem, "icon0"), "opacity", 1.0);
3097+ tryCompare(findChild(indicatorItem, "leftLabel"), "color", "#ededed");
3098+ tryCompare(findChild(indicatorItem, "rightLabel"), "color", "#ededed");
3099+ tryCompare(findChild(indicatorItem, "indicatorName"), "color", "#ededed");
3100+ }
3101+ }
3102+}
3103
3104=== removed file 'tests/qmltests/Panel/tst_IndicatorItem.qml'
3105--- tests/qmltests/Panel/tst_IndicatorItem.qml 2014-10-15 16:33:45 +0000
3106+++ tests/qmltests/Panel/tst_IndicatorItem.qml 1970-01-01 00:00:00 +0000
3107@@ -1,50 +0,0 @@
3108-/*
3109- * Copyright 2013 Canonical Ltd.
3110- *
3111- * This program is free software; you can redistribute it and/or modify
3112- * it under the terms of the GNU General Public License as published by
3113- * the Free Software Foundation; version 3.
3114- *
3115- * This program is distributed in the hope that it will be useful,
3116- * but WITHOUT ANY WARRANTY; without even the implied warranty of
3117- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3118- * GNU General Public License for more details.
3119- *
3120- * You should have received a copy of the GNU General Public License
3121- * along with this program. If not, see <http://www.gnu.org/licenses/>.
3122- */
3123-
3124-import QtQuick 2.0
3125-import QtTest 1.0
3126-import ".."
3127-import "../../../qml/Panel"
3128-import Ubuntu.Components 0.1
3129-import Unity.Test 0.1 as UT
3130-
3131-Rectangle {
3132- width: units.gu(10)
3133- height: units.gu(5)
3134- color: "black"
3135-
3136- IndicatorItem {
3137- id: indicatorItem
3138- anchors.fill: parent
3139- }
3140-
3141- UT.UnityTestCase {
3142- name: "IndicatorItem"
3143-
3144- function test_dimmed() {
3145- indicatorItem.dimmed = false;
3146- tryCompareFunction(function(){return indicatorItem.opacity}, 1.0);
3147- indicatorItem.dimmed = true;
3148- tryCompareFunction(function(){return indicatorItem.opacity < 1.0}, true);
3149- }
3150-
3151- function test_empty() {
3152- compare(indicatorItem.indicatorVisible, false, "IndicatorItem should not be visible.");
3153- indicatorItem.widgetSource = "../../../qml/Panel/Indicators/DefaultIndicatorWidget.qml";
3154- tryCompare(indicatorItem, "indicatorVisible", true);
3155- }
3156- }
3157-}
3158
3159=== added file 'tests/qmltests/Panel/tst_IndicatorItemRow.qml'
3160--- tests/qmltests/Panel/tst_IndicatorItemRow.qml 1970-01-01 00:00:00 +0000
3161+++ tests/qmltests/Panel/tst_IndicatorItemRow.qml 2014-10-15 16:33:46 +0000
3162@@ -0,0 +1,279 @@
3163+/*
3164+ * Copyright 2013-2014 Canonical Ltd.
3165+ *
3166+ * This program is free software; you can redistribute it and/or modify
3167+ * it under the terms of the GNU General Public License as published by
3168+ * the Free Software Foundation; version 3.
3169+ *
3170+ * This program is distributed in the hope that it will be useful,
3171+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3172+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3173+ * GNU General Public License for more details.
3174+ *
3175+ * You should have received a copy of the GNU General Public License
3176+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3177+ */
3178+
3179+import QtQuick 2.1
3180+import QtQuick.Layouts 1.1
3181+import QtTest 1.0
3182+import "../../../qml/Panel"
3183+import Ubuntu.Components 0.1
3184+import Unity.Test 0.1 as UT
3185+import Unity.Indicators 0.1 as Indicators
3186+
3187+IndicatorTest {
3188+ id: root
3189+ width: units.gu(100)
3190+ height: units.gu(40)
3191+ color: "white"
3192+
3193+ RowLayout {
3194+ anchors.fill: parent
3195+ anchors.margins: units.gu(1)
3196+
3197+ Rectangle {
3198+ Layout.fillWidth: true
3199+ Layout.fillHeight: true
3200+
3201+ id: itemArea
3202+ color: "blue"
3203+
3204+ Rectangle {
3205+ color: "black"
3206+ anchors.fill: indicatorsRow
3207+ }
3208+
3209+ IndicatorItemRow {
3210+ id: indicatorsRow
3211+ height: expanded ? units.gu(7) : units.gu(3)
3212+ anchors.centerIn: parent
3213+ indicatorsModel: root.indicatorsModel
3214+ enableLateralChanges: ma.pressed
3215+
3216+ Behavior on height {
3217+ NumberAnimation {
3218+ id: heightAnimation
3219+ duration: UbuntuAnimation.SnapDuration; easing: UbuntuAnimation.StandardEasing
3220+ }
3221+ }
3222+
3223+ MouseArea {
3224+ id: ma
3225+ anchors.fill: parent
3226+ onPositionChanged: {
3227+ indicatorsRow.lateralPosition = mouse.x;
3228+ }
3229+ onPressed: {
3230+ if (pressed) {
3231+ indicatorsRow.lateralPosition = mouse.x;
3232+ indicatorsRow.selectItemAt(mouse.x);
3233+ }
3234+ }
3235+ }
3236+ }
3237+ }
3238+
3239+ ColumnLayout {
3240+ Layout.alignment: Qt.AlignTop
3241+ Layout.fillWidth: false
3242+
3243+ Button {
3244+ Layout.fillWidth: true
3245+ text: indicatorsRow.expanded ? "Collapse" : "Expand"
3246+ onClicked: indicatorsRow.expanded = !indicatorsRow.expanded
3247+ }
3248+
3249+ Rectangle {
3250+ Layout.preferredHeight: units.dp(1);
3251+ Layout.fillWidth: true;
3252+ color: "black"
3253+ }
3254+
3255+ Repeater {
3256+ model: indicatorsModel.originalModelData
3257+ RowLayout {
3258+ CheckBox {
3259+ checked: true
3260+ onCheckedChanged: checked ? insertIndicator(index) : removeIndicator(index);
3261+ }
3262+ Label { text: modelData["identifier"] }
3263+ }
3264+ }
3265+ }
3266+ }
3267+
3268+ UT.UnityTestCase {
3269+ name: "IndicatorItemRow"
3270+ when: windowShown
3271+
3272+ function init() {
3273+ root.resetData();
3274+
3275+ indicatorsRow.resetCurrentItem();
3276+ indicatorsRow.lateralPosition = -1;
3277+
3278+ indicatorsRow.expanded = false;
3279+ tryCompare(heightAnimation, "running", false);
3280+ tryCompare(findChild(indicatorsRow, "highlight"), "highlightCenterOffset", 0);
3281+ wait(1); // row seems to take a bit of time for item x values to update.
3282+ }
3283+
3284+ function wait_for_expansion_to_settle() {
3285+ tryCompare(heightAnimation, "running", false);
3286+ wait(200); // put a little extra wait in for things to settle
3287+ }
3288+
3289+ function test_indicatorRowChanges_data() {
3290+ return [
3291+ { remove: [0, 2] },
3292+ { remove: [0, 1, 2, 3, 4] },
3293+ ];
3294+ }
3295+
3296+ // test the changes in the available indicators updates the
3297+ // indicators that are visible.
3298+ function test_indicatorRowChanges(data) {
3299+ var i;
3300+ var item;
3301+ var itemsToRemove = [0, 2];
3302+
3303+ verify(indicatorsModel.originalModelData.length > 0);
3304+ for (i = 0; i < indicatorsModel.originalModelData.length; i++) {
3305+ item = findChild(indicatorsRow, indicatorsModel.originalModelData[i]["identifier"] + "-panelItem");
3306+ verify(item);
3307+
3308+ compare(item.ownIndex, i, "Item at incorrect index");
3309+ }
3310+
3311+ for (i = data.remove.length-1; i >= 0; i--) {
3312+ removeIndicator(data.remove[i]);
3313+ }
3314+
3315+ // test removals
3316+ for (i = 0; i < indicatorsModel.originalModelData.length; i++) {
3317+ item = findChild(indicatorsRow, indicatorsModel.originalModelData[i]["identifier"] + "-panelItem");
3318+
3319+ verify(data.remove.indexOf(i) !== -1 ? (item === null) : (item !== null));
3320+ }
3321+
3322+ // test insertion
3323+ for (i = 0; i < data.remove.length; i++) {
3324+ insertIndicator(data.remove[i]);
3325+ }
3326+
3327+ for (i = 0; i < indicatorsModel.originalModelData.length; i++) {
3328+ item = findChild(indicatorsRow, indicatorsModel.originalModelData[i]["identifier"] + "-panelItem");
3329+ verify(item);
3330+
3331+ compare(item.ownIndex, i, "Item at incorrect index");
3332+ }
3333+ }
3334+
3335+ function test_validCurrentItem_data() {
3336+ return [
3337+ { index: 0 },
3338+ { index: 2 },
3339+ { index: 4 }
3340+ ];
3341+ }
3342+
3343+ // test selecting the item at it's position sets the current item of the row.
3344+ function test_validCurrentItem(data) {
3345+ var dataItem = findChild(indicatorsRow, indicatorsModel.originalModelData[data.index]["identifier"] + "-panelItem");
3346+ verify(dataItem !== null);
3347+
3348+ indicatorsRow.selectItemAt(dataItem.x + dataItem.width/2);
3349+ compare(indicatorsRow.currentItem, dataItem);
3350+ }
3351+
3352+ // tests item default selection (no item at position X)
3353+ function test_invalidCurrentItem() {
3354+ indicatorsRow.selectItemAt(-100);
3355+ var item = findChild(indicatorsRow, indicatorsModel.originalModelData[0]["identifier"] + "-panelItem");
3356+ compare(indicatorsRow.currentItem, item);
3357+ }
3358+
3359+ // testing that changing the lateral position offset of the row changes the current item.
3360+ function test_lateralPositionChangesCurrentItem_data() {
3361+ return [
3362+ { tag: "0 -> 4", from: 0, to: 4 },
3363+ { tag: "3 -> 1", from: 3, to: 1 }
3364+ ];
3365+ }
3366+
3367+ function test_lateralPositionChangesCurrentItem(data) {
3368+ indicatorsRow.expanded = true;
3369+ wait_for_expansion_to_settle();
3370+
3371+ var fromItem = findChild(indicatorsRow, indicatorsModel.originalModelData[data.from]["identifier"] + "-panelItem");
3372+ verify(fromItem !== null);
3373+
3374+ var toItem = findChild(indicatorsRow, indicatorsModel.originalModelData[data.to]["identifier"] + "-panelItem");
3375+ verify(toItem !== null);
3376+
3377+ var fromPosition = indicatorsRow.mapFromItem(fromItem, fromItem.width/2, fromItem.height/2);
3378+ var toPosition = indicatorsRow.mapFromItem(toItem, toItem.width/2, toItem.height/2);
3379+
3380+ mousePress(indicatorsRow, fromPosition.x, fromPosition.y);
3381+ compare(indicatorsRow.currentItem, fromItem, "Initial item not selected");
3382+
3383+ // this uses the MouseArea above to change the indicatorRow lateralPosition
3384+ mouseFlick(indicatorsRow, fromPosition.x, fromPosition.y, toPosition.x, toPosition.y, false, false, units.gu(5), 30);
3385+
3386+ mouseRelease(indicatorsRow, fromPosition.x, fromPosition.y);
3387+ compare(indicatorsRow.currentItem, toItem, "Current item did not change to expected item");
3388+ }
3389+
3390+ // testing that positive changes to the lateral position offset shifts the highlight offset to the right
3391+ function test_positiveLateralPositionChangesHighlightOffset() {
3392+ indicatorsRow.expanded = true;
3393+ wait_for_expansion_to_settle();
3394+
3395+ var highlight = findChild(indicatorsRow, "highlight");
3396+ var item = findChild(indicatorsRow, indicatorsModel.originalModelData[2]["identifier"] + "-panelItem");
3397+ verify(item !== null);
3398+ var mappedPosition = indicatorsRow.mapFromItem(item, item.width/2, item.height/2);
3399+
3400+ mousePress(indicatorsRow, mappedPosition.x, mappedPosition.y);
3401+ var originalHightlightX = highlight.x;
3402+ var offset = 1;
3403+ while((highlight.x - originalHightlightX) <= units.gu(0.5) && offset < units.gu(10)) {
3404+ mouseMove(indicatorsRow, mappedPosition.x + offset, mappedPosition.y, 10);
3405+ offset = offset + 2;
3406+ }
3407+ // verify that we hit the offset
3408+ verify((highlight.x - originalHightlightX) >= units.gu(0.5));
3409+ mouseRelease(indicatorsRow);
3410+
3411+ // should go back to 0
3412+ tryCompare(highlight, "highlightCenterOffset", 0);
3413+ }
3414+
3415+ // testing that negative changes to the lateral position offset shifts the highlight offset to the left
3416+ function test_negativeLateralPositionChangesHighlightOffset() {
3417+ indicatorsRow.expanded = true;
3418+ wait_for_expansion_to_settle();
3419+
3420+ var highlight = findChild(indicatorsRow, "highlight");
3421+ var item = findChild(indicatorsRow, indicatorsModel.originalModelData[2]["identifier"] + "-panelItem");
3422+ verify(item !== null);
3423+ var mappedPosition = indicatorsRow.mapFromItem(item, item.width/2, item.height/2);
3424+
3425+ mousePress(indicatorsRow, mappedPosition.x, mappedPosition.y);
3426+ var originalHightlightX = highlight.x;
3427+ var offset = 1;
3428+ while((highlight.x - originalHightlightX) >= -units.gu(0.5) && offset < units.gu(10)) {
3429+ mouseMove(indicatorsRow, mappedPosition.x - offset, mappedPosition.y, 10);
3430+ offset = offset + 2;
3431+ }
3432+
3433+ // verify that we hit the offset
3434+ verify((highlight.x - originalHightlightX) <= -units.gu(0.5));
3435+ mouseRelease(indicatorsRow);
3436+
3437+ // should go back to 0
3438+ tryCompare(findChild(indicatorsRow, "highlight"), "highlightCenterOffset", 0);
3439+ }
3440+ }
3441+}
3442
3443=== renamed file 'tests/qmltests/Panel/Indicators/tst_DefaultIndicatorPage.qml' => 'tests/qmltests/Panel/tst_IndicatorPage.qml'
3444--- tests/qmltests/Panel/Indicators/tst_DefaultIndicatorPage.qml 2014-10-15 16:33:45 +0000
3445+++ tests/qmltests/Panel/tst_IndicatorPage.qml 2014-10-15 16:33:46 +0000
3446@@ -1,5 +1,5 @@
3447 /*
3448- * Copyright 2013 Canonical Ltd.
3449+ * Copyright 2013-2014 Canonical Ltd.
3450 *
3451 * This program is free software; you can redistribute it and/or modify
3452 * it under the terms of the GNU General Public License as published by
3453@@ -18,14 +18,14 @@
3454 import QtTest 1.0
3455 import Unity.Test 0.1 as UT
3456 import Unity.Indicators 0.1 as Indicators
3457-import "../../../../qml/Panel/Indicators"
3458+import "../../../qml/Panel"
3459
3460 Item {
3461 id: testView
3462 width: units.gu(40)
3463 height: units.gu(70)
3464
3465- DefaultIndicatorPage {
3466+ IndicatorPage {
3467 id: page
3468 anchors.fill: parent
3469
3470@@ -117,7 +117,7 @@
3471 }
3472
3473 UT.UnityTestCase {
3474- name: "DefaultIndicatorPage"
3475+ name: "IndicatorPage"
3476
3477 function init() {
3478 initializeMenuData([]);
3479
3480=== removed file 'tests/qmltests/Panel/tst_IndicatorRow.qml'
3481--- tests/qmltests/Panel/tst_IndicatorRow.qml 2014-10-15 16:33:45 +0000
3482+++ tests/qmltests/Panel/tst_IndicatorRow.qml 1970-01-01 00:00:00 +0000
3483@@ -1,158 +0,0 @@
3484-/*
3485- * Copyright 2013 Canonical Ltd.
3486- *
3487- * This program is free software; you can redistribute it and/or modify
3488- * it under the terms of the GNU General Public License as published by
3489- * the Free Software Foundation; version 3.
3490- *
3491- * This program is distributed in the hope that it will be useful,
3492- * but WITHOUT ANY WARRANTY; without even the implied warranty of
3493- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3494- * GNU General Public License for more details.
3495- *
3496- * You should have received a copy of the GNU General Public License
3497- * along with this program. If not, see <http://www.gnu.org/licenses/>.
3498- */
3499-
3500-import QtQuick 2.0
3501-import QtTest 1.0
3502-import Unity.Test 0.1 as UT
3503-import ".."
3504-import "../../../qml/Panel"
3505-import Unity.Indicators 0.1 as Indicators
3506-
3507-/*
3508- This tests the IndicatorRow component by using a fake model to stage data in the indicators
3509- A view will show with indicators at the top, as does in the shell.
3510-*/
3511-Item {
3512- id: rootItem
3513- width: units.gu(40)
3514- height: units.gu(60)
3515-
3516- PanelBackground {
3517- anchors.fill: indicatorRow
3518- }
3519-
3520- IndicatorRow {
3521- id: indicatorRow
3522- anchors {
3523- left: parent.left
3524- right: parent.right
3525- }
3526-
3527- indicatorsModel: indicatorModel
3528-
3529- Component.onCompleted: indicatorModel.load("test1")
3530- }
3531-
3532- Indicators.IndicatorsModel {
3533- id: indicatorModel
3534- }
3535-
3536- UT.UnityTestCase {
3537- name: "IndicatorRow"
3538- when: windowShown
3539-
3540- function init() {
3541- indicatorModel.load("test1");
3542-
3543- indicatorRow.state = "initial";
3544- indicatorRow.setCurrentItemIndex(-1);
3545- indicatorRow.unitProgress = 0.0;
3546- }
3547-
3548- function get_indicator_item(index) {
3549- return findChild(indicatorRow.row, "item" + index);
3550- }
3551-
3552- function test_set_current_item() {
3553- indicatorRow.setCurrentItemIndex(0);
3554- compare(indicatorRow.indicatorsModel.data(indicatorRow.currentItemIndex, Indicators.IndicatorsModelRole.Identifier),
3555- "indicator-fake1",
3556- "Incorrect item at position 0");
3557-
3558- indicatorRow.setCurrentItemIndex(1);
3559- compare(indicatorRow.indicatorsModel.data(indicatorRow.currentItemIndex, Indicators.IndicatorsModelRole.Identifier),
3560- "indicator-fake2",
3561- "Incorrect item at position 1");
3562-
3563- indicatorRow.setCurrentItemIndex(2);
3564- compare(indicatorRow.indicatorsModel.data(indicatorRow.currentItemIndex, Indicators.IndicatorsModelRole.Identifier),
3565- "indicator-fake3",
3566- "Incorrect item at position 2");
3567- }
3568-
3569- function test_highlight_data() {
3570- return [
3571- { index: 0, progress: 0.0, current: false, other: false },
3572- { index: 0, progress: 0.1, current: true, other: false },
3573- { index: 0, progress: 0.5, current: true, other: false },
3574- { index: 0, progress: 1.0, current: true, other: false },
3575- { index: 2, progress: 0.0, current: false, other: false },
3576- { index: 2, progress: 0.1, current: true, other: false },
3577- { index: 2, progress: 0.5, current: true, other: false },
3578- { index: 2, progress: 1.0, current: true, other: false }
3579- ];
3580- }
3581-
3582- function test_highlight(data) {
3583- indicatorRow.unitProgress = data.progress;
3584- indicatorRow.setCurrentItemIndex(data.index);
3585-
3586- compare(indicatorRow.currentItem.highlighted, data.current, "Indicator hightlight did not match for current item");
3587-
3588- for (var i = 0; i < indicatorRow.row.count; i++) {
3589- compare(get_indicator_item(i).highlighted, i === data.index ? data.current: data.other, "Indicator hightlight did not match for item iter");
3590- }
3591- }
3592-
3593- function test_opacity_data() {
3594- return [
3595- { index: 0, progress: 0.0, current: 1.0, other: 1.0 },
3596- { index: 0, progress: 0.1, current: 1.0, other: 0.9 },
3597- { index: 0, progress: 0.5, current: 1.0, other: 0.5 },
3598- { index: 0, progress: 1.0, current: 1.0, other: 0.0 },
3599- { index: 2, progress: 0.0, current: 1.0, other: 1.0 },
3600- { index: 2, progress: 0.1, current: 1.0, other: 0.9 },
3601- { index: 2, progress: 0.5, current: 1.0, other: 0.5 },
3602- { index: 2, progress: 1.0, current: 1.0, other: 0.0 }
3603- ];
3604- }
3605-
3606- function test_opacity(data) {
3607- indicatorRow.unitProgress = data.progress;
3608- indicatorRow.setCurrentItemIndex(data.index);
3609-
3610- tryCompare(indicatorRow.currentItem, "opacity", data.current);
3611-
3612- for (var i = 0; i < indicatorRow.row.count; i++) {
3613- tryCompare(get_indicator_item(i), "opacity", i === data.index ? data.current: data.other);
3614- }
3615- }
3616-
3617- function test_dimmed_data() {
3618- return [
3619- { index: 0, progress: 0.0, current: false, other: false },
3620- { index: 0, progress: 0.1, current: false, other: true },
3621- { index: 0, progress: 0.5, current: false, other: true },
3622- { index: 0, progress: 1.0, current: false, other: true },
3623- { index: 2, progress: 0.0, current: false, other: false },
3624- { index: 2, progress: 0.1, current: false, other: true },
3625- { index: 2, progress: 0.5, current: false, other: true },
3626- { index: 2, progress: 1.0, current: false, other: true }
3627- ];
3628- }
3629-
3630- function test_dimmed(data) {
3631- indicatorRow.unitProgress = data.progress;
3632- indicatorRow.setCurrentItemIndex(data.index);
3633-
3634- compare(indicatorRow.currentItem.dimmed, data.current, "Indicator dim did not match for current item");
3635-
3636- for (var i = 0; i < indicatorRow.row.count; i++) {
3637- compare(get_indicator_item(i).dimmed, i === data.index ? data.current: data.other, "Indicator dim did not match for item iter");
3638- }
3639- }
3640- }
3641-}
3642
3643=== removed file 'tests/qmltests/Panel/tst_Indicators.qml'
3644--- tests/qmltests/Panel/tst_Indicators.qml 2014-10-15 16:33:45 +0000
3645+++ tests/qmltests/Panel/tst_Indicators.qml 1970-01-01 00:00:00 +0000
3646@@ -1,231 +0,0 @@
3647-/*
3648- * Copyright 2013 Canonical Ltd.
3649- *
3650- * This program is free software; you can redistribute it and/or modify
3651- * it under the terms of the GNU General Public License as published by
3652- * the Free Software Foundation; version 3.
3653- *
3654- * This program is distributed in the hope that it will be useful,
3655- * but WITHOUT ANY WARRANTY; without even the implied warranty of
3656- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3657- * GNU General Public License for more details.
3658- *
3659- * You should have received a copy of the GNU General Public License
3660- * along with this program. If not, see <http://www.gnu.org/licenses/>.
3661- */
3662-
3663-import QtQuick 2.0
3664-import QtTest 1.0
3665-import Unity.Test 0.1 as UT
3666-import Ubuntu.Components 0.1 as UC
3667-import ".."
3668-import "../../../qml/Panel"
3669-import "../../../qml/Components"
3670-
3671-/*
3672- This tests the Indicators component by using a fake model to stage data in the indicators
3673- A view will show with indicators at the top, as does in the shell. There is a clickable area
3674- marked "Click Me" which can be used to expose the indicators.
3675-*/
3676-Item {
3677- id: shell
3678- width: units.gu(40)
3679- height: units.gu(80)
3680-
3681- PanelBackground {
3682- anchors.fill: indicators
3683- }
3684-
3685- Indicators {
3686- id: indicators
3687- anchors {
3688- right: parent.right
3689- }
3690- width: (shell.width > units.gu(60)) ? units.gu(40) : shell.width
3691- y: 0
3692- shown: false
3693- profile: "test1"
3694-
3695- openedHeight: parent.height - button.height
3696- }
3697-
3698- UC.Button {
3699- id: button
3700- text: indicators.shown ? "Hide" : "Show"
3701- anchors {
3702- bottom: shell.bottom
3703- left: parent.left
3704- right: parent.right
3705- }
3706- height: 50
3707-
3708- onClicked: {
3709- if (!indicators.shown) {
3710- indicators.show();
3711- } else {
3712- indicators.hide();
3713- }
3714- }
3715- }
3716-
3717- UT.UnityTestCase {
3718- name: "Indicators"
3719- when: windowShown
3720-
3721- function init() {
3722- indicators.initialise();
3723-
3724- indicators.hide();
3725- tryCompare(indicators.hideAnimation, "running", false);
3726- tryCompare(indicators, "state", "initial");
3727- }
3728-
3729- // Showing the indicators should fully open the indicator panel.
3730- function test_show() {
3731- indicators.show()
3732- tryCompare(indicators, "fullyOpened", true);
3733- }
3734-
3735- // Test the change in the revealer lateral position changes the current panel menu to fit the position
3736- // of the indicator in the row.
3737- function test_change_revealer_lateral_position()
3738- {
3739- // tests changing the lateral position of the revealer activates the correct indicator items.
3740-
3741- var indicatorRow = findChild(indicators, "indicatorRow")
3742- verify(indicatorRow !== null);
3743- var indicatorRowItems = findChild(indicatorRow, "indicatorRowItems");
3744- verify(indicatorRowItems !== null);
3745-
3746- for (var i = 0; i < indicatorRowItems.count; i++) {
3747- var indicatorItem = findChild(indicatorRowItems, "item" + i);
3748-
3749- if (!indicatorItem.visible)
3750- continue;
3751-
3752- var indicatorPosition = indicators.mapFromItem(indicatorItem,
3753- indicatorItem.width/2, indicatorItem.height/2);
3754-
3755- touchFlick(indicators,
3756- indicatorPosition.x, indicatorPosition.y,
3757- indicatorPosition.x, indicators.openedHeight * 0.4,
3758- true /* beginTouch */, false /* endTouch */);
3759-
3760- compare(indicatorRow.currentItem, indicatorItem,
3761- "Incorrect item activated at position " + i);
3762-
3763- touchFlick(indicators,
3764- indicatorPosition.x, indicators.openedHeight * 0.4,
3765- indicatorPosition.x, indicatorPosition.y,
3766- false /* beginTouch */, true /* endTouch */);
3767-
3768- // wait until fully closed
3769- tryCompare(indicators, "height", indicators.panelHeight);
3770- }
3771- }
3772-
3773- // values for specific state changes are subject to internal decisions, so we can't
3774- // determine the true height value which would cause the state to change without making
3775- // too many assuptyions
3776- // However, we can assume that a partially opened panel will not be initial, and fully
3777- // opened panel will be locked.
3778-
3779- function test_progress_changes_state_to_not_initial() {
3780- indicators.height = indicators.openedHeight / 2
3781- compare(indicators.state!="initial", true,
3782- "Indicators should not be in initial state when partially opened.");
3783- }
3784-
3785- function test_progress_changes_state_to_locked() {
3786- indicators.height = indicators.openedHeight - indicators.panelHeight
3787- compare(indicators.state, "locked", "Indicators should be locked when fully opened.");
3788- }
3789-
3790- function test_partially_open() {
3791- indicators.height = indicators.openedHeight / 2
3792- compare(indicators.partiallyOpened, true,
3793- "Indicator should show as partially opened when height is half of openedHeight");
3794- compare(indicators.fullyOpened, false,
3795- "Indicator should not show as fully opened when height is half of openedHeight");
3796- }
3797-
3798- function test_fully_open() {
3799- indicators.height = indicators.openedHeight
3800- compare(indicators.partiallyOpened, false);
3801- compare(indicators.fullyOpened, true);
3802- }
3803-
3804- function init_invisible_indicator(identifier) {
3805- tryCompareFunction(function() { return findChild(indicators, identifier+"-delegate") !== undefined }, true);
3806- var item = findChild(indicators, identifier+"-delegate");
3807- verify(item !== null);
3808-
3809- item.enabled = false;
3810- }
3811-
3812- function test_row_visible_menuContent_visible_data() { return [
3813- {tag: "first", visible: [false, true, true, true, true] },
3814- {tag: "adjacent", visible: [true, false, false, true, true] },
3815- {tag: "bounds", visible: [false, true, true, true, false] },
3816- {tag: "disjoint", visible: [true, false, true, false, true] },
3817- {tag: "last", visible: [true, true, true, true, false] }];
3818- }
3819-
3820- function test_row_visible_menuContent_visible(data) {
3821- indicators.show();
3822-
3823- var contentListView = findChild(indicators, "indicatorsContentListView");
3824- var indicatorRowItems = findChild(indicators, "indicatorRowItems");
3825-
3826- var count = data.visible.length
3827- for (var i = 0; i< data.visible.length; i++) {
3828- if (data.visible[i] === false) {
3829- init_invisible_indicator("indicator-fake" + (i + 1));
3830- count--;
3831- }
3832- }
3833-
3834- tryCompare(indicatorRowItems, "count", count);
3835-
3836- for (i = 0; i < data.visible.length; i++) {
3837- var widgetName = "indicator-fake" + (i + 1 + "-widget");
3838- var pageName = "indicator-fake" + (i + 1 + "-page");
3839-
3840- // check for item
3841- tryCompareFunction(function() { return findChild(indicatorRowItems, widgetName) !== null }, data.visible[i]);
3842-
3843- // check for tab
3844- tryCompareFunction(function() { return findChild(contentListView, pageName) !== null }, data.visible[i]);
3845- }
3846- }
3847-
3848- function test_indicator_visible_correct_menu_data() { return [
3849- {tag: "current-first", currentIndex: 0, visible: [false, true, true, true, true], expectedIndex: 0, expextedMenu: "indicator-fake2" },
3850- {tag: "current-last", currentIndex: 4, visible: [true, true, true, true, false], expectedIndex: 3, expextedMenu: "indicator-fake4" },
3851- {tag: "after", currentIndex: 0, visible: [true, false, true, true, true], expectedIndex: 0, expextedMenu: "indicator-fake1" },
3852- {tag: "before", currentIndex: 1, visible: [false, true, true, true, true], expectedIndex: 1, expextedMenu: "indicator-fake2" }];
3853- }
3854-
3855- function test_indicator_visible_correct_menu(data) {
3856- var contentListView = findChild(indicators, "indicatorsContentListView");
3857- var indicatorRow = findChild(indicators, "indicatorRow");
3858-
3859- indicators.show();
3860- indicatorRow.setCurrentItemIndex(data.currentIndex);
3861- tryCompare(indicators, "fullyOpened", true);
3862-
3863- for (var i = 0; i< data.visible.length; i++) {
3864- if (data.visible[i] === false) {
3865- init_invisible_indicator("indicator-fake" + (i + 1));
3866- }
3867- }
3868-
3869- // check for current selected item
3870- tryCompare(indicatorRow, "currentItemIndex", data.expectedIndex);
3871-
3872- // check for current selected tab
3873- tryCompareFunction(function() { return findChild(contentListView, data.expextedMenu) === contentListView.currentItem }, true);
3874-
3875- }
3876- }
3877-}
3878
3879=== added file 'tests/qmltests/Panel/tst_IndicatorsBar.qml'
3880--- tests/qmltests/Panel/tst_IndicatorsBar.qml 1970-01-01 00:00:00 +0000
3881+++ tests/qmltests/Panel/tst_IndicatorsBar.qml 2014-10-15 16:33:46 +0000
3882@@ -0,0 +1,178 @@
3883+/*
3884+ * Copyright 2013-2014 Canonical Ltd.
3885+ *
3886+ * This program is free software; you can redistribute it and/or modify
3887+ * it under the terms of the GNU General Public License as published by
3888+ * the Free Software Foundation; version 3.
3889+ *
3890+ * This program is distributed in the hope that it will be useful,
3891+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3892+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3893+ * GNU General Public License for more details.
3894+ *
3895+ * You should have received a copy of the GNU General Public License
3896+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3897+ */
3898+
3899+import QtQuick 2.1
3900+import QtQuick.Layouts 1.1
3901+import QtTest 1.0
3902+import "../../../qml/Panel"
3903+import Ubuntu.Components 0.1
3904+import Unity.Test 0.1 as UT
3905+import Unity.Indicators 0.1 as Indicators
3906+
3907+IndicatorTest {
3908+ id: root
3909+ width: units.gu(100)
3910+ height: units.gu(40)
3911+
3912+
3913+ RowLayout {
3914+ anchors.fill: parent
3915+ anchors.margins: units.gu(1)
3916+
3917+ Rectangle {
3918+ id: itemArea
3919+ color: "blue"
3920+ Layout.fillWidth: true
3921+ Layout.fillHeight: true
3922+
3923+ Rectangle {
3924+ color: "black"
3925+ anchors.fill: indicatorsBar
3926+ }
3927+
3928+ IndicatorsBar {
3929+ id: indicatorsBar
3930+ height: expanded ? units.gu(7) : units.gu(3)
3931+ width: units.gu(30)
3932+ anchors.centerIn: parent
3933+ indicatorsModel: root.indicatorsModel
3934+
3935+ Behavior on height {
3936+ NumberAnimation {
3937+ id: heightAnimation
3938+ duration: UbuntuAnimation.SnapDuration; easing: UbuntuAnimation.StandardEasing
3939+ }
3940+ }
3941+
3942+ MouseArea {
3943+ anchors.fill: parent
3944+ enabled: !indicatorsBar.expanded
3945+ onPressed: {
3946+ indicatorsBar.selectItemAt(mouse.x);
3947+ indicatorsBar.expanded = true
3948+ }
3949+ }
3950+ }
3951+ }
3952+
3953+ ColumnLayout {
3954+ Layout.alignment: Qt.AlignTop
3955+ Layout.fillWidth: false
3956+
3957+ Button {
3958+ Layout.fillWidth: true
3959+ text: indicatorsBar.expanded ? "Collapse" : "Expand"
3960+ onClicked: indicatorsBar.expanded = !indicatorsBar.expanded
3961+ }
3962+
3963+ Rectangle {
3964+ Layout.preferredHeight: units.dp(1);
3965+ Layout.fillWidth: true;
3966+ color: "black"
3967+ }
3968+
3969+ Repeater {
3970+ model: indicatorsModel.originalModelData
3971+ RowLayout {
3972+ CheckBox {
3973+ checked: true
3974+ onCheckedChanged: checked ? insertIndicator(index) : removeIndicator(index);
3975+ }
3976+ Label { text: modelData["identifier"] }
3977+ }
3978+ }
3979+ }
3980+ }
3981+
3982+ UT.UnityTestCase {
3983+ name: "IndicatorsBar"
3984+ when: windowShown
3985+
3986+ function init() {
3987+ indicatorsBar.expanded = false;
3988+ tryCompare(heightAnimation, "running", false);
3989+ }
3990+
3991+ function test_expandSelectedItem_data() {
3992+ return [
3993+ { index: 0 },
3994+ { index: 2 },
3995+ { index: 4 }
3996+ ];
3997+ }
3998+
3999+ function wait_for_expansion_to_settle() {
4000+ tryCompare(heightAnimation, "running", false);
4001+ wait(200); // put a little extra wait in for things to settle
4002+ }
4003+
4004+ // Rough check that expanding a selected item keeps it within the area of the original item.
4005+ function test_expandSelectedItem(data) {
4006+ var dataItem = findChild(indicatorsBar, indicatorsModel.originalModelData[data.index]["identifier"] + "-panelItem");
4007+ verify(dataItem !== null);
4008+
4009+ var mappedPosition = indicatorsBar.mapFromItem(dataItem, dataItem.width/2, dataItem.height/2);
4010+
4011+ indicatorsBar.selectItemAt(mappedPosition.x);
4012+ indicatorsBar.expanded = true;
4013+ wait_for_expansion_to_settle();
4014+
4015+ var mappedRect = indicatorsBar.mapFromItem(dataItem, 0, 0, dataItem.width, dataItem.height);
4016+
4017+ // mappedPosition contained within mappedRect
4018+ verify(mappedRect.x <= mappedPosition.x);
4019+ verify(mappedRect.x + mappedRect.width >= mappedPosition.x);
4020+ }
4021+
4022+ function test_scrollOffset() {
4023+ indicatorsBar.expanded = true;
4024+ wait_for_expansion_to_settle();
4025+
4026+ var lastItemIndex = indicatorsModel.originalModelData.length-1;
4027+ var dataItem = findChild(indicatorsBar, indicatorsModel.originalModelData[lastItemIndex]["identifier"] + "-panelItem");
4028+ verify(dataItem !== null);
4029+
4030+ var row = findChild(indicatorsBar, "indicatorItemRow");
4031+ // test will not work without these conditions
4032+ verify(row.width >= indicatorsBar.width + dataItem.width);
4033+
4034+ var mappedPosition = indicatorsBar.mapFromItem(dataItem, dataItem.width/2, dataItem.height/2);
4035+ indicatorsBar.addScrollOffset(-dataItem.width);
4036+ var newMappedPosition = indicatorsBar.mapFromItem(dataItem, dataItem.width/2, dataItem.height/2);
4037+
4038+ compare(mappedPosition.x, newMappedPosition.x - dataItem.width);
4039+ }
4040+
4041+ function test_selectItemWhenExpanded_data() {
4042+ return [
4043+ { index: 3 },
4044+ { index: 4 }
4045+ ];
4046+ }
4047+
4048+ function test_selectItemWhenExpanded(data) {
4049+ indicatorsBar.expanded = true;
4050+ wait_for_expansion_to_settle();
4051+
4052+ var dataItem = findChild(indicatorsBar, indicatorsModel.originalModelData[data.index]["identifier"] + "-panelItem");
4053+ if (indicatorsBar.mapFromItem(dataItem, dataItem.width/2, dataItem.height/2).x < 0) {
4054+ skip("Out of bounds");
4055+ }
4056+ mouseClick(dataItem, dataItem.width/2, dataItem.height/2);
4057+ verify(dataItem.selected === true);
4058+ }
4059+ }
4060+}
4061
4062=== added file 'tests/qmltests/Panel/tst_IndicatorsMenu.qml'
4063--- tests/qmltests/Panel/tst_IndicatorsMenu.qml 1970-01-01 00:00:00 +0000
4064+++ tests/qmltests/Panel/tst_IndicatorsMenu.qml 2014-10-15 16:33:46 +0000
4065@@ -0,0 +1,247 @@
4066+/*
4067+ * Copyright 2013-2014 Canonical Ltd.
4068+ *
4069+ * This program is free software; you can redistribute it and/or modify
4070+ * it under the terms of the GNU General Public License as published by
4071+ * the Free Software Foundation; version 3.
4072+ *
4073+ * This program is distributed in the hope that it will be useful,
4074+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4075+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4076+ * GNU General Public License for more details.
4077+ *
4078+ * You should have received a copy of the GNU General Public License
4079+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4080+ */
4081+
4082+import QtQuick 2.1
4083+import QtQuick.Layouts 1.1
4084+import QtTest 1.0
4085+import "../../../qml/Panel"
4086+import Ubuntu.Components 0.1
4087+import Unity.Test 0.1 as UT
4088+import Unity.Indicators 0.1 as Indicators
4089+
4090+IndicatorTest {
4091+ id: root
4092+ width: units.gu(80)
4093+ height: units.gu(71)
4094+ color: "white"
4095+
4096+ property string indicatorProfile: "phone"
4097+
4098+ RowLayout {
4099+ anchors.fill: parent
4100+ anchors.margins: units.gu(1)
4101+
4102+ Rectangle {
4103+ Layout.fillWidth: true
4104+ Layout.fillHeight: true
4105+
4106+ id: itemArea
4107+ color: "blue"
4108+
4109+ IndicatorsMenu {
4110+ id: indicatorsMenu
4111+ width: units.gu(40)
4112+ anchors {
4113+ top: parent.top
4114+ right: parent.right
4115+ }
4116+ minimizedPanelHeight: units.gu(3)
4117+ expandedPanelHeight: units.gu(7)
4118+ openedHeight: parent.height
4119+ indicatorsModel: root.indicatorsModel
4120+ shown: false
4121+ }
4122+ }
4123+
4124+ ColumnLayout {
4125+ Layout.alignment: Qt.AlignTop
4126+ Layout.fillWidth: false
4127+
4128+ Button {
4129+ Layout.fillWidth: true
4130+ text: indicatorsMenu.shown ? "Hide" : "Show"
4131+ onClicked: {
4132+ if (indicatorsMenu.shown) {
4133+ indicatorsMenu.hide();
4134+ } else {
4135+ indicatorsMenu.show();
4136+ }
4137+ }
4138+ }
4139+
4140+ Rectangle {
4141+ Layout.preferredHeight: units.dp(1);
4142+ Layout.fillWidth: true;
4143+ color: "black"
4144+ }
4145+
4146+ Repeater {
4147+ model: indicatorsModel.originalModelData
4148+ RowLayout {
4149+ CheckBox {
4150+ checked: true
4151+ onCheckedChanged: checked ? insertIndicator(index) : removeIndicator(index);
4152+ }
4153+ Label { text: modelData["identifier"] }
4154+ }
4155+ }
4156+ }
4157+ }
4158+
4159+ UT.UnityTestCase {
4160+ id: testCase
4161+ name: "IndicatorsMenu"
4162+ when: windowShown
4163+
4164+ function init() {
4165+ indicatorsMenu.hide();
4166+ tryCompare(indicatorsMenu.hideAnimation, "running", false);
4167+ compare(indicatorsMenu.state, "initial");
4168+
4169+ indicatorsMenu.verticalVelocityThreshold = 0.5
4170+ }
4171+
4172+ function get_indicator_item(index) {
4173+ var indicatorItem = findChild(indicatorsMenu, indicatorsModel.originalModelData[index]["identifier"] + "-panelItem");
4174+ verify(indicatorItem !== null);
4175+
4176+ return indicatorItem;
4177+ }
4178+
4179+ // Showing the indicators should fully open the indicator panel.
4180+ function test_showAndHide() {
4181+ indicatorsMenu.show();
4182+ tryCompare(indicatorsMenu, "fullyOpened", true);
4183+
4184+ indicatorsMenu.hide();
4185+ tryCompare(indicatorsMenu, "fullyClosed", true);
4186+ }
4187+
4188+ // Test that closing the indicators ends up in the correct position.
4189+ function test_hideEndsInCorrectPosition() {
4190+ var indicatorsBar = findChild(indicatorsMenu, "indicatorsBar");
4191+ var flickable = findChild(indicatorsBar, "flickable");
4192+
4193+ var originalContentX = flickable.contentX;
4194+
4195+ indicatorsMenu.show();
4196+ indicatorsBar.setCurrentItemIndex(0);
4197+ tryCompare(indicatorsMenu, "fullyOpened", true);
4198+
4199+ indicatorsMenu.hide();
4200+ tryCompare(flickable, "contentX", originalContentX);
4201+ }
4202+
4203+ function test_progress_changes_state_to_reveal() {
4204+ indicatorsMenu.height = indicatorsMenu.openedHeight / 2;
4205+ compare(indicatorsMenu.state, "reveal", "Indicators should be revealing when partially opened.");
4206+
4207+ indicatorsMenu.height = indicatorsMenu.openedHeight;
4208+ compare(indicatorsMenu.state, "reveal", "Indicators should still be revealing when fully opened.");
4209+ }
4210+
4211+ function test_open_state() {
4212+ compare(indicatorsMenu.fullyClosed, true, "Indicator should show as fully closed.");
4213+ compare(indicatorsMenu.partiallyOpened, false, "Indicator should not show as partially opened");
4214+ compare(indicatorsMenu.fullyOpened, false, "Indicator should not show as fully opened");
4215+
4216+ indicatorsMenu.height = indicatorsMenu.openedHeight / 2
4217+ compare(indicatorsMenu.fullyClosed, false, "Indicator should not show as fully closed.");
4218+ compare(indicatorsMenu.partiallyOpened, true, "Indicator should show as partially opened");
4219+ compare(indicatorsMenu.fullyOpened, false, "Indicator should not show as fully opened");
4220+
4221+ indicatorsMenu.height = indicatorsMenu.openedHeight;
4222+ compare(indicatorsMenu.fullyClosed, false, "Indicator should not show as fully closed.");
4223+ compare(indicatorsMenu.partiallyOpened, false, "Indicator should show as partially opened");
4224+ compare(indicatorsMenu.fullyOpened, true, "Indicator should not show as fully opened");
4225+ }
4226+
4227+ // Pressing on the indicator panel should activate the indicator hints
4228+ // and expose the header
4229+ function test_hint() {
4230+ var indicatorItem = get_indicator_item(0);
4231+ var mappedPosition = root.mapFromItem(indicatorItem, indicatorItem.width/2, indicatorItem.height/2);
4232+
4233+ touchPress(indicatorsMenu, mappedPosition.x, indicatorsMenu.minimizedPanelHeight / 2);
4234+
4235+ // hint animation should be run, meaning that indicators will move downwards
4236+ // by hintValue pixels without any drag taking place
4237+ tryCompareFunction(function() { return indicatorsMenu.height }, indicatorsMenu.expandedPanelHeight + units.gu(2));
4238+ tryCompare(indicatorsMenu, "partiallyOpened", true);
4239+
4240+ touchRelease(indicatorsMenu, mappedPosition.x, indicatorsMenu.minimizedPanelHeight / 2);
4241+ }
4242+
4243+ // tests swiping on an indicator item activates the correct item.
4244+ function test_swipeForCurrentItem()
4245+ {
4246+ var indicatorItemRow = findChild(indicatorsMenu, "indicatorItemRow");
4247+ verify(indicatorItemRow !== null);
4248+
4249+ for (var i = 0; i < indicatorsModel.originalModelData.length; i++) {
4250+ var indicatorItem = get_indicator_item(i);
4251+
4252+ var mappedPosition = root.mapFromItem(indicatorItem, indicatorItem.width/2, indicatorItem.height/2);
4253+
4254+ touchFlick(indicatorsMenu,
4255+ mappedPosition.x, mappedPosition.y,
4256+ mappedPosition.x, indicatorsMenu.openedHeight / 2,
4257+ true /* beginTouch */, false /* endTouch */);
4258+
4259+ compare(indicatorItemRow.currentItem, indicatorItem,
4260+ "Incorrect item activated at position " + i);
4261+
4262+ touchFlick(indicatorItemRow,
4263+ mappedPosition.x, indicatorsMenu.openedHeight / 2,
4264+ mappedPosition.x, mappedPosition.y,
4265+ false /* beginTouch */, true /* endTouch */);
4266+
4267+ // wait until fully closed
4268+ tryCompare(indicatorsMenu, "fullyClosed", true);
4269+ }
4270+ }
4271+
4272+ // Test the vertical velocity check when flicking the indicators open at an angle.
4273+ // If the vertical velocity is above a specific point, we shouldnt change active indicators
4274+ // if the x position changes
4275+ function test_verticalVelocityDetector() {
4276+ indicatorsMenu.verticalVelocityThreshold = 0;
4277+ verify(indicatorsModel.originalModelData.length >= 2);
4278+
4279+ var indicatorItemRow = findChild(indicatorsMenu, "indicatorItemRow");
4280+ verify(indicatorItemRow !== null);
4281+
4282+ // Get the first indicator
4283+ var firstItem = get_indicator_item(0);
4284+ var firstItemMappedPosition = root.mapFromItem(firstItem, firstItem.width/2, firstItem.height/2);
4285+
4286+ // 1) Drag the mouse down to hint a bit
4287+ touchFlick(indicatorsMenu,
4288+ firstItemMappedPosition.x, indicatorsMenu.minimizedPanelHeight / 2,
4289+ firstItemMappedPosition.x, indicatorsMenu.minimizedPanelHeight * 2,
4290+ true /* beginTouch */, false /* endTouch */);
4291+
4292+ tryCompare(indicatorItemRow, "currentItem", firstItem)
4293+
4294+ // next time position will have moved.
4295+ var nextItem = get_indicator_item(1);
4296+ var nextItemMappedPosition = root.mapFromItem(nextItem, nextItem.width/2, nextItem.height/2);
4297+
4298+ // 1) Flick mouse down to bottom
4299+ touchFlick(indicatorsMenu,
4300+ firstItemMappedPosition.x, indicatorsMenu.minimizedPanelHeight * 2,
4301+ nextItemMappedPosition.x, indicatorsMenu.openedHeight / 3,
4302+ false /* beginTouch */, false /* endTouch */,
4303+ units.gu(50) /* speed */, 5 /* iterations */); // more samples needed for accurate velocity
4304+
4305+ compare(indicatorItemRow.currentItem, firstItem, "First indicator should still be the current item");
4306+ // after waiting in the same spot with touch down, it should update to the next item.
4307+ tryCompare(indicatorItemRow, "currentItem", nextItem);
4308+
4309+ touchRelease(indicatorsMenu, nextItemMappedPosition.x, indicatorsMenu.openedHeight / 3);
4310+ }
4311+ }
4312+}
4313
4314=== modified file 'tests/qmltests/Panel/tst_MenuContent.qml'
4315--- tests/qmltests/Panel/tst_MenuContent.qml 2014-10-15 16:33:45 +0000
4316+++ tests/qmltests/Panel/tst_MenuContent.qml 2014-10-15 16:33:46 +0000
4317@@ -1,5 +1,5 @@
4318 /*
4319- * Copyright 2013 Canonical Ltd.
4320+ * Copyright 2013-2014 Canonical Ltd.
4321 *
4322 * This program is free software; you can redistribute it and/or modify
4323 * it under the terms of the GNU General Public License as published by
4324@@ -17,12 +17,11 @@
4325 import QtQuick 2.0
4326 import QtTest 1.0
4327 import Unity.Test 0.1 as UT
4328-import ".."
4329 import "../../../qml/Panel"
4330 import Unity.Indicators 0.1 as Indicators
4331
4332-Item {
4333- id: shell
4334+IndicatorTest {
4335+ id: root
4336 width: units.gu(40)
4337 height: units.gu(70)
4338
4339@@ -30,15 +29,9 @@
4340 Item { id: greeter }
4341 Item { id: handle }
4342
4343-
4344- Indicators.IndicatorsModel {
4345- id: indicatorsModel
4346- Component.onCompleted: load("test1")
4347- }
4348-
4349 MenuContent {
4350 id: menuContent
4351- indicatorsModel: indicatorsModel
4352+ indicatorsModel: root.indicatorsModel
4353 height: parent.height - 50
4354 }
4355
4356@@ -107,7 +100,7 @@
4357
4358 // Check that the correct menus are displayed for the requested item.
4359 function test_show_menu() {
4360- var menuCount = indicatorsModel.count;
4361+ var menuCount = root.indicatorsModel.count;
4362 verify(menuCount > 0, "Menu count should be greater than zero");
4363
4364 var listView = menu_content_test.findChild(menuContent, "indicatorsContentListView")
4365@@ -126,14 +119,13 @@
4366
4367 // Tests QTBUG-30632 - asynchronous loader crashes when changing index quickly.
4368 function test_multi_activate() {
4369- var menuCount = indicatorsModel.count;
4370+ var menuCount = root.indicatorsModel.count;
4371 verify(menuCount > 0, "Menu count should be greater than zero");
4372
4373 for (var i = 0; i < 100; i++) {
4374 activate_content(i % menuCount);
4375 compare(menuContent.currentMenuIndex, i%menuCount);
4376 }
4377- wait(100);
4378 }
4379 }
4380 }
4381
4382=== added file 'tests/qmltests/Panel/tst_Panel.qml'
4383--- tests/qmltests/Panel/tst_Panel.qml 1970-01-01 00:00:00 +0000
4384+++ tests/qmltests/Panel/tst_Panel.qml 2014-10-15 16:33:46 +0000
4385@@ -0,0 +1,297 @@
4386+/*
4387+ * Copyright 2013-2014 Canonical Ltd.
4388+ *
4389+ * This program is free software; you can redistribute it and/or modify
4390+ * it under the terms of the GNU General Public License as published by
4391+ * the Free Software Foundation; version 3.
4392+ *
4393+ * This program is distributed in the hope that it will be useful,
4394+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4395+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4396+ * GNU General Public License for more details.
4397+ *
4398+ * You should have received a copy of the GNU General Public License
4399+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4400+ */
4401+
4402+import QtQuick 2.1
4403+import QtQuick.Layouts 1.1
4404+import QtTest 1.0
4405+import Unity.Test 0.1 as UT
4406+import Ubuntu.Components 0.1
4407+import Unity.Indicators 0.1 as Indicators
4408+import Ubuntu.Telephony 0.1 as Telephony
4409+import "../../../qml/Panel"
4410+
4411+IndicatorTest {
4412+ id: root
4413+ width: units.gu(100)
4414+ height: units.gu(71)
4415+ color: "white"
4416+
4417+ property string indicatorProfile: "phone"
4418+
4419+ RowLayout {
4420+ anchors.fill: parent
4421+ anchors.margins: units.gu(1)
4422+ clip: true
4423+
4424+ Rectangle {
4425+ Layout.fillWidth: true
4426+ Layout.fillHeight: true
4427+
4428+ id: itemArea
4429+ color: "blue"
4430+
4431+ Panel {
4432+ id: panel
4433+ anchors.fill: parent
4434+ indicators {
4435+ width: parent.width > units.gu(60) ? units.gu(40) : parent.width
4436+ indicatorsModel: root.indicatorsModel
4437+ }
4438+
4439+ property real panelAndSeparatorHeight: panel.indicators.minimizedPanelHeight + units.dp(2)
4440+ }
4441+ }
4442+
4443+ ColumnLayout {
4444+ Layout.alignment: Qt.AlignTop
4445+ Layout.fillWidth: false
4446+
4447+ Button {
4448+ Layout.fillWidth: true
4449+ text: panel.indicators.shown ? "Hide" : "Show"
4450+ onClicked: {
4451+ if (panel.indicators.shown) {
4452+ panel.indicators.hide();
4453+ } else {
4454+ panel.indicators.show();
4455+ }
4456+ }
4457+ }
4458+
4459+ Button {
4460+ text: panel.fullscreenMode ? "Maximize" : "FullScreen"
4461+ Layout.fillWidth: true
4462+ onClicked: panel.fullscreenMode = !panel.fullscreenMode
4463+ }
4464+
4465+ Button {
4466+ Layout.fillWidth: true
4467+ text: callManager.hasCalls ? "Called" : "No Calls"
4468+ onClicked: {
4469+ if (callManager.foregroundCall) {
4470+ callManager.foregroundCall = null;
4471+ } else {
4472+ callManager.foregroundCall = phoneCall;
4473+ }
4474+ }
4475+ }
4476+
4477+ Rectangle {
4478+ Layout.preferredHeight: units.dp(1);
4479+ Layout.fillWidth: true;
4480+ color: "black"
4481+ }
4482+
4483+ Repeater {
4484+ model: indicatorsModel.originalModelData
4485+ RowLayout {
4486+ CheckBox {
4487+ checked: true
4488+ onCheckedChanged: checked ? insertIndicator(index) : removeIndicator(index);
4489+ }
4490+ Label { text: modelData["identifier"] }
4491+ }
4492+ }
4493+ }
4494+ }
4495+
4496+ Telephony.CallEntry {
4497+ id: phoneCall
4498+ phoneNumber: "+447812221111"
4499+ }
4500+
4501+ UT.UnityTestCase {
4502+ name: "Panel"
4503+ when: windowShown
4504+
4505+ function init() {
4506+ panel.fullscreenMode = false;
4507+ callManager.foregroundCall = null;
4508+
4509+ panel.indicators.hide();
4510+ // Wait for animation to complete
4511+ tryCompare(panel.indicators.hideAnimation, "running", false);
4512+
4513+ // Wait for the indicators to get into position.
4514+ // (switches between normal and fullscreen modes are animated)
4515+ var indicatorArea = findChild(panel, "indicatorArea");
4516+ tryCompare(indicatorArea, "y", 0);
4517+ }
4518+
4519+ function get_indicator_item(index) {
4520+ var indicatorItem = findChild(panel, indicatorsModel.originalModelData[index]["identifier"]+"-panelItem");
4521+ verify(indicatorItem !== null);
4522+
4523+ return indicatorItem;
4524+ }
4525+
4526+ function test_drag_show_data() {
4527+ return [
4528+ { tag: "pinned", fullscreen: false, call: null,
4529+ indicatorY: 0 },
4530+ { tag: "fullscreen", fullscreen: true, call: null,
4531+ indicatorY: -panel.panelAndSeparatorHeight },
4532+ { tag: "pinned-callActive", fullscreen: false, call: phoneCall,
4533+ indicatorY: 0},
4534+ { tag: "fullscreen-callActive", fullscreen: true, call: phoneCall,
4535+ indicatorY: -panel.panelAndSeparatorHeight }
4536+ ];
4537+ }
4538+
4539+ // Dragging from a indicator item in the panel will gradually expose the
4540+ // indicators, first by running the hint animation, then after dragging down will
4541+ // expose more of the panel, binding it to the selected indicator and opening it's menu.
4542+ // Tested from first Y pixel to check for swipe from offscreen.
4543+ function test_drag_show(data) {
4544+ panel.fullscreenMode = data.fullscreen;
4545+ callManager.foregroundCall = data.call;
4546+
4547+ var indicatorRow = findChild(panel.indicators, "indicatorItemRow");
4548+ verify(indicatorRow !== null);
4549+
4550+ var menuContent = findChild(panel.indicators, "menuContent");
4551+ verify(menuContent !== null);
4552+
4553+ var indicatorArea = findChild(panel, "indicatorArea");
4554+ verify(indicatorArea !== null);
4555+
4556+ // Wait for the indicators to get into position.
4557+ // (switches between normal and fullscreen modes are animated)
4558+ tryCompareFunction(function() { return indicatorArea.y }, data.indicatorY);
4559+
4560+ for (var i = 0; i < indicatorsModel.originalModelData.length; i++) {
4561+ var indicatorItem = get_indicator_item(i);
4562+
4563+ var startXPosition = root.mapFromItem(indicatorItem, indicatorItem.width / 2, 0).x;
4564+ var startYPosition = root.mapFromItem(panel, 0, 0).y;
4565+
4566+ touchFlick(panel,
4567+ startXPosition, startYPosition,
4568+ startXPosition, panel.height,
4569+ true /* beginTouch */, false /* endTouch */, units.gu(5), 15);
4570+
4571+ // Indicators height should follow the drag, and therefore increase accordingly.
4572+ // They should be at least half-way through the screen
4573+ tryCompareFunction(
4574+ function() {return panel.indicators.height >= panel.height * 0.5},
4575+ true);
4576+
4577+ touchRelease(panel, startXPosition, panel.height);
4578+
4579+ compare(indicatorRow.currentItemIndex, i, "Indicator item should be activated at position " + i);
4580+ compare(menuContent.currentMenuIndex, i, "Menu conetent should be activated for item at position " + i);
4581+
4582+ // init for next indicatorItem
4583+ panel.indicators.hide();
4584+ tryCompare(panel.indicators.hideAnimation, "running", false);
4585+ tryCompare(panel.indicators, "state", "initial");
4586+ }
4587+ }
4588+
4589+ function test_drag_hide_data() {
4590+ return [
4591+ { tag: "pinned", fullscreen: false, call: null,
4592+ indicatorY: 0 },
4593+ { tag: "fullscreen", fullscreen: true, call: null,
4594+ indicatorY: -panel.panelAndSeparatorHeight },
4595+ { tag: "pinned-callActive", fullscreen: false, call: phoneCall,
4596+ indicatorY: 0},
4597+ { tag: "fullscreen-callActive", fullscreen: true, call: phoneCall,
4598+ indicatorY: -panel.panelAndSeparatorHeight }
4599+ ];
4600+ }
4601+
4602+ // Dragging the shown indicators up from bottom of panel will hide the indicators
4603+ // Tested from last Y pixel to check for swipe from offscreen.
4604+ function test_drag_hide(data) {
4605+ panel.fullscreenMode = data.fullscreen;
4606+ callManager.foregroundCall = data.call;
4607+
4608+ var indicatorRow = findChild(panel.indicators, "indicatorItemRow");
4609+ verify(indicatorRow !== null);
4610+
4611+ var menuContent = findChild(panel.indicators, "menuContent");
4612+ verify(menuContent !== null);
4613+
4614+ var indicatorArea = findChild(panel, "indicatorArea");
4615+ verify(indicatorArea !== null);
4616+
4617+ // Wait for the indicators to get into position.
4618+ // (switches between normal and fullscreen modes are animated)
4619+ tryCompareFunction(function() { return indicatorArea.y }, data.indicatorY);
4620+
4621+ var startXPosition = root.mapFromItem(panel.indicators, panel.indicators.width / 2, 0).x;
4622+ var startYPosition = root.mapFromItem(panel, 0, panel.height).y;
4623+
4624+ panel.indicators.show();
4625+ tryCompare(panel.indicators.showAnimation, "running", false);
4626+ tryCompare(panel.indicators, "unitProgress", 1);
4627+
4628+
4629+ touchFlick(panel.indicators,
4630+ startXPosition, startYPosition,
4631+ startXPosition, 0,
4632+ true /* beginTouch */, false /* endTouch */, units.gu(5), 15);
4633+
4634+ // Indicators height should follow the drag, and therefore increase accordingly.
4635+ // They should be at least half-way through the screen
4636+ tryCompareFunction(
4637+ function() {return panel.indicators.height <= panel.height * 0.5},
4638+ true);
4639+
4640+ touchRelease(panel.indicators, startXPosition, 0);
4641+
4642+ tryCompare(panel.indicators.hideAnimation, "running", true);
4643+ tryCompare(panel.indicators.hideAnimation, "running", false);
4644+ tryCompare(panel.indicators, "state", "initial");
4645+ }
4646+
4647+ function test_hint_data() {
4648+ return [
4649+ { tag: "normal", fullscreen: false, call: null, hintExpected: true},
4650+ { tag: "fullscreen", fullscreen: true, call: null, hintExpected: false},
4651+ { tag: "call hint", fullscreen: false, call: phoneCall, hintExpected: false},
4652+ ];
4653+ }
4654+
4655+ function test_hint(data) {
4656+ panel.fullscreenMode = data.fullscreen;
4657+ callManager.foregroundCall = data.call;
4658+
4659+ if (data.fullscreen) {
4660+ // Wait for the indicators to get into position.
4661+ // (switches between normal and fullscreen modes are animated)
4662+ var indicatorArea = findChild(panel, "indicatorArea");
4663+ tryCompare(indicatorArea, "y", -panel.panelHeight);
4664+ }
4665+
4666+ var indicatorItem = get_indicator_item(0);
4667+ var mappedPosition = root.mapFromItem(indicatorItem, indicatorItem.width / 2, indicatorItem.height / 2);
4668+
4669+ touchPress(panel, mappedPosition.x, panel.indicators.minimizedPanelHeight / 2);
4670+
4671+ // Give some time for a hint animation to change things, if any
4672+ wait(500);
4673+
4674+ // no hint animation when fullscreen
4675+ compare(panel.indicators.fullyClosed, !data.hintExpected, "Indicator should be fully closed");
4676+ compare(panel.indicators.partiallyOpened, data.hintExpected, "Indicator should be partialy opened");
4677+ compare(panel.indicators.fullyOpened, false, "Indicator should not be fully opened");
4678+
4679+ touchRelease(panel, mappedPosition.x, panel.minimizedPanelHeight / 2);
4680+ }
4681+ }
4682+}
4683
4684=== removed file 'tests/qmltests/Panel/tst_Panel.qml'
4685--- tests/qmltests/Panel/tst_Panel.qml 2014-07-10 13:36:41 +0000
4686+++ tests/qmltests/Panel/tst_Panel.qml 1970-01-01 00:00:00 +0000
4687@@ -1,337 +0,0 @@
4688-/*
4689- * Copyright 2013 Canonical Ltd.
4690- *
4691- * This program is free software; you can redistribute it and/or modify
4692- * it under the terms of the GNU General Public License as published by
4693- * the Free Software Foundation; version 3.
4694- *
4695- * This program is distributed in the hope that it will be useful,
4696- * but WITHOUT ANY WARRANTY; without even the implied warranty of
4697- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4698- * GNU General Public License for more details.
4699- *
4700- * You should have received a copy of the GNU General Public License
4701- * along with this program. If not, see <http://www.gnu.org/licenses/>.
4702- */
4703-
4704-import QtQuick 2.0
4705-import QtTest 1.0
4706-import Unity.Test 0.1 as UT
4707-import Ubuntu.Components 0.1 as UC
4708-import Ubuntu.Telephony 0.1 as Telephony
4709-import ".."
4710-import "../../../qml/Panel"
4711-
4712-/*
4713- This tests the Panel component using a fake model to stage data in the indicators
4714- A view will show with indicators at the top, as does in the shell. This can be controlled
4715- as in the shell.
4716-*/
4717-Item {
4718- id: shell
4719- width: units.gu(40)
4720- height: units.gu(80)
4721-
4722- Panel {
4723- id: panel
4724- anchors {
4725- left: parent.left
4726- right: parent.right
4727- }
4728- height: parent.height - row.height
4729- fullscreenMode: false
4730-
4731- indicators {
4732- profile: "test1"
4733- panelHeight: units.gu(5)
4734- }
4735- callHint {
4736- height: units.gu(4)
4737- }
4738-
4739- property real panelAndSeparatorHeight: panel.indicators.panelHeight + units.dp(2)
4740- }
4741-
4742-
4743- Row {
4744- id: row
4745- anchors {
4746- bottom: shell.bottom
4747- left: parent.left
4748- right: parent.right
4749- }
4750- height: 50
4751-
4752- UC.Button {
4753- text: panel.indicators.shown ? "Hide" : "Show"
4754- anchors {
4755- top: parent.top
4756- bottom: parent.bottom
4757- }
4758- width: parent.width/3
4759-
4760- onClicked: {
4761- if (panel.indicators.shown) {
4762- panel.indicators.hide();
4763- } else {
4764- panel.indicators.show();
4765- }
4766- }
4767- }
4768-
4769- UC.Button {
4770- text: panel.fullscreenMode ? "Maximize" : "FullScreen"
4771- anchors {
4772- top: parent.top
4773- bottom: parent.bottom
4774- }
4775- width: parent.width/3
4776-
4777- onClicked: panel.fullscreenMode = !panel.fullscreenMode
4778- }
4779-
4780- UC.Button {
4781- text: callManager.hasCalls ? "Called" : "No Calls"
4782- anchors {
4783- top: parent.top
4784- bottom: parent.bottom
4785- }
4786- width: parent.width/3
4787-
4788- onClicked: {
4789- if (callManager.foregroundCall) {
4790- callManager.foregroundCall = null;
4791- } else {
4792- callManager.foregroundCall = phoneCall;
4793- }
4794- }
4795- }
4796- }
4797-
4798- Telephony.CallEntry {
4799- id: phoneCall
4800- phoneNumber: "+447812221111"
4801- }
4802-
4803- UT.UnityTestCase {
4804- name: "Panel"
4805- when: windowShown
4806-
4807- function init() {
4808- panel.indicators.initialise();
4809- panel.fullscreenMode = false;
4810-
4811- panel.indicators.hide();
4812- // Wait for animation to complete
4813- tryCompare(panel.indicators.hideAnimation, "running", false);
4814- callManager.foregroundCall = null;
4815-
4816- // Wait for the indicators to get into position.
4817- // (switches between normal and fullscreen modes are animated)
4818- var indicatorArea = findChild(panel, "indicatorArea");
4819- tryCompare(indicatorArea, "y", 0);
4820- }
4821-
4822- function get_indicator_item(index) {
4823- var indicatorRow = findChild(panel.indicators, "indicatorRow");
4824- verify(indicatorRow !== null);
4825-
4826- return findChild(indicatorRow.row, "item" + index);
4827- }
4828-
4829- function get_indicator_item_position(index) {
4830- var indicatorRow = findChild(panel.indicators, "indicatorRow");
4831- verify(indicatorRow !== null);
4832-
4833- var indicatorItem = get_indicator_item(index);
4834- verify(indicatorItem !== null);
4835-
4836- return panel.mapFromItem(indicatorItem, indicatorItem.width/2, indicatorItem.height/2);
4837- }
4838-
4839- // Pressing on the indicator panel should activate the indicator hints
4840- // and expose a portion of the conent.
4841- function test_hint() {
4842- var indicatorItemCoord = get_indicator_item_position(0);
4843-
4844- touchPress(panel, indicatorItemCoord.x, panel.indicators.panelHeight / 2);
4845-
4846- // hint animation should be run, meaning that indicators will move downwards
4847- // by hintValue pixels without any drag taking place
4848- tryCompareFunction(function() { return panel.indicators.height },
4849- panel.indicators.panelHeight + panel.indicators.hintValue);
4850- tryCompare(panel.indicators, "partiallyOpened", true);
4851- tryCompare(panel.indicators, "fullyOpened", false);
4852-
4853- touchRelease(panel, indicatorItemCoord.x, panel.indicators.panelHeight/2);
4854- }
4855-
4856- // Pressing on the top edge of the screen should have no effect if the panel
4857- // is hidden (fullscreen), which is the case when a fullscreen app is being shown
4858- function test_noHintOnFullscreenMode() {
4859- panel.fullscreenMode = true;
4860- // Wait for the indicators to get into position.
4861- // (switches between normal and fullscreen modes are animated)
4862- var indicatorArea = findChild(panel, "indicatorArea");
4863- tryCompare(indicatorArea, "y", -panel.panelHeight);
4864-
4865- var indicatorItemCoord = get_indicator_item_position(0);
4866-
4867- touchPress(panel, indicatorItemCoord.x, panel.indicators.panelHeight / 2);
4868-
4869- // Give some time for a hint animation to change things, if any
4870- wait(500);
4871-
4872- // no hint animation when fullscreen
4873- compare(panel.indicators.partiallyOpened, false,
4874- "Indicator should not be partially opened when panel is pressed in" +
4875- " fullscreenmode");
4876- compare(panel.indicators.fullyOpened, false, "Indicator should not be partially" +
4877- " opened when panel is pressed in fullscreenmode");
4878-
4879- touchRelease(panel, indicatorItemCoord.x, panel.panelHeight/2);
4880- }
4881-
4882- // Pressing on the top edge of the indicator should have no effect if the panel
4883- // has an active call
4884- function test_noHintOnActiveCall() {
4885- callManager.foregroundCall = phoneCall;
4886-
4887- var indicatorItemCoord = get_indicator_item_position(0);
4888-
4889- touchPress(panel, indicatorItemCoord.x, panel.callHint.height + panel.indicators.panelHeight / 2);
4890-
4891- // Give some time for a hint animation to change things, if any
4892- wait(500);
4893-
4894- // no hint animation when fullscreen
4895- compare(panel.indicators.partiallyOpened, false,
4896- "Indicator should not be partially opened when panel is pressed in" +
4897- " fullscreenmode");
4898- compare(panel.indicators.fullyOpened, false, "Indicator should not be partially" +
4899- " opened when panel is pressed in fullscreenmode");
4900-
4901- touchRelease(panel, indicatorItemCoord.x, panel.panelHeight/2);
4902- }
4903-
4904- function test_drag_show_data() {
4905- return [
4906- { tag: "pinned", fullscreenFlag: false, alreadyOpen: false, call: null,
4907- indicatorY: 0 },
4908- { tag: "fullscreen", fullscreenFlag: true, alreadyOpen: false, call: null,
4909- indicatorY: -panel.panelAndSeparatorHeight },
4910- { tag: "pinned-alreadyOpen", fullscreenFlag: false, alreadyOpen: true, call: null,
4911- indicatorY: 0 },
4912- { tag: "fullscreen-alreadyOpen", fullscreenFlag: true, alreadyOpen: true, call: null,
4913- indicatorY: 0 },
4914- { tag: "pinned-callActive", fullscreenFlag: false, alreadyOpen: false, call: phoneCall,
4915- indicatorY: 0},
4916- { tag: "fullscreen-callActive", fullscreenFlag: true, alreadyOpen: false, call: phoneCall,
4917- indicatorY: -panel.panelAndSeparatorHeight }
4918- ];
4919- }
4920-
4921- // Dragging from a indicator item in the panel will gradually expose the
4922- // indicators, first by running the hint animation, then after dragging down will
4923- // expose more of the panel, binding it to the selected indicator and opening it's menu.
4924- function test_drag_show(data) {
4925- panel.fullscreenMode = data.fullscreenFlag;
4926- callManager.foregroundCall = data.call;
4927-
4928- if (data.alreadyOpen) {
4929- panel.indicators.show();
4930- tryCompare(panel.indicators, "fullyOpened", true);
4931- }
4932-
4933- var indicatorRow = findChild(panel.indicators, "indicatorRow");
4934- verify(indicatorRow !== null);
4935-
4936- var menuContent = findChild(panel.indicators, "menuContent");
4937- verify(menuContent !== null);
4938-
4939- var indicatorArea = findChild(panel, "indicatorArea");
4940- verify(indicatorArea !== null);
4941-
4942- // Wait for the indicators to get into position.
4943- // (switches between normal and fullscreen modes are animated)
4944- tryCompareFunction(function() { return indicatorArea.y }, data.indicatorY);
4945-
4946- // do this for each indicator item
4947- for (var i = 0; i < indicatorRow.row.count; i++) {
4948-
4949- var indicatorItem = get_indicator_item(i);
4950- verify(indicatorItem !== null);
4951-
4952- if (!indicatorItem.visible)
4953- continue;
4954-
4955- var indicatorItemCoord = get_indicator_item_position(i);
4956-
4957- touchPress(panel,
4958- indicatorItemCoord.x, panel.indicators.panelHeight / 2);
4959-
4960- // 1) Drag the mouse down
4961- touchFlick(panel,
4962- indicatorItemCoord.x, panel.indicators.panelHeight / 2,
4963- indicatorItemCoord.x, panel.height,
4964- false /* beginTouch */, false /* endTouch */);
4965-
4966- // Indicators height should follow the drag, and therefore increase accordingly.
4967- // They should be at least half-way through the screen
4968- tryCompareFunction(
4969- function() {return panel.indicators.height >= panel.height * 0.5},
4970- true);
4971-
4972- touchRelease(panel, indicatorItemCoord.x, panel.height);
4973-
4974- compare(indicatorRow.currentItem, indicatorItem,
4975- "Incorrect item activated at position " + i);
4976- compare(menuContent.currentMenuIndex, i, "Menu conetent should be enabled for item at position " + i);
4977-
4978- // init for next indicatorItem
4979- if (!data.alreadyOpen) {
4980- panel.indicators.hide();
4981- tryCompare(panel.indicators.hideAnimation, "running", false);
4982- tryCompare(panel.indicators, "state", "initial");
4983- }
4984- }
4985- }
4986-
4987- // Test the vertical velocity check when flicking the indicators open at an angle.
4988- // If the vertical velocity is above a specific point, we shouldnt change active indicators
4989- // if the x position changes
4990- function test_vertical_velocity_detector() {
4991- panel.fullscreenMode = false;
4992-
4993- var indicatorRow = findChild(panel.indicators, "indicatorRow");
4994- verify(indicatorRow !== null);
4995-
4996- // Get the first indicator
4997- var indicatorItemFirst = get_indicator_item(0);
4998- verify(indicatorItemFirst !== null);
4999-
5000- var indicatorItemCoordFirst = get_indicator_item_position(0);
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: