on xenial help sign in
Merge Trunk.
commit9d197a1088c94564c865500c1ba53e5e5286a75b authorChristopher Lee <chris.lee@canonical.com> dateMon 22 Jul 2013, 14:35 (13 years ago) parentd28e0176bc361d
45 files changed+1214−953
ApplicationArguments.h+49 CMakeLists.txt+1 Components/Carousel.qml+38−1 Dash/Dash.qml−3 Dash/DashContent.qml−2 Dash/Generic/GenericCarousel.qml+58 Dash/Generic/GenericFilterGrid.qml+59 Panel/Menus/IndicatorMenuWindow.qml → Dash/Generic/GenericFilterGridPotrait.qml+9−14 Dash/GenericScopeView.qml+46−41 Notifications/Notification.qml+4−3 Notifications/Notifications.qml+1 Panel/IndicatorRow.qml+1−2 Panel/Indicators.qml+22−44 Panel/MenuContent.qml+20−69 Panel/Menus/Overview.qml−70 Panel/Menus/Overview/FlightModeWidget.qml−60 Panel/Menus/Overview/OverviewGrid.qml−135 Panel/Menus/Overview/VolumeWidget.qml−88 Panel/Menus/Overview/graphics/plane_icon@18.png Panel/Menus/Overview/graphics/sound_off_icon@18.png Panel/Menus/Overview/graphics/sound_on_icon@18.png Shell.qml+2−2 debian/changelog+19 main.cpp+4−6 plugins/ListViewWithPageHeader/listviewwithpageheader.cpp+1−1 plugins/Unity/Indicators/CMakeLists.txt+1 plugins/Unity/Indicators/menucontentactivator.cpp+345 plugins/Unity/Indicators/menucontentactivator.h+117 plugins/Unity/Indicators/plugin.cpp+3 plugins/Unity/Indicators/qml/IndicatorPage.qml−6 run_on_device+3−19 tests/mocks/Unity/Indicators/CMakeLists.txt+1 tests/mocks/Unity/Indicators/fakeplugin.cpp+4 tests/plugins/ListViewWithPageHeader/listviewwithpageheadertest.cpp+19 tests/plugins/ListViewWithPageHeader/listviewwithpageheadertestsection.cpp+19 tests/plugins/Unity/Indicators/CMakeLists.txt+1 tests/plugins/Unity/Indicators/menucontentactivatortest.cpp+303 tests/qmltests/CMakeLists.txt−2 tests/qmltests/Notifications/tst_Notifications.qml+20−9 tests/qmltests/Panel/Menus/tst_IndicatorMenuWindow.qml−68 tests/qmltests/Panel/tst_IndicatorRow.qml−14 tests/qmltests/Panel/tst_Indicators.qml+1−39 tests/qmltests/Panel/tst_MenuContent.qml+10−80 tests/qmltests/Panel/tst_Overview.qml−142 tests/qmltests/Panel/tst_Panel.qml+33−33
ApplicationArguments.hnew file+49
@@ -0,0 +1,49 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
17+ */
18+
19+
20+#ifndef APPLICATION_ARGUMENTS_H
21+#define APPLICATION_ARGUMENTS_H
22+
23+#include <QObject>
24+#include <QSize>
25+#include <QStringList>
26+
27+class ApplicationArguments : public QObject
28+{
29+ Q_OBJECT
30+public:
31+ ApplicationArguments(const QStringList& args) {
32+ if (args.contains(QLatin1String("-geometry")) && args.size() > args.indexOf(QLatin1String("-geometry")) + 1) {
33+ QStringList geometryArg = args.at(args.indexOf(QLatin1String("-geometry")) + 1).split('x');
34+ if (geometryArg.size() == 2) {
35+ m_size.rwidth() = geometryArg.at(0).toInt();
36+ m_size.rheight() = geometryArg.at(1).toInt();
37+ }
38+ }
39+ }
40+
41+ Q_INVOKABLE bool hasGeometry() const { return m_size.isValid(); }
42+ Q_INVOKABLE int width() const { return m_size.width(); }
43+ Q_INVOKABLE int height() const { return m_size.height(); }
44+
45+private:
46+ QSize m_size;
47+};
48+
49+#endif // APPLICATION_ARGUMENTS_H
CMakeLists.txt+1
@@ -101,6 +101,7 @@ set(shell_app_HDRS
101101
102102add_executable(${SHELL_APP}
103103 ${shellapplication_MOC_SRCS}
104+ ApplicationArguments.h
104105 main.cpp
105106 MouseTouchAdaptor.cpp
106107 )
Components/Carousel.qml+38−1
@@ -52,6 +52,12 @@ Item {
5252 /// @param itemY is y of the clicked delegate
5353 signal clicked(int index, var delegateItem, real itemY)
5454
55+ /// Emitted when the user pressed and held on an item
56+ /// @param index is the index of the held item
57+ /// @param delegateItem is the held component/delegate itself
58+ /// @param itemY is y of the held delegate
59+ signal pressAndHold(int index, var delegateItem, real itemY)
60+
5561 implicitHeight: listView.tileHeight * selectedItemScaleFactor
5662
5763 /* Basic idea behind the carousel effect is to move the items of the delegates (compacting /stuffing them).
@@ -159,6 +165,30 @@ Item {
159165 newContentXAnimation.start()
160166 }
161167
168+ function itemPressAndHold(index, delegateItem) {
169+ var x = CarouselJS.getXFromContinuousIndex(index,
170+ realWidth,
171+ realContentWidth,
172+ tileWidth,
173+ gapToMiddlePhase,
174+ gapToEndPhase,
175+ carousel.drawBuffer);
176+
177+ if (Math.abs(x - contentX) < 1) {
178+ /* We're pressAndHold the selected item and
179+ we're in the neighbourhood of radius 1 pixel from it.
180+ Let's emit the pressAndHold signal. */
181+ carousel.pressAndHold(index, delegateItem, delegateItem.y);
182+ return;
183+ }
184+
185+ stepAnimation.stop();
186+ newContentXAnimation.stop();
187+
188+ newContentX = x;
189+ newContentXAnimation.start();
190+ }
191+
162192 onMovementStarted: {
163193 stepAnimation.stop()
164194 newContentXAnimation.stop()
@@ -279,7 +309,14 @@ Item {
279309
280310 anchors.fill: parent
281311
282− onClicked: listView.itemClicked(index, item)
312+ onClicked: {
313+ listView.itemClicked(index, item)
314+ }
315+
316+ onPressAndHold: {
317+ listView.itemPressAndHold(index, item)
318+ }
319+
283320 }
284321 }
285322 }
Dash/Dash.qml−3
@@ -27,9 +27,6 @@ Showable {
2727 property string showScopeOnLoaded: "home.scope"
2828 property real contentScale: 1.0
2929
30− width: units.gu(40)
31− height: units.gu(71)
32−
3330 function setCurrentScope(scopeId, animate, reset) {
3431 var scopeIndex = filteredScopes.findFirst(Scopes.RoleId, scopeId)
3532
Dash/DashContent.qml−2
@@ -20,8 +20,6 @@ import Unity 0.1
2020
2121Item {
2222 id: dashContent
23− width: units.gu(40)
24− height: units.gu(71)
2523
2624 property var model: null
2725 property var scopes: null
Dash/Generic/GenericCarousel.qmlnew file+58
@@ -0,0 +1,58 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import Ubuntu.Components 0.1
19+import "../../Components"
20+import "../../Components/IconUtil.js" as IconUtil
21+
22+Carousel {
23+ id: genericCarousel
24+
25+ tileAspectRatio: 198 / 288
26+ minimumTileWidth: units.gu(13)
27+ itemComponent: carouselDelegateGeneric
28+ selectedItemScaleFactor: 1.14
29+ cacheBuffer: 1404 // 18px * 13gu * 6
30+ height: implicitHeight + units.gu(6)
31+
32+ Component {
33+ id: carouselDelegateGeneric
34+
35+ BaseCarouselDelegate {
36+ id: item
37+
38+ UbuntuShape {
39+ anchors.fill: parent
40+ radius: "medium"
41+ borderSource: ""
42+ image: Image {
43+ asynchronous: true
44+ sourceSize { width: item.width; height: item.height }
45+ source: model ? IconUtil.from_gicon(model.icon) : ""
46+ }
47+ }
48+
49+ BorderImage {
50+ anchors.centerIn: parent
51+ opacity: 0.6
52+ source: "../../Components/graphics/non-selected.sci"
53+ width: parent.width + units.gu(1.5)
54+ height: parent.height + units.gu(1.5)
55+ }
56+ }
57+ }
58+}
Dash/Generic/GenericFilterGrid.qmlnew file+59
@@ -0,0 +1,59 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import "../../Components"
19+import "../../Components/IconUtil.js" as IconUtil
20+
21+FilterGrid {
22+ id: filtergrid
23+
24+ filter: false
25+ minimumHorizontalSpacing: units.gu(0.5)
26+ delegateWidth: units.gu(11)
27+ delegateHeight: units.gu(9.5)
28+ verticalSpacing: units.gu(2)
29+
30+ property int iconWidth: units.gu(8)
31+ property int iconHeight: units.gu(7.5)
32+
33+ signal clicked(int index, var delegateItem, real itemY)
34+ signal pressAndHold(int index, var delegateItem, real itemY)
35+
36+ delegate: Tile {
37+ id: tile
38+ objectName: "delegate" + index
39+ width: filtergrid.cellWidth
40+ height: filtergrid.cellHeight
41+ text: model.title
42+ imageWidth: filtergrid.iconWidth
43+ imageHeight: filtergrid.iconHeight
44+
45+ source: IconUtil.from_gicon(model.icon)
46+
47+ fillMode: Image.PreserveAspectCrop
48+
49+ onClicked: {
50+ var data = { model: model }
51+ filtergrid.clicked(index, data, tile.y)
52+ }
53+
54+ onPressAndHold: {
55+ var data = { model: model }
56+ filtergrid.pressAndHold(index, data, tile.y)
57+ }
58+ }
59+}
Panel/Menus/IndicatorMenuWindow.qml → Dash/Generic/GenericFilterGridPotrait.qmlrenamed+9−14
@@ -15,21 +15,16 @@
1515 */
1616
1717import QtQuick 2.0
18+import "../../Components"
1819
19−Item {
20− id: menuWindow
20+GenericFilterGrid {
21+ id: filtergrid
2122
22− property bool shown: false
23− property int contentHeight: height
24− property string headingText: name
25− property string name
23+ minimumHorizontalSpacing: units.gu(0.5)
24+ delegateWidth: units.gu(11)
25+ delegateHeight: units.gu(18)
26+ verticalSpacing: units.gu(2)
2627
27− enabled: shown
28− opacity: shown ? 1.0 : 0.0
29− Behavior on opacity { NumberAnimation {duration: shown ? 300 : 150 } }
30−
31− // don't pass any events under this screen
32− MouseArea {
33− anchors.fill: parent
34− }
28+ iconWidth: (width / columns) * 0.8
29+ iconHeight: iconWidth * 16 / 11
3530}
Dash/GenericScopeView.qml+46−41
@@ -56,53 +56,45 @@ ScopeView {
5656 delegate: ListItems.Base {
5757 highlightWhenPressed: false
5858
59− FilterGrid {
60− id: filtergrid
61− model: results
62−
59+ Loader {
60+ id: rendererLoader
6361 anchors {
6462 top: parent.top
6563 left: parent.left
6664 right: parent.right
6765 }
6866
69− filter: false
70− minimumHorizontalSpacing: units.gu(0.5)
71− delegateWidth: units.gu(11)
72− delegateHeight: units.gu(18)
73− verticalSpacing: units.gu(2)
74−
75− delegate: Tile {
76− width: filtergrid.cellWidth
77− height: filtergrid.cellHeight
78− text: title
79− imageWidth: units.gu(11)
80− imageHeight: units.gu(16)
81−
82− source: IconUtil.from_gicon(icon)
83−
84− MouseArea {
85− anchors {
86− fill: parent
87− }
88− onClicked: {
89− mouse.accepted = true
90− effect.positionPx = mapToItem(categoryView, 0, 0).y
91− scopeView.scope.activate(uri, icon,
92− category, 0,
93− mimetype, title,
94− comment, dndUri,
95− metadata)
96− }
97− onPressAndHold: {
98− mouse.accepted = true
99− effect.positionPx = mapToItem(categoryView, 0, 0).y
100− scopeView.scope.preview(uri, icon,
101− category, 0,
102− mimetype, title,
103− comment, dndUri,
104− metadata)
105− }
67+ source: getRenderer(model.renderer, model.contentType)
68+
69+ onLoaded: {
70+ item.model = results
71+ }
72+
73+ Connections {
74+ target: rendererLoader.item
75+ onClicked: {
76+ effect.positionPx = mapToItem(categoryView, 0, itemY).y
77+ scopeView.scope.activate(delegateItem.model.uri,
78+ delegateItem.model.icon,
79+ delegateItem.model.category,
80+ 0,
81+ delegateItem.model.mimetype,
82+ delegateItem.model.title,
83+ delegateItem.model.comment,
84+ delegateItem.model.dndUri,
85+ delegateItem.model.metadata)
86+ }
87+ onPressAndHold: {
88+ effect.positionPx = mapToItem(categoryView, 0, itemY).y
89+ scopeView.scope.preview( delegateItem.model.uri,
90+ delegateItem.model.icon,
91+ delegateItem.model.category,
92+ 0,
93+ delegateItem.model.mimetype,
94+ delegateItem.model.title,
95+ delegateItem.model.comment,
96+ delegateItem.model.dndUri,
97+ delegateItem.model.metadata)
10698 }
10799 }
108100 }
@@ -122,6 +114,19 @@ ScopeView {
122114 }
123115 }
124116
117+ function getRenderer(rendererId, contentType) {
118+ switch (rendererId) {
119+ case "grid": {
120+ switch (contentType) {
121+ case "video": return "Generic/GenericFilterGridPotrait.qml";
122+ default: return "Generic/GenericFilterGrid.qml";
123+ }
124+ }
125+ case "carousel": return "Generic/GenericCarousel.qml";
126+ default: return "Generic/GenericFilterGrid.qml";
127+ }
128+ }
129+
125130 OpenEffect {
126131 id: effect
127132 anchors {
Notifications/Notification.qml+4−3
@@ -28,6 +28,7 @@ UbuntuShape {
2828 property var actions
2929 property var notificationId
3030 property var type
31+ property var hints
3132 property var notification
3233
3334 objectName: "background"
@@ -164,7 +165,7 @@ UbuntuShape {
164165 bottom: parent.bottom
165166 }
166167 text: notification.type == Notification.SnapDecision && actionRepeater.count >= 2 ? actionRepeater.itemAt(1).actionLabel : ""
167− color: "#cdcdcb"
168+ gradient: UbuntuColors.greyGradient
168169 onClicked: {
169170 if (actionRepeater.count > 2) {
170171 buttonRow.expanded = !buttonRow.expanded
@@ -194,7 +195,7 @@ UbuntuShape {
194195 top: parent.top
195196 bottom: parent.bottom
196197 }
197− color: "#d85317" // FIXME ??
198+ gradient: notification.hints == Notification.ButtonTint ? UbuntuColors.orangeGradient : UbuntuColors.greyGradient
198199 visible: width > 0
199200 onClicked: notification.notification.invokeAction(actionRepeater.itemAt(0).actionId)
200201 }
@@ -241,7 +242,7 @@ UbuntuShape {
241242
242243 text: loader.actionLabel
243244 height: units.gu(4)
244− color: "#cdcdcb" // FIXME ?? which color?
245+ gradient: UbuntuColors.greyGradient
245246 onClicked: notification.notification.invokeAction(loader.actionId)
246247 }
247248 }
Notifications/Notifications.qml+1
@@ -32,6 +32,7 @@ ListView {
3232 right: parent.right
3333 }
3434 type: model.type
35+ hints: model.hints
3536 iconSource: model.icon
3637 secondaryIconSource: model.secondaryIcon
3738 summary: model.summary
Panel/IndicatorRow.qml+1−2
@@ -24,7 +24,6 @@ Item {
2424 readonly property int currentItemIndex: currentItem ? currentItem.ownIndex : -1
2525 property alias row: row
2626 property QtObject indicatorsModel: null
27− property bool overviewActive: false // "state of the menu"
2827
2928 Behavior on y {NumberAnimation {duration: 300; easing.type: Easing.OutCubic} }
3029
@@ -76,7 +75,7 @@ Item {
7675 height: indicatorRow.height
7776 y: {
7877 //FIXME: all indicators will be initial for now.
79− if (!highlighted && !overviewActive && (indicatorRow.state == "locked" || indicatorRow.state == "commit")) {
78+ if (!highlighted && (indicatorRow.state == "locked" || indicatorRow.state == "commit")) {
8079 return -indicatorRow.height
8180 } else {
8281 return 0
Panel/Indicators.qml+22−44
@@ -56,36 +56,22 @@ Showable {
5656
5757 onHeightChanged: {
5858 // need to use handle.get_height(). As the handle height depends on indicators.height changes (but this is called first!)
59− var contentProgress = indicators.height - handle.get_height()
59+ var contentProgress = indicators.height - handle.get_height();
6060 if (!showAnimation.running && !hideAnimation.running) {
6161 if (contentProgress <= hintValue && indicators.state == "reveal") {
62− indicators.state = "hint"
63− menuContent.hideAll()
62+ indicators.state = "hint";
6463 } else if (contentProgress > hintValue && contentProgress < lockThreshold) {
65− menuContent.showMenu()
66− indicators.state = "reveal"
64+ indicators.state = "reveal";
6765 } else if (contentProgress >= lockThreshold && lockThreshold > 0) {
68− // If we've shown the overview and are closing the view with progress changes (revealer handle),
69− // we dont want to switch to a indicator menu until we hit reveal state.
70− if (menuContent.overviewActive) {
71− menuContent.showOverview()
72− } else {
73− menuContent.showMenu()
74− }
75− indicators.state = "locked"
66+ indicators.state = "locked";
7667 }
7768 }
7869
7970 if (contentProgress == 0) {
80− menuContent.releaseContent()
71+ menuContent.releaseContent();
8172 }
8273 }
8374
84− function openOverview() {
85− indicatorRow.currentItem = null
86− menuContent.showOverview()
87− }
88−
8975 function calculateCurrentItem(xValue, useBuffer) {
9076 var rowCoordinates
9177 var itemCoordinates
@@ -93,7 +79,7 @@ Showable {
9379 var distanceFromRightEdge
9480 var bufferExceeded = false
9581
96− if (indicators.state == "commit" || indicators.state == "locked" || showAnimation.running || hideAnimation.running) return
82+ if (indicators.state == "commit" || indicators.state == "locked" || showAnimation.running || hideAnimation.running) return;
9783
9884 /*
9985 If user drags the indicator handle bar down a distance hintValue or less, this is 0.
@@ -102,14 +88,14 @@ Showable {
10288 */
10389 var verticalProgress =
10490 MathLocal.clamp((indicators.height - handle.height - hintValue) /
105− (lockThreshold - hintValue), 0, 1)
91+ (lockThreshold - hintValue), 0, 1);
10692
10793 /*
10894 Percentage of an indicator icon's width the user's press can stray horizontally from the
10995 focused icon before we change focus to another icon. E.g. a value of 0.5 means you must
11096 go right a distance of half an icon's width before focus moves to the icon on the right
11197 */
112− var maxBufferThreshold = 0.5
98+ var maxBufferThreshold = 0.5;
11399
114100 /*
115101 To help users find the indicator of their choice while opening the indicators, we add logic to add a
@@ -126,12 +112,12 @@ Showable {
126112 itemCoordinates = indicatorRow.row.mapToItem(currentItem, rowCoordinates.x, 0);
127113 distanceFromRightEdge = (currentItem.width - itemCoordinates.x) / (currentItem.width)
128114 if (Math.abs(currentItem.ownIndex - indicatorRow.currentItemIndex) > 1) {
129− bufferExceeded = true
115+ bufferExceeded = true;
130116 } else {
131117 if (indicatorRow.currentItemIndex < currentItem.ownIndex && distanceFromRightEdge < (1 - effectiveBufferThreshold)) {
132− bufferExceeded = true
118+ bufferExceeded = true;
133119 } else if (indicatorRow.currentItemIndex > currentItem.ownIndex && distanceFromRightEdge > effectiveBufferThreshold) {
134− bufferExceeded = true
120+ bufferExceeded = true;
135121 }
136122 }
137123 if ((!useBuffer || (useBuffer && bufferExceeded)) || indicatorRow.currentItem < 0 || indicatorRow.currentItem == null) {
@@ -172,8 +158,7 @@ Showable {
172158 bottom: parent.bottom
173159 }
174160 indicatorsModel: indicatorsModel
175− animate: false
176− clip: indicators.partiallyOpened
161+ clip: !indicators.fullyOpened
177162
178163 onMenuSelected: {
179164 indicatorRow.setItem(index)
@@ -209,7 +194,7 @@ Showable {
209194 clip: height < handleImage.height
210195
211196 function get_height() {
212− return Math.max(Math.min(handleImage.height, indicators.height - handleImage.height), 0)
197+ return Math.max(Math.min(handleImage.height, indicators.height - handleImage.height), 0);
213198 }
214199
215200 BorderImage {
@@ -264,7 +249,6 @@ Showable {
264249 height: indicators.panelHeight
265250 indicatorsModel: indicatorsModel
266251 state: indicators.state
267− overviewActive: menuContent.overviewActive
268252
269253 onCurrentItemIndexChanged: menuContent.currentIndex = currentItemIndex
270254
@@ -279,9 +263,11 @@ Showable {
279263 onRunningChanged: {
280264 if (hideAnimation.running) {
281265 indicators.state = "initial"
282− menuContent.hideAll()
283266 } else {
284− if (state == "initial") indicatorRow.setDefaultItem()
267+ if (state == "initial") {
268+ indicatorRow.setDefaultItem();
269+ menuContent.releaseContent();
270+ }
285271 }
286272 }
287273 }
@@ -289,13 +275,8 @@ Showable {
289275 target: showAnimation
290276 onRunningChanged: {
291277 if (showAnimation.running) {
292− if (indicators.state == "initial") {
293− openOverview()
294− } else {
295− indicators.calculateCurrentItem(dragHandle.touchX, false)
296− menuContent.showMenu()
297− }
298− indicators.state = "commit"
278+ indicators.calculateCurrentItem(dragHandle.touchX, false);
279+ indicators.state = "commit";
299280 }
300281 }
301282 }
@@ -303,8 +284,8 @@ Showable {
303284 Connections {
304285 target: dragHandle
305286 onTouchXChanged: {
306− var buffer = dragHandle.dragging ? true : false
307− indicators.calculateCurrentItem(dragHandle.touchX, buffer)
287+ var buffer = dragHandle.dragging ? true : false;
288+ indicators.calculateCurrentItem(dragHandle.touchX, buffer);
308289 }
309290 }
310291
@@ -339,8 +320,7 @@ Showable {
339320
340321 onStatusChanged: {
341322 if (status === DirectionalDragArea.Recognized) {
342− menuContent.hideAll()
343− menuContent.activateContent()
323+ menuContent.activateContent();
344324 }
345325 }
346326 }
@@ -368,7 +348,6 @@ Showable {
368348 State {
369349 name: "reveal"
370350 extend: "hint"
371− PropertyChanges { target: menuContent; animate: true }
372351 StateChangeScript { script: calculateCurrentItem(dragHandle.touchX, false); }
373352 },
374353 State {
@@ -390,7 +369,6 @@ Showable {
390369 },
391370 State {
392371 name: "reveal"
393− PropertyChanges { target: menuContent; animate: true }
394372 StateChangeScript { script: calculateCurrentItem(dragHandle.touchX, false); }
395373 },
396374 State {
Panel/MenuContent.qml+20−69
@@ -17,16 +17,12 @@
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
1919import Unity.Indicators 0.1 as Indicators
20−import "Menus"
2120import "../Components"
2221
2322Rectangle {
2423 id: content
2524
2625 property QtObject indicatorsModel: null
27− property bool animate: true // FIXME: Remove. This doesnt seem to be being used and it's referenced in Indicators.
28− property bool overviewActive: true // "state of the menu"
29− property bool __shown: false
3026 property bool __contentActive: false
3127 property alias currentIndex : menus.currentIndex
3228 property color backgroundColor: "#221e1c" // FIXME not in palette yet
@@ -35,32 +31,17 @@ Rectangle {
3531 width: units.gu(40)
3632 height: units.gu(42)
3733 color: backgroundColor
38− enabled: __shown
3934
4035 signal menuSelected(int index)
4136
42− function showMenu() {
43− __shown = true
44− overviewActive = false
45− }
46−
47− function showOverview() {
48− __shown = true
49− overviewActive = true
50− }
51−
52− function hideAll() {
53− __shown = false
54− }
55−
5637 function activateContent() {
57− contentReleaseTimer.stop()
58− __contentActive = true
38+ contentReleaseTimer.stop();
39+ __contentActive = true;
5940 }
6041
6142 function releaseContent() {
6243 if (__contentActive)
63− contentReleaseTimer.restart()
44+ contentReleaseTimer.restart();
6445 }
6546
6647 ListView {
@@ -72,7 +53,6 @@ Rectangle {
7253 width: parent.width
7354
7455 spacing: units.gu(0.5)
75− opacity: !overviewActive && __shown ? 1 : 0
7656 enabled: opacity != 0
7757 orientation: ListView.Horizontal
7858 model: indicatorsModel
@@ -83,24 +63,23 @@ Rectangle {
8363
8464 delegate: Loader {
8565 clip: true
86− property bool contentActive: content.__contentActive
66+ property bool contentActive: content.__contentActive && menuActivator.content[index].active
8767
8868 onContentActiveChanged: {
8969 if (contentActive && item) {
90− item.start()
70+ item.start();
9171 } else if (!contentActive && item) {
92− item.stop()
72+ item.stop();
9373 }
9474 }
9575
9676 width: menus.width
9777 height: menus.height
9878 source: pageSource
99− visible: content.__shown
10079 onVisibleChanged: {
10180 // Reset the indicator states
10281 if (!visible && item && item["reset"]) {
103− item.reset()
82+ item.reset();
10483 }
10584 }
10685 asynchronous: true
@@ -108,11 +87,11 @@ Rectangle {
10887 onLoaded: {
10988 for(var pName in indicatorProperties) {
11089 if (item.hasOwnProperty(pName)) {
111− item[pName] = indicatorProperties[pName]
90+ item[pName] = indicatorProperties[pName];
11291 }
11392 }
11493 if (contentActive && menus.visible) {
115− item.start()
94+ item.start();
11695 }
11796 }
11897
@@ -124,40 +103,6 @@ Rectangle {
124103 value: handle.height
125104 }
126105 }
127−
128− Behavior on opacity { NumberAnimation {duration: 200} }
129− }
130−
131− Overview {
132− id: overview
133− objectName: "overview"
134−
135− anchors.top: header.bottom
136− anchors.bottom: parent.bottom
137− // FIXME: Dont know why we're using handle height (introduces dep).. Check with design about bottom margin
138− anchors.bottomMargin: handle.height
139−
140− width: content.width
141− indicatorsModel: content.indicatorsModel
142− enabled: content.overviewActive && content.__shown
143− opacity: content.overviewActive && content.__shown ? 1 : 0
144− Behavior on opacity {NumberAnimation{duration: 200}}
145− visible: opacity != 0
146−
147− onMenuSelected: {
148− var storedDuration = menus.highlightMoveDuration
149− var storedVelocity = menus.highlightMoveVelocity
150− menus.highlightMoveDuration = 0
151− menus.highlightMoveVelocity = 100000
152−
153− menus.currentIndex = modelIndex
154− content.overviewActive = false
155−
156− menus.highlightMoveDuration = storedDuration
157− menus.highlightMoveVelocity = storedVelocity
158−
159− content.menuSelected(modelIndex)
160− }
161106 }
162107
163108 Rectangle {
@@ -181,14 +126,10 @@ Rectangle {
181126 right: parent.right
182127 }
183128 text: {
184− if (content.overviewActive)
185− return i18n.tr("Device");
186129 if (indicatorsModel && menus.currentIndex >= 0 && menus.currentIndex < indicatorsModel.count)
187130 return indicatorsModel.data(menus.currentIndex, Indicators.IndicatorsModelRole.Title);
188131 return "";
189132 }
190− opacity: __shown ? 1 : 0
191− Behavior on opacity {NumberAnimation{duration: 100}}
192133 }
193134 }
194135
@@ -196,6 +137,16 @@ Rectangle {
196137 id: contentReleaseTimer
197138
198139 interval: contentReleaseInterval
199− onTriggered: __contentActive = false
140+ onTriggered: {
141+ __contentActive = false;
142+ menuActivator.clear();
143+ }
144+ }
145+
146+ Indicators.MenuContentActivator {
147+ id: menuActivator
148+ running: content.__contentActive
149+ baseIndex: content.currentIndex
150+ count: indicatorsModel.count
200151 }
201152}
Panel/Menus/Overview.qmldeleted−70
@@ -1,70 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−import "../../Components/ListItems" as ListItems
20−import "Overview"
21−
22−IndicatorMenuWindow {
23− id: overview
24−
25− property QtObject indicatorsModel: null
26−
27− signal menuSelected(int modelIndex)
28−
29− VisualItemModel {
30− id: itemModel
31−
32− FlightModeWidget {
33− anchors {
34− left: parent ? parent.left : undefined
35− right: parent ? parent.right : undefined
36− }
37− height: units.gu(8)
38−
39− ListItems.ThinDivider {
40− anchors {
41− bottom: parent.bottom
42− bottomMargin: -units.dp(1)
43− }
44− }
45− }
46−
47− VolumeWidget {
48− anchors {
49− left: parent ? parent.left : undefined
50− right: parent ? parent.right : undefined
51− }
52− height: units.gu(10)
53− }
54−
55− OverviewGrid {
56− model: indicatorsModel
57− anchors {
58− left: parent ? parent.left : undefined
59− right: parent ? parent.right : undefined
60− }
61− }
62− }
63−
64− ListView {
65− id: listView
66− anchors.fill: parent
67− model: itemModel
68− interactive: false
69− }
70−}
Panel/Menus/Overview/FlightModeWidget.qmldeleted−60
@@ -1,60 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−
20−Item {
21− id: flightModeWidget
22−
23− Image {
24− id: flightIcon
25− source: "graphics/plane_icon.png"
26− anchors {
27− left: parent.left
28− leftMargin: units.gu(2)
29− verticalCenter: parent.verticalCenter
30− }
31− width: units.gu(4)
32− height: units.gu(4)
33− }
34−
35− Label {
36− anchors {
37− left: flightIcon.right
38− right: flightModeSwitch.left
39− margins: units.gu(2)
40− verticalCenter: parent.verticalCenter
41− }
42− text: i18n.tr("Flight mode")
43− color: Theme.palette.selected.backgroundText
44− style: Text.Raised
45− styleColor: "black"
46− opacity: 0.6;
47− fontSize: "medium"
48− elide: Text.ElideRight
49− horizontalAlignment: Text.AlignLeft
50− }
51−
52− Switch {
53− id: flightModeSwitch
54− anchors {
55− right: parent.right
56− rightMargin: units.gu(2)
57− verticalCenter: parent.verticalCenter
58− }
59− }
60−}
Panel/Menus/Overview/OverviewGrid.qmldeleted−135
@@ -1,135 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−
20−import "../../../Components/ListItems" as ListItems
21−
22−Item {
23− id: overviewGrid
24−
25− height: childrenRect.height
26−
27− property var model
28−
29− UbuntuShape {
30− id: gridBackground
31− anchors.fill: grid
32− color: "#282421" // FIXME missing palette
33− radius: "medium"
34− }
35−
36− GridView {
37− id: grid
38− objectName: "overviewGrid"
39−
40− property int columnCount: 3
41− property int rowCount: Math.ceil(model.count / columnCount)
42−
43− anchors {
44− top: parent.top
45− left: parent.left
46− right: parent.right
47− topMargin: units.gu(3)
48− leftMargin: units.gu(2)
49− rightMargin: units.gu(2)
50− }
51− height: cellWidth * rowCount
52− cellWidth: Math.floor((width) / columnCount)
53− cellHeight: cellWidth
54− model: overviewGrid.model
55− visible: opacity != 0
56− interactive: false
57− delegate:
58− AbstractButton {
59− objectName: "overviewGridButton" + index
60− width: grid.cellWidth
61− height: grid.cellHeight
62−
63− Loader {
64− id: loader
65− source: widgetSource
66−
67− width: units.gu(5)
68− height: units.gu(5)
69− anchors.centerIn: parent
70− anchors.verticalCenterOffset: -units.gu(1)
71−
72− onLoaded: {
73− for(var pName in indicatorProperties) {
74− if (item.hasOwnProperty(pName)) {
75− item[pName] = indicatorProperties[pName]
76− }
77− }
78− }
79− }
80−
81− Label {
82− text: title
83− color: Theme.palette.selected.backgroundText
84− fontSize: "small"
85− anchors {
86− left: parent.left
87− right: parent.right
88− bottom: parent.bottom
89− leftMargin: units.gu(0.5)
90− rightMargin: units.gu(0.5)
91− bottomMargin: units.gu(1.5)
92− }
93− elide: Text.ElideRight
94− horizontalAlignment: Text.AlignHCenter
95−
96− }
97− onClicked: overview.menuSelected(index)
98− }
99− }
100−
101− Item {
102− id: gridOverlay
103− anchors.fill: grid
104−
105− Column {
106− anchors {
107− left: parent.left
108− right: parent.right
109− }
110− spacing: grid.cellHeight
111− y: grid.cellHeight - units.dp(1)
112− Repeater {
113− model: grid.rowCount - 1
114− ListItems.ThinDivider {
115− anchors.margins: units.dp(1)
116− }
117− }
118− }
119−
120− Row {
121− anchors {
122− top: parent.top
123− bottom: parent.bottom
124− }
125− spacing: grid.cellWidth - units.dp(1)
126− x: grid.cellWidth - units.dp(1)
127− Repeater {
128− model: grid.columnCount - 1
129− ListItems.VerticalThinDivider {
130− anchors.margins: units.dp(1)
131− }
132− }
133− }
134− }
135−}
Panel/Menus/Overview/VolumeWidget.qmldeleted−88
@@ -1,88 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−import "../../../Components/"
20−
21−Item {
22− id: volumeWidget
23−
24− Image {
25− id: minVolumeIcon
26− objectName: "minVolumeIcon"
27− source: "graphics/sound_off_icon.png"
28− anchors {
29− left: parent.left
30− leftMargin: units.gu(2)
31− verticalCenter: parent.verticalCenter
32− }
33− width: units.gu(4)
34− height: units.gu(4)
35−
36− MouseArea {
37− anchors.fill: parent
38− onClicked: volumeControl.volumeDown();
39− }
40− }
41−
42− Slider {
43− id: slider
44− objectName: "volumeSlider"
45− anchors {
46− left: minVolumeIcon.right
47− right: maxVolumeIcon.left
48− margins: units.gu(1)
49− verticalCenter: parent.verticalCenter
50− }
51− live: false
52− minimumValue: 0
53− maximumValue: 100
54− value: 50
55−
56− onValueChanged: {
57− volumeControl.volume = value;
58− }
59−
60− Binding {
61− target: slider
62− property: "value"
63− value: volumeControl.volume
64− }
65−
66− function formatValue(v) {
67− return ""
68− }
69− }
70−
71− Image {
72− id: maxVolumeIcon
73− objectName: "maxVolumeIcon"
74− source: "graphics/sound_on_icon.png"
75− anchors {
76− right: parent.right
77− rightMargin: units.gu(2)
78− verticalCenter: parent.verticalCenter
79− }
80− width: units.gu(4)
81− height: units.gu(4)
82−
83− MouseArea {
84− anchors.fill: parent
85− onClicked: volumeControl.volumeUp();
86− }
87− }
88−}
Panel/Menus/Overview/graphics/plane_icon@18.pngdeleted

Binary file not shown.

Panel/Menus/Overview/graphics/sound_off_icon@18.pngdeleted

Binary file not shown.

Panel/Menus/Overview/graphics/sound_on_icon@18.pngdeleted

Binary file not shown.

Shell.qml+2−2
@@ -36,8 +36,8 @@ FocusScope {
3636
3737 // this is only here to select the width / height of the window if not running fullscreen
3838 property bool tablet: false
39− width: tablet ? units.gu(160) : units.gu(40)
40− height: tablet ? units.gu(100) : units.gu(71)
39+ width: tablet ? units.gu(160) : ApplicationArguments.hasGeometry() ? ApplicationArguments.width() : units.gu(40)
40+ height: tablet ? units.gu(100) : ApplicationArguments.hasGeometry() ? ApplicationArguments.height() : units.gu(71)
4141
4242 property real edgeSize: units.gu(2)
4343 property url default_background: shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg"
debian/changelog+19
@@ -1,3 +1,22 @@
1+unity8 (7.81.3+13.10.20130718ubuntu.unity.next-0ubuntu1) saucy; urgency=low
2+
3+ [ Andrea Cimitan ]
4+ * Add support for the colour palette.
5+
6+ [ Omer Akram ]
7+ * fix the calendar icon in the launcher. (LP: #1201905)
8+
9+ [ Nick Dedekind ]
10+ * Export indicator plugin symbols using Q_DECL_EXPORT.
11+
12+ [ Ying-Chun Liu ]
13+ * Don't include .moc in previewbindingstest.cpp.
14+
15+ [ Ubuntu daily release ]
16+ * Automatic snapshot from revision 118 (ubuntu-unity/next)
17+
18+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 18 Jul 2013 06:07:00 +0000
19+
120unity8 (7.81.3+13.10.20130717ubuntu.unity.next-0ubuntu1) saucy; urgency=low
221
322 [ Daniel d'Andrada ]
main.cpp+4−6
@@ -18,6 +18,7 @@
1818 */
1919
2020// Qt
21+#include <QtQml>
2122#include <QtQuick/QQuickView>
2223#include <QtGui/QIcon>
2324#include <QtGui/QGuiApplication>
@@ -30,6 +31,7 @@
3031// local
3132#include "paths.h"
3233#include "MouseTouchAdaptor.h"
34+#include "ApplicationArguments.h"
3335
3436namespace {
3537
@@ -86,6 +88,7 @@ int main(int argc, char** argv)
8688 resolveIconTheme();
8789
8890 QStringList args = application.arguments();
91+ ApplicationArguments qmlArgs(args);
8992
9093 // The testability driver is only loaded by QApplication but not by QGuiApplication.
9194 // However, QApplication depends on QWidget which would add some unneeded overhead => Let's load the testability driver on our own.
@@ -110,6 +113,7 @@ int main(int argc, char** argv)
110113 view->setResizeMode(QQuickView::SizeRootObjectToView);
111114 view->setTitle("Qml Phone Shell");
112115 view->engine()->setBaseUrl(QUrl::fromLocalFile(::shellAppDirectory()));
116+ view->rootContext()->setContextProperty("ApplicationArguments", &qmlArgs);
113117 if (args.contains(QLatin1String("-frameless"))) {
114118 view->setFlags(Qt::FramelessWindowHint);
115119 }
@@ -141,12 +145,6 @@ int main(int argc, char** argv)
141145 if (qgetenv("QT_QPA_PLATFORM") == "ubuntu" || args.contains(QLatin1String("-fullscreen"))) {
142146 view->showFullScreen();
143147 } else {
144− if (args.contains(QLatin1String("-geometry")) && args.size() > args.indexOf(QLatin1String("-geometry")) + 1) {
145− QStringList geometryArg = args.at(args.indexOf(QLatin1String("-geometry")) + 1).split('x');
146− if (geometryArg.size() == 2) {
147− view->resize(geometryArg.at(0).toInt(), geometryArg.at(1).toInt());
148− }
149− }
150148 view->show();
151149 }
152150
plugins/ListViewWithPageHeader/listviewwithpageheader.cpp+1−1
@@ -806,7 +806,7 @@ void ListViewWithPageHeader::onModelUpdated(const QQuickChangeSet &changeSet, bo
806806 Q_FOREACH(const QQuickChangeSet::Insert &insert, changeSet.inserts()) {
807807// qDebug() << "ListViewWithPageHeader::onModelUpdated Insert" << insert.index << insert.count;
808808 const bool insertingInValidIndexes = insert.index > m_firstVisibleIndex && insert.index < m_firstVisibleIndex + m_visibleItems.count();
809− const bool firstItemWithViewOnTop = insert.index == 0 && m_firstVisibleIndex == 0 && m_visibleItems.first()->y() + m_clipItem->y() > contentY();
809+ const bool firstItemWithViewOnTop = insert.index == 0 && m_firstVisibleIndex == 0 && !m_visibleItems.isEmpty() && m_visibleItems.first()->y() + m_clipItem->y() > contentY();
810810 if (insertingInValidIndexes || firstItemWithViewOnTop)
811811 {
812812 // If the items we are adding won't be really visible
plugins/Unity/Indicators/CMakeLists.txt+1
@@ -23,6 +23,7 @@ set(IndicatorsQML_SOURCES
2323 indicators.h
2424 indicatorsmanager.cpp
2525 indicatorsmodel.cpp
26+ menucontentactivator.cpp
2627 plugin.cpp
2728)
2829add_definitions(-DUNITYINDICATORS_LIBRARY)
plugins/Unity/Indicators/menucontentactivator.cppnew file+345
@@ -0,0 +1,345 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Author: Nick Dedekind <nick.dedekind@canonical.com>
17+ */
18+
19+ #include "menucontentactivator.h"
20+
21+// Essentially a QTimer wrapper
22+class ContentTimer : public UnityIndicators::AbstractTimer
23+{
24+ Q_OBJECT
25+public:
26+ ContentTimer(QObject *parent) : UnityIndicators::AbstractTimer(parent) {
27+ m_timer.setSingleShot(false);
28+ connect(&m_timer, &QTimer::timeout,
29+ this, &UnityIndicators::AbstractTimer::timeout);
30+ }
31+ virtual int interval() const { return m_timer.interval(); }
32+ virtual void setInterval(int msecs) { m_timer.setInterval(msecs); }
33+ virtual void start() { m_timer.start(); UnityIndicators::AbstractTimer::start(); }
34+ virtual void stop() { m_timer.stop(); UnityIndicators::AbstractTimer::stop(); }
35+private:
36+ QTimer m_timer;
37+};
38+
39+class MenuContentActivatorPrivate : public QObject
40+{
41+ Q_OBJECT
42+public:
43+ MenuContentActivatorPrivate(MenuContentActivator* parent)
44+ : m_running(false),
45+ m_baseIndex(0),
46+ m_delta(0),
47+ m_count(0),
48+ m_timer(NULL),
49+ q(parent)
50+ {}
51+
52+ ~MenuContentActivatorPrivate()
53+ {
54+ qDeleteAll(m_content);
55+ m_content.clear();
56+ }
57+
58+ int findNextInactiveDelta(bool* finished = NULL);
59+
60+ static int content_count(QQmlListProperty<MenuContentState> *prop);
61+ static MenuContentState* content_at(QQmlListProperty<MenuContentState> *prop, int index);
62+
63+ bool m_running;
64+ int m_baseIndex;
65+ int m_delta;
66+ int m_count;
67+ UnityIndicators::AbstractTimer* m_timer;
68+ QMap<int, MenuContentState*> m_content;
69+ MenuContentActivator* q;
70+};
71+
72+MenuContentActivator::MenuContentActivator(QObject* parent)
73+ : QObject(parent),
74+ d(new MenuContentActivatorPrivate(this))
75+{
76+ qRegisterMetaType<QQmlListProperty<MenuContentState> > ("QQmlListProperty<MenuContentState>");
77+
78+ setContentTimer(new ContentTimer(this));
79+ d->m_timer->setInterval(75);
80+}
81+
82+MenuContentActivator::~MenuContentActivator()
83+{
84+ delete d;
85+}
86+
87+void MenuContentActivator::restart()
88+{
89+ // when we start, make sure we have the base index in the list.
90+ setMenuContentState(d->m_baseIndex, true);
91+ setDelta(0);
92+
93+ // check if we've finished before starting the timer.
94+ bool finished = false;
95+ d->findNextInactiveDelta(&finished);
96+ if (!finished) {
97+ d->m_timer->start();
98+ } else {
99+ d->m_timer->stop();
100+ }
101+
102+ if (!d->m_running) {
103+ d->m_running = true;
104+ Q_EMIT runningChanged(true);
105+ }
106+}
107+
108+void MenuContentActivator::stop()
109+{
110+ d->m_timer->stop();
111+ if (!d->m_running) {
112+ d->m_running = false;
113+ Q_EMIT runningChanged(false);
114+ }
115+}
116+
117+void MenuContentActivator::clear()
118+{
119+ qDeleteAll(d->m_content);
120+ d->m_content.clear();
121+
122+ setDelta(0);
123+ d->m_timer->stop();
124+
125+ Q_EMIT contentChanged();
126+}
127+
128+bool MenuContentActivator::isMenuContentActive(int index) const
129+{
130+ if (d->m_content.contains(index))
131+ return d->m_content[index]->isActive();
132+ return false;
133+}
134+
135+void MenuContentActivator::setRunning(bool running)
136+{
137+ if (running) {
138+ restart();
139+ } else {
140+ stop();
141+ }
142+}
143+
144+bool MenuContentActivator::isRunning() const
145+{
146+ return d->m_running;
147+}
148+
149+void MenuContentActivator::setBaseIndex(int index)
150+{
151+ if (d->m_baseIndex != index) {
152+ d->m_baseIndex = index;
153+
154+ if (isRunning()) {
155+ restart();
156+ }
157+
158+ Q_EMIT baseIndexChanged(index);
159+ }
160+}
161+
162+int MenuContentActivator::baseIndex() const
163+{
164+ return d->m_baseIndex;
165+}
166+
167+void MenuContentActivator::setCount(int count)
168+{
169+ if (d->m_count != count) {
170+ d->m_count = count;
171+ Q_EMIT countChanged(count);
172+
173+ if (isRunning()) {
174+ restart();
175+ }
176+ }
177+}
178+
179+int MenuContentActivator::count() const
180+{
181+ return d->m_count;
182+}
183+
184+void MenuContentActivator::setDelta(int delta)
185+{
186+ if (d->m_delta != delta) {
187+ d->m_delta = delta;
188+ Q_EMIT deltaChanged(d->m_delta);
189+ }
190+}
191+
192+int MenuContentActivator::delta() const
193+{
194+ return d->m_delta;
195+}
196+
197+QQmlListProperty<MenuContentState> MenuContentActivator::content()
198+{
199+ return QQmlListProperty<MenuContentState>(this,
200+ 0,
201+ MenuContentActivatorPrivate::content_count,
202+ MenuContentActivatorPrivate::content_at);
203+}
204+
205+void MenuContentActivator::onTimeout()
206+{
207+ bool finished = false;
208+ int tempDelta = d->findNextInactiveDelta(&finished);
209+ if (!finished) {
210+ setMenuContentState(d->m_baseIndex + tempDelta, true);
211+ setDelta(tempDelta);
212+ }
213+
214+ if (finished) {
215+ d->m_timer->stop();
216+ }
217+}
218+
219+void MenuContentActivator::setContentTimer(UnityIndicators::AbstractTimer *timer)
220+{
221+ int interval = 0;
222+ bool timerWasRunning = false;
223+
224+ // can be null when called from the constructor
225+ if (d->m_timer) {
226+ interval = d->m_timer->interval();
227+ timerWasRunning = d->m_timer->isRunning();
228+ if (d->m_timer->parent() == this) {
229+ delete d->m_timer;
230+ }
231+ }
232+
233+ d->m_timer = timer;
234+ timer->setInterval(interval);
235+ connect(timer, &UnityIndicators::AbstractTimer::timeout,
236+ this, &MenuContentActivator::onTimeout);
237+ if (timerWasRunning) {
238+ d->m_timer->start();
239+ }
240+}
241+
242+void MenuContentActivator::setMenuContentState(int index, bool active)
243+{
244+ if (d->m_content.contains(index)) {
245+ d->m_content[index]->setActive(active);
246+ } else {
247+ d->m_content[index] = new MenuContentState(active);
248+ Q_EMIT contentChanged();
249+ }
250+}
251+
252+int MenuContentActivatorPrivate::findNextInactiveDelta(bool* finished)
253+{
254+ if (m_count == 0 || m_baseIndex >= m_count) {
255+ if (finished) *finished = true;
256+ return 0;
257+ }
258+
259+ int tmpDelta = m_delta;
260+ bool topReached = false, bottomReached = false;
261+ while(true) {
262+
263+ // prechecks for bottom and top limits.
264+ if (tmpDelta > 0 && bottomReached) tmpDelta = -tmpDelta;
265+ if (tmpDelta < 0 && topReached) tmpDelta = (-tmpDelta) + 1;
266+
267+ if (tmpDelta > 0) {
268+ // negative of baseIndex
269+ tmpDelta = -tmpDelta;
270+ // reached the bottom?
271+ if (m_baseIndex + tmpDelta < 0) {
272+ bottomReached = true;
273+ // if we've reached the top as well, then we know we're done.
274+ if (topReached) {
275+ if (finished) *finished = true;
276+ return 0;
277+ }
278+ continue;
279+ }
280+ } else {
281+ // positive of baseIndex
282+ tmpDelta = (-tmpDelta) + 1;
283+ // reached the top?
284+ if (m_baseIndex + tmpDelta >= m_count) {
285+ topReached = true;
286+ // if we've reached the bottom as well, then we know we're done.
287+ if (bottomReached) {
288+ if (finished) *finished = true;
289+ return 0;
290+ }
291+ continue;
292+ }
293+ }
294+
295+ if (q->isMenuContentActive(m_baseIndex + tmpDelta)) {
296+ continue;
297+ }
298+ break;
299+ }
300+ if (finished) *finished = false;
301+ return tmpDelta;
302+}
303+
304+int MenuContentActivatorPrivate::content_count(QQmlListProperty<MenuContentState> *prop)
305+{
306+ MenuContentActivator *p = qobject_cast<MenuContentActivator*>(prop->object);
307+ // we'll create MenuContentState on demand.
308+ return p->count();
309+}
310+
311+MenuContentState* MenuContentActivatorPrivate::content_at(QQmlListProperty<MenuContentState> *prop, int index)
312+{
313+ MenuContentActivator *p = qobject_cast<MenuContentActivator*>(prop->object);
314+ MenuContentActivatorPrivate *d = p->d;
315+
316+ if (!d->m_content.contains(index)) {
317+ MenuContentState* content = new MenuContentState(false);
318+ d->m_content[index] = content;
319+ Q_EMIT p->contentChanged();
320+ return content;
321+ }
322+
323+ return d->m_content[index];
324+}
325+
326+MenuContentState::MenuContentState(bool active)
327+ : m_active(active)
328+{
329+}
330+
331+bool MenuContentState::isActive() const
332+{
333+ return m_active;
334+}
335+
336+void MenuContentState::setActive(bool active)
337+{
338+ if (m_active != active) {
339+ m_active = active;
340+ Q_EMIT activeChanged();
341+ }
342+}
343+
344+// Because we are defining a new QObject-based class (ContentTimer) here.
345+#include "menucontentactivator.moc"
plugins/Unity/Indicators/menucontentactivator.hnew file+117
@@ -0,0 +1,117 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Author: Nick Dedekind <nick.dedekind@canonical.com>
17+ */
18+
19+#ifndef MENUCONTENTACTIVATOR_H
20+#define MENUCONTENTACTIVATOR_H
21+
22+#include "unityindicatorsglobal.h"
23+
24+#include <QObject>
25+#include <QTimer>
26+#include <QQmlListProperty>
27+
28+
29+namespace UnityIndicators {
30+/* Defines an interface for a Timer. */
31+class UNITYINDICATORS_EXPORT AbstractTimer : public QObject {
32+ Q_OBJECT
33+public:
34+ AbstractTimer(QObject *parent) : QObject(parent), m_isRunning(false) {}
35+ virtual int interval() const = 0;
36+ virtual void setInterval(int msecs) = 0;
37+ virtual void start() { m_isRunning = true; };
38+ virtual void stop() { m_isRunning = false; }
39+ bool isRunning() const { return m_isRunning; }
40+Q_SIGNALS:
41+ void timeout();
42+private:
43+ bool m_isRunning;
44+};
45+}
46+
47+/* Defines a object to express the active state of a menu. */
48+class UNITYINDICATORS_EXPORT MenuContentState : public QObject
49+{
50+ Q_OBJECT
51+ Q_PROPERTY(bool active READ isActive NOTIFY activeChanged)
52+public:
53+ MenuContentState(bool active);
54+
55+ bool isActive() const;
56+ void setActive(bool active);
57+
58+Q_SIGNALS:
59+ void activeChanged();
60+private:
61+ bool m_active;
62+};
63+
64+class MenuContentActivatorPrivate;
65+
66+class UNITYINDICATORS_EXPORT MenuContentActivator : public QObject
67+{
68+ Q_OBJECT
69+ Q_PROPERTY(int baseIndex READ baseIndex WRITE setBaseIndex NOTIFY baseIndexChanged)
70+ Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged)
71+ Q_PROPERTY(int count READ count WRITE setCount NOTIFY countChanged)
72+ Q_PROPERTY(QQmlListProperty<MenuContentState> content READ content NOTIFY contentChanged DESIGNABLE false)
73+public:
74+ MenuContentActivator(QObject* parent = NULL);
75+ ~MenuContentActivator();
76+
77+ Q_INVOKABLE void restart();
78+ Q_INVOKABLE void stop();
79+ Q_INVOKABLE void clear();
80+ Q_INVOKABLE bool isMenuContentActive(int index) const;
81+
82+ void setRunning(bool running);
83+ bool isRunning() const;
84+
85+ void setBaseIndex(int index);
86+ int baseIndex() const;
87+
88+ void setCount(int index);
89+ int count() const;
90+
91+ void setDelta(int index);
92+ int delta() const;
93+
94+ QQmlListProperty<MenuContentState> content();
95+
96+ // Replaces the existing Timer with the given one.
97+ //
98+ // Useful for providing a fake timer when testing.
99+ void setContentTimer(UnityIndicators::AbstractTimer *timer);
100+ void setMenuContentState(int index, bool active);
101+
102+Q_SIGNALS:
103+ void baseIndexChanged(int baseIndex);
104+ void deltaChanged(int delta);
105+ void runningChanged(bool running);
106+ void countChanged(int count);
107+ void contentChanged();
108+
109+private Q_SLOTS:
110+ void onTimeout();
111+
112+private:
113+ MenuContentActivatorPrivate* d;
114+ friend class MenuContentActivatorPrivate;
115+};
116+
117+#endif // MENUCONTENTACTIVATOR_H
plugins/Unity/Indicators/plugin.cpp+3
@@ -27,6 +27,7 @@
2727#include "indicatorsmanager.h"
2828#include "indicatorsmodel.h"
2929#include "indicators.h"
30+#include "menucontentactivator.h"
3031
3132void IndicatorsPlugin::registerTypes(const char *uri)
3233{
@@ -35,7 +36,9 @@ void IndicatorsPlugin::registerTypes(const char *uri)
3536 qmlRegisterType<IndicatorsManager>(uri, 0, 1, "IndicatorsManager");
3637 qmlRegisterType<FlatMenuProxyModel>(uri, 0, 1, "FlatMenuProxyModel");
3738 qmlRegisterType<IndicatorsModel>(uri, 0, 1, "IndicatorsModel");
39+ qmlRegisterType<MenuContentActivator>(uri, 0, 1, "MenuContentActivator");
3840
41+ qmlRegisterUncreatableType<MenuContentState>(uri, 0, 1, "MenuContentState", "Can't create MenuContentState class");
3942 qmlRegisterUncreatableType<ActionState>(uri, 0, 1, "ActionState", "Can't create ActionState class");
4043 qmlRegisterUncreatableType<NetworkActionState>(uri, 0, 1, "NetworkActionState", "Can't create NetworkActionState class");
4144 qmlRegisterUncreatableType<NetworkConnection>(uri, 0, 1, "NetworkConnection", "Can't create NetworkConnection class");
plugins/Unity/Indicators/qml/IndicatorPage.qml−6
@@ -188,10 +188,4 @@ IndicatorBase {
188188 mainMenu.currentIndex = -1;
189189 mainMenu.positionViewAtBeginning();
190190 }
191−
192− Component.onCompleted: {
193− if ((busType != 0) && (busName != "") && (deviceMenuObjectPath != "")) {
194− start();
195− }
196− }
197191}
run_on_device+3−19
@@ -33,7 +33,7 @@ usage() {
3333}
3434
3535exec_with_ssh() {
36− ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -t $USER@$TARGET_IP -p $TARGET_SSH_PORT "bash -ic \"$@\""
36+ ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -t $USER@$TARGET_IP -p $TARGET_SSH_PORT sudo -u $USER -i bash -ic \"$@\"
3737}
3838
3939exec_with_adb() {
@@ -83,17 +83,6 @@ build() {
8383}
8484
8585run() {
86− SERVICEFILE="${CHROOT_PREFIX}/etc/device-services"
87− adb shell "egrep '$BINARY' $SERVICEFILE"
88− CONTAINS_SHELL=$?
89− if [ $CONTAINS_SHELL -eq 0 ]; then
90− echo "Modifying $SERVICEFILE on device. Old contents will be saved in $SERVICEFILE.backup"
91− adb shell cp $SERVICEFILE $SERVICEFILE.backup
92− adb shell sed -i "/$BINARY/d" $SERVICEFILE
93− if $FLIPPED; then exec_with_adb /usr/bin/service ubuntu-touch-session restart
94− else exec_with_adb /usr/bin/service ubuntu-session restart; fi
95− fi
96− adb shell pkill $BINARY
9786 ARGS="--nomousetouch"
9887 if $GDB; then
9988 ARGS="$ARGS --gdb"
@@ -105,14 +94,9 @@ run() {
10594 ARGS="$ARGS -k"
10695 fi
10796
97+ exec_with_ssh "stop unity8"
10898 exec_with_ssh "cd $CODE_DIR/ && ./run $ARGS -- $RUN_OPTIONS"
109−
110− if [ $CONTAINS_SHELL -eq 0 ]; then
111− echo "Restoring $SERVICEFILE on device from $SERVICEFILE.backup"
112− adb shell cp $SERVICEFILE.backup $SERVICEFILE
113− if $FLIPPED; then exec_with_adb /usr/bin/service ubuntu-touch-session restart
114− else exec_with_adb /usr/bin/service ubuntu-session restart; fi
115− fi
99+ exec_with_ssh "start unity8"
116100}
117101
118102set -- `getopt -n$0 -u -a --longoptions="setup,gdb,pinlock,keylock,help" "sgpkh" "$@"`
tests/mocks/Unity/Indicators/CMakeLists.txt+1
@@ -12,6 +12,7 @@ include_directories(
1212set(IndicatorsFakeQml_SOURCES
1313 fakeplugin.cpp
1414 ${CMAKE_SOURCE_DIR}/plugins/Unity/Indicators/indicators.h
15+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Indicators/menucontentactivator.cpp
1516)
1617
1718set(IndicatorsFakeQml_RESOURCES
tests/mocks/Unity/Indicators/fakeplugin.cpp+4
@@ -24,11 +24,15 @@
2424
2525// local
2626#include "indicators.h"
27+#include "menucontentactivator.h"
2728
2829void IndicatorsFakePlugin::registerTypes(const char * uri)
2930{
3031 Q_INIT_RESOURCE(indicators_fake);
3132
33+ qmlRegisterType<MenuContentActivator>(uri, 0, 1, "MenuContentActivator");
34+
35+ qmlRegisterUncreatableType<MenuContentState>(uri, 0, 1, "MenuContentState", "Can't create MenuContentState class");
3236 qmlRegisterUncreatableType<ActionState>(uri, 0, 1, "ActionState", "Can't create ActionState class");
3337 qmlRegisterUncreatableType<NetworkActionState>(uri, 0, 1, "NetworkActionState", "Can't create NetworkActionState class");
3438 qmlRegisterUncreatableType<NetworkConnection>(uri, 0, 1, "NetworkConnection", "Can't create NetworkConnection class");
tests/plugins/ListViewWithPageHeader/listviewwithpageheadertest.cpp+19
@@ -991,6 +991,25 @@ private Q_SLOTS:
991991 QCOMPARE(lvwph->m_headerItemShownHeight, 50.);
992992 }
993993
994+ void testInsertToEmpty()
995+ {
996+ QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 0), Q_ARG(QVariant, 6));
997+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 0);
998+ QCOMPARE(lvwph->m_minYExtent, 0.);
999+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
1000+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1001+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1002+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1003+ QCOMPARE(lvwph->contentY(), 0.);
1004+
1005+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 100));
1006+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 125));
1007+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1008+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1009+ verifyItem(0, 50., 125., false);
1010+ verifyItem(1, 175., 100., false);
1011+ }
1012+
9941013 void testRemoveItemsAtTop()
9951014 {
9961015 QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 0), Q_ARG(QVariant, 2));
tests/plugins/ListViewWithPageHeader/listviewwithpageheadertestsection.cpp+19
@@ -1121,6 +1121,25 @@ private Q_SLOTS:
11211121 QCOMPARE(lvwph->m_topSectionItem->y(), -23.);
11221122 }
11231123
1124+ void testInsertToEmpty()
1125+ {
1126+ QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 0), Q_ARG(QVariant, 6));
1127+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 0);
1128+ QCOMPARE(lvwph->m_minYExtent, 0.);
1129+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
1130+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1131+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1132+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1133+ QCOMPARE(lvwph->contentY(), 0.);
1134+
1135+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 100), Q_ARG(QVariant, "Agressive"));
1136+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 1), Q_ARG(QVariant, 125), Q_ARG(QVariant, "Regular"));
1137+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1138+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1139+ verifyItem(0, 50., 140., false, "Agressive", false);
1140+ verifyItem(1, 190., 165., false, "Regular", false);
1141+ }
1142+
11241143 void testRemoveItemsAtTop()
11251144 {
11261145 QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 0), Q_ARG(QVariant, 2));
tests/plugins/Unity/Indicators/CMakeLists.txt+1
@@ -24,4 +24,5 @@ endmacro(run_tests)
2424run_tests(
2525 indicatorsmanagertest
2626 indicatorsmodeltest
27+ menucontentactivatortest
2728 )
tests/plugins/Unity/Indicators/menucontentactivatortest.cppnew file+303
@@ -0,0 +1,303 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Nick Dedekind <nick.dedekind@canonical.com>
18+ */
19+
20+#include "menucontentactivator.h"
21+#include "paths.h"
22+
23+#include <QtTest>
24+#include <QDebug>
25+
26+class FakeTimer : public UnityIndicators::AbstractTimer
27+{
28+ Q_OBJECT
29+public:
30+ FakeTimer(QObject *parent = 0)
31+ : UnityIndicators::AbstractTimer(parent)
32+ {}
33+
34+ virtual int interval() const { return m_duration; }
35+ virtual void setInterval(int msecs) { m_duration = msecs; }
36+
37+ void emitTimeout() {
38+ if (isRunning()) {
39+ Q_EMIT timeout();
40+ }
41+ }
42+private:
43+ int m_duration;
44+};
45+
46+
47+class MenuConentActivatorTest : public QObject
48+{
49+ Q_OBJECT
50+private Q_SLOTS:
51+ void init() // called right before each and every test function is executed
52+ {
53+ m_fakeTimeSource = new FakeTimer(this);
54+ m_deltas.clear();
55+ }
56+ void cleanup() // called right after each and every test function is executed
57+ {
58+ delete m_fakeTimeSource;
59+ m_fakeTimeSource = 0;
60+ }
61+
62+ /*
63+ * Tests the ordering of activation
64+ */
65+ void testContentActiveChange()
66+ {
67+ MenuContentActivator activator;
68+ activator.setContentTimer(m_fakeTimeSource);
69+ activator.setCount(10);
70+ activator.setBaseIndex(5);
71+ activator.restart();
72+
73+ QCOMPARE(activator.isMenuContentActive(4), false);
74+ QCOMPARE(activator.isMenuContentActive(5), true); // always active at base index.
75+ QCOMPARE(activator.isMenuContentActive(6), false);
76+
77+ m_fakeTimeSource->emitTimeout();
78+ QCOMPARE(activator.isMenuContentActive(4), false);
79+ QCOMPARE(activator.isMenuContentActive(5), true);
80+ QCOMPARE(activator.isMenuContentActive(6), true);
81+ QCOMPARE(activator.isMenuContentActive(7), false);
82+
83+ m_fakeTimeSource->emitTimeout();
84+ QCOMPARE(activator.isMenuContentActive(3), false);
85+ QCOMPARE(activator.isMenuContentActive(4), true);
86+ QCOMPARE(activator.isMenuContentActive(5), true);
87+ QCOMPARE(activator.isMenuContentActive(6), true);
88+ QCOMPARE(activator.isMenuContentActive(7), false);
89+
90+ m_fakeTimeSource->emitTimeout();
91+ QCOMPARE(activator.isMenuContentActive(3), false);
92+ QCOMPARE(activator.isMenuContentActive(4), true);
93+ QCOMPARE(activator.isMenuContentActive(5), true);
94+ QCOMPARE(activator.isMenuContentActive(6), true);
95+ QCOMPARE(activator.isMenuContentActive(7), true);
96+ QCOMPARE(activator.isMenuContentActive(8), false);
97+
98+ m_fakeTimeSource->emitTimeout();
99+ QCOMPARE(activator.isMenuContentActive(2), false);
100+ QCOMPARE(activator.isMenuContentActive(3), true);
101+ QCOMPARE(activator.isMenuContentActive(4), true);
102+ QCOMPARE(activator.isMenuContentActive(5), true);
103+ QCOMPARE(activator.isMenuContentActive(6), true);
104+ QCOMPARE(activator.isMenuContentActive(7), true);
105+ QCOMPARE(activator.isMenuContentActive(8), false);
106+
107+ m_fakeTimeSource->emitTimeout();
108+ QCOMPARE(activator.isMenuContentActive(2), false);
109+ QCOMPARE(activator.isMenuContentActive(3), true);
110+ QCOMPARE(activator.isMenuContentActive(4), true);
111+ QCOMPARE(activator.isMenuContentActive(5), true);
112+ QCOMPARE(activator.isMenuContentActive(6), true);
113+ QCOMPARE(activator.isMenuContentActive(7), true);
114+ QCOMPARE(activator.isMenuContentActive(8), true);
115+ QCOMPARE(activator.isMenuContentActive(9), false);
116+
117+ m_fakeTimeSource->emitTimeout();
118+ QCOMPARE(activator.isMenuContentActive(1), false);
119+ QCOMPARE(activator.isMenuContentActive(2), true);
120+ QCOMPARE(activator.isMenuContentActive(3), true);
121+ QCOMPARE(activator.isMenuContentActive(4), true);
122+ QCOMPARE(activator.isMenuContentActive(5), true);
123+ QCOMPARE(activator.isMenuContentActive(6), true);
124+ QCOMPARE(activator.isMenuContentActive(7), true);
125+ QCOMPARE(activator.isMenuContentActive(8), true);
126+ QCOMPARE(activator.isMenuContentActive(9), false);
127+
128+ m_fakeTimeSource->emitTimeout();
129+ QCOMPARE(activator.isMenuContentActive(1), false);
130+ QCOMPARE(activator.isMenuContentActive(2), true);
131+ QCOMPARE(activator.isMenuContentActive(3), true);
132+ QCOMPARE(activator.isMenuContentActive(4), true);
133+ QCOMPARE(activator.isMenuContentActive(5), true);
134+ QCOMPARE(activator.isMenuContentActive(6), true);
135+ QCOMPARE(activator.isMenuContentActive(7), true);
136+ QCOMPARE(activator.isMenuContentActive(8), true);
137+ QCOMPARE(activator.isMenuContentActive(9), true);
138+ QCOMPARE(activator.isMenuContentActive(10), false);
139+
140+ m_fakeTimeSource->emitTimeout();
141+ QCOMPARE(activator.isMenuContentActive(0), false);
142+ QCOMPARE(activator.isMenuContentActive(1), true);
143+ QCOMPARE(activator.isMenuContentActive(2), true);
144+ QCOMPARE(activator.isMenuContentActive(3), true);
145+ QCOMPARE(activator.isMenuContentActive(4), true);
146+ QCOMPARE(activator.isMenuContentActive(5), true);
147+ QCOMPARE(activator.isMenuContentActive(6), true);
148+ QCOMPARE(activator.isMenuContentActive(7), true);
149+ QCOMPARE(activator.isMenuContentActive(8), true);
150+ QCOMPARE(activator.isMenuContentActive(9), true);
151+ QCOMPARE(activator.isMenuContentActive(10), false);
152+
153+ m_fakeTimeSource->emitTimeout();
154+ QCOMPARE(activator.isMenuContentActive(-1), false);
155+ QCOMPARE(activator.isMenuContentActive(0), true);
156+ QCOMPARE(activator.isMenuContentActive(1), true);
157+ QCOMPARE(activator.isMenuContentActive(2), true);
158+ QCOMPARE(activator.isMenuContentActive(3), true);
159+ QCOMPARE(activator.isMenuContentActive(4), true);
160+ QCOMPARE(activator.isMenuContentActive(5), true);
161+ QCOMPARE(activator.isMenuContentActive(6), true);
162+ QCOMPARE(activator.isMenuContentActive(7), true);
163+ QCOMPARE(activator.isMenuContentActive(8), true);
164+ QCOMPARE(activator.isMenuContentActive(9), true);
165+ QCOMPARE(activator.isMenuContentActive(10), false);
166+ }
167+
168+ /*
169+ * Tests the delta calculation for each timeout.
170+ */
171+ void testDelta()
172+ {
173+ MenuContentActivator activator;
174+ activator.setContentTimer(m_fakeTimeSource);
175+ activator.setCount(9);
176+ activator.setBaseIndex(3);
177+
178+ connect(&activator, &MenuContentActivator::deltaChanged,
179+ this, &MenuConentActivatorTest::onDeltaChange);
180+ activator.restart();
181+
182+ QCOMPARE(m_deltas, QList<int>()); // empty
183+ QCOMPARE(getIndexList(&activator), QList<int>()); // empty
184+
185+ m_fakeTimeSource->emitTimeout();
186+ QCOMPARE(m_deltas, QList<int>() << 1);
187+ QCOMPARE(getIndexList(&activator), QList<int>() << 4);
188+
189+ m_fakeTimeSource->emitTimeout();
190+ QCOMPARE(m_deltas, QList<int>() << 1 << -1);
191+ QCOMPARE(getIndexList(&activator), QList<int>() << 4 << 2);
192+
193+ m_fakeTimeSource->emitTimeout();
194+ QCOMPARE(m_deltas, QList<int>() << 1 << -1 << 2);
195+ QCOMPARE(getIndexList(&activator), QList<int>() << 4 << 2 << 5);
196+
197+ m_fakeTimeSource->emitTimeout();
198+ QCOMPARE(m_deltas, QList<int>() << 1 << -1 << 2 << -2);
199+ QCOMPARE(getIndexList(&activator), QList<int>() << 4 << 2 << 5 << 1);
200+
201+ m_fakeTimeSource->emitTimeout();
202+ QCOMPARE(m_deltas, QList<int>() << 1 << -1 << 2 << -2 << 3);
203+ QCOMPARE(getIndexList(&activator), QList<int>() << 4 << 2 << 5 << 1 << 6);
204+
205+ m_fakeTimeSource->emitTimeout();
206+ QCOMPARE(m_deltas, QList<int>() << 1 << -1 << 2 << -2 << 3 << -3);
207+ QCOMPARE(getIndexList(&activator), QList<int>() << 4 << 2 << 5 << 1 << 6 << 0);
208+
209+ m_fakeTimeSource->emitTimeout();
210+ QCOMPARE(m_deltas, QList<int>() << 1 << -1 << 2 << -2 << 3 << -3 << 4);
211+ QCOMPARE(getIndexList(&activator), QList<int>() << 4 << 2 << 5 << 1 << 6 << 0 << 7);
212+
213+ m_fakeTimeSource->emitTimeout();
214+ QCOMPARE(m_deltas, QList<int>() << 1 << -1 << 2 << -2 << 3 << -3 << 4 << 5);
215+ QCOMPARE(getIndexList(&activator), QList<int>() << 4 << 2 << 5 << 1 << 6 << 0 << 7 << 8);
216+
217+ m_fakeTimeSource->emitTimeout();
218+ QCOMPARE(m_deltas, QList<int>() << 1 << -1 << 2 << -2 << 3 << -3 << 4 << 5);
219+ QCOMPARE(getIndexList(&activator), QList<int>() << 4 << 2 << 5 << 1 << 6 << 0 << 7 << 8);
220+ }
221+
222+ /*
223+ * Tests that changing the base index re-prioritizes the activation
224+ * around the base index.
225+ */
226+ void testBaseIndexChange()
227+ {
228+ MenuContentActivator activator;
229+ activator.setContentTimer(m_fakeTimeSource);
230+ activator.setCount(12);
231+ activator.setBaseIndex(5);
232+ activator.restart();
233+
234+ m_fakeTimeSource->emitTimeout();
235+ m_fakeTimeSource->emitTimeout();
236+ QCOMPARE(activator.isMenuContentActive(3), false);
237+ QCOMPARE(activator.isMenuContentActive(4), true);
238+ QCOMPARE(activator.isMenuContentActive(5), true); // always active at base index.
239+ QCOMPARE(activator.isMenuContentActive(6), true);
240+ QCOMPARE(activator.isMenuContentActive(7), false);
241+
242+ activator.setBaseIndex(8);
243+ QCOMPARE(activator.isMenuContentActive(3), false);
244+ QCOMPARE(activator.isMenuContentActive(4), true);
245+ QCOMPARE(activator.isMenuContentActive(5), true);
246+ QCOMPARE(activator.isMenuContentActive(6), true);
247+ QCOMPARE(activator.isMenuContentActive(7), false);
248+ QCOMPARE(activator.isMenuContentActive(8), true);
249+ QCOMPARE(activator.isMenuContentActive(9), false);
250+
251+ m_fakeTimeSource->emitTimeout();
252+ QCOMPARE(activator.isMenuContentActive(3), false);
253+ QCOMPARE(activator.isMenuContentActive(4), true);
254+ QCOMPARE(activator.isMenuContentActive(5), true);
255+ QCOMPARE(activator.isMenuContentActive(6), true);
256+ QCOMPARE(activator.isMenuContentActive(7), false);
257+ QCOMPARE(activator.isMenuContentActive(8), true);
258+ QCOMPARE(activator.isMenuContentActive(9), true);
259+ QCOMPARE(activator.isMenuContentActive(10), false);
260+
261+ m_fakeTimeSource->emitTimeout();
262+ QCOMPARE(activator.isMenuContentActive(3), false);
263+ QCOMPARE(activator.isMenuContentActive(4), true);
264+ QCOMPARE(activator.isMenuContentActive(5), true);
265+ QCOMPARE(activator.isMenuContentActive(6), true);
266+ QCOMPARE(activator.isMenuContentActive(7), true);
267+ QCOMPARE(activator.isMenuContentActive(8), true);
268+ QCOMPARE(activator.isMenuContentActive(9), true);
269+ QCOMPARE(activator.isMenuContentActive(10), false);
270+
271+ m_fakeTimeSource->emitTimeout();
272+ QCOMPARE(activator.isMenuContentActive(3), false);
273+ QCOMPARE(activator.isMenuContentActive(4), true);
274+ QCOMPARE(activator.isMenuContentActive(5), true);
275+ QCOMPARE(activator.isMenuContentActive(6), true);
276+ QCOMPARE(activator.isMenuContentActive(7), true);
277+ QCOMPARE(activator.isMenuContentActive(8), true);
278+ QCOMPARE(activator.isMenuContentActive(9), true);
279+ QCOMPARE(activator.isMenuContentActive(10), true);
280+ QCOMPARE(activator.isMenuContentActive(11), false);
281+ }
282+
283+ void onDeltaChange(int delta)
284+ {
285+ m_deltas << delta;
286+ }
287+
288+private:
289+ QList<int> getIndexList(MenuContentActivator* activator)
290+ {
291+ QList<int> list;
292+ Q_FOREACH(int delta, m_deltas) {
293+ list << (activator->baseIndex() + delta);
294+ }
295+ return list;
296+ }
297+
298+ FakeTimer* m_fakeTimeSource;
299+ QList<int> m_deltas;
300+};
301+
302+QTEST_MAIN(MenuConentActivatorTest)
303+#include "menucontentactivatortest.moc"
tests/qmltests/CMakeLists.txt−2
@@ -61,10 +61,8 @@ add_qml_test(Notifications Notifications IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_P
6161add_qml_test(Panel IndicatorRow)
6262add_qml_test(Panel Indicators IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
6363add_qml_test(Panel MenuContent)
64−add_qml_test(Panel Overview)
6564add_qml_test(Panel Panel IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
6665add_qml_test(Panel SearchIndicator)
67−add_qml_test(Panel/Menus IndicatorMenuWindow IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS})
6866add_qml_test(SideStage SideStage IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS}
6967 ${CMAKE_BINARY_DIR}/tests/mocks
7068 ${CMAKE_BINARY_DIR}/plugins)
tests/qmltests/Notifications/tst_Notifications.qml+20−9
@@ -48,6 +48,7 @@ Row {
4848 function addSnapDecisionNotification() {
4949 var n = {
5050 type: Notification.SnapDecision,
51+ hints: Notification.ButtonTint,
5152 summary: "Tom Ato",
5253 body: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.",
5354 icon: "../graphics/avatars/funky.png",
@@ -189,8 +190,9 @@ Row {
189190 function test_NotificationRenderer_data() {
190191 return [
191192 {
192− tag: "Snap Decision with secondary icon",
193+ tag: "Snap Decision with secondary icon and button-tint",
193194 type: Notification.SnapDecision,
195+ hints: Notification.ButtonTint,
194196 summary: "Tom Ato",
195197 body: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.",
196198 icon: "../graphics/avatars/funky.png",
@@ -205,7 +207,8 @@ Row {
205207 interactiveAreaEnabled: false,
206208 iconVisible: true,
207209 secondaryIconVisible: true,
208− buttonRowVisible: true
210+ buttonRowVisible: true,
211+ buttonTinted: true
209212 },
210213 {
211214 tag: "Ephemeral notification - icon-summary layout",
@@ -220,7 +223,8 @@ Row {
220223 interactiveAreaEnabled: false,
221224 iconVisible: false,
222225 secondaryIconVisible: true,
223− buttonRowVisible: false
226+ buttonRowVisible: false,
227+ buttonTinted: false
224228 },
225229 {
226230 tag: "Ephemeral notification - check suppression of secondary icon for icon-summary layout",
@@ -235,7 +239,8 @@ Row {
235239 interactiveAreaEnabled: false,
236240 iconVisible: false,
237241 secondaryIconVisible: true,
238− buttonRowVisible: false
242+ buttonRowVisible: false,
243+ buttonTinted: false
239244 },
240245 {
241246 tag: "Interactive notification",
@@ -250,10 +255,11 @@ Row {
250255 interactiveAreaEnabled: true,
251256 iconVisible: true,
252257 secondaryIconVisible: false,
253− buttonRowVisible: false
258+ buttonRowVisible: false,
259+ buttonTinted: false
254260 },
255261 {
256− tag: "Snap Decision without secondary icon",
262+ tag: "Snap Decision without secondary icon and no button-tint",
257263 type: Notification.SnapDecision,
258264 summary: "Bro Coly",
259265 body: "At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.",
@@ -266,7 +272,8 @@ Row {
266272 interactiveAreaEnabled: false,
267273 iconVisible: true,
268274 secondaryIconVisible: false,
269− buttonRowVisible: true
275+ buttonRowVisible: true,
276+ buttonTinted: false
270277 },
271278 {
272279 tag: "Ephemeral notification",
@@ -281,7 +288,8 @@ Row {
281288 interactiveAreaEnabled: false,
282289 iconVisible: true,
283290 secondaryIconVisible: true,
284− buttonRowVisible: false
291+ buttonRowVisible: false,
292+ buttonTinted: false
285293 }
286294 ]
287295 }
@@ -356,6 +364,9 @@ Row {
356364 actionSpy.clear()
357365 }
358366
367+ // check the tinting of the positive/right button
368+ verify(buttonAccept.gradient === data.buttonTinted ? UbuntuColors.orangeGradient : UbuntuColors.greyGradient, "button has the wrong color-tint")
369+
359370 // click the positive/right button
360371 mouseClick(buttonAccept, buttonAccept.width / 2, buttonAccept.height / 2)
361372 actionSpy.wait()
@@ -370,7 +381,7 @@ Row {
370381 mouseClick(buttonCancel, buttonCancel.width / 2, buttonCancel.height / 2)
371382 waitForRendering(notification)
372383 actionSpy.clear()
373− 
384+
374385 // test the additional buttons
375386 for (var i = 2; i < data.actions.length; i++) {
376387 waitForRendering(notification)
tests/qmltests/Panel/Menus/tst_IndicatorMenuWindow.qmldeleted−68
@@ -1,68 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import QtTest 1.0
19−import "../.."
20−import "../../../../Panel/Menus"
21−import Ubuntu.Components 0.1
22−import Unity.Test 0.1 as UT
23−
24−Item {
25− id: testIndicatorMenuWindowItem
26− width: units.gu(9)
27− height: units.gu(3)
28−
29− MouseArea {
30− id: mouseArea
31− anchors.fill: parent
32− }
33−
34− IndicatorMenuWindow {
35− id: indicatorMenuWindow
36− name: "TestIndicatorMenuWindow"
37− anchors.fill: parent
38− }
39−
40− UT.UnityTestCase {
41− name: "IndicatorMenuWindow"
42− when: windowShown
43−
44− function test_mouseEvent_data() {
45− return [
46− {tag: "visible", shown: true, opacity: 1.0, mouseClicks: 0},
47− {tag: "invisible", shown: false, opacity: 0.0, mouseClicks: 1},
48− ]
49− }
50−
51− function test_mouseEvent(data) {
52− indicatorMenuWindow.shown = data.shown
53− tryCompare(indicatorMenuWindow, "opacity", data.opacity)
54−
55− clickedSpy.clear()
56− mouseClick(indicatorMenuWindow, indicatorMenuWindow.width / 2,
57− indicatorMenuWindow.height / 2)
58− compare(clickedSpy.count, data.mouseClicks,
59− "Check for Mouse event eating by indicatorMenuWindow failed")
60− }
61− }
62−
63− SignalSpy {
64− id: clickedSpy
65− target: mouseArea
66− signalName: "clicked"
67− }
68−}
tests/qmltests/Panel/tst_IndicatorRow.qml−14
@@ -32,7 +32,6 @@ Item {
3232
3333 function init_test()
3434 {
35− indicatorRow.overviewActive = false;
3635 indicatorRow.state = "initial";
3736 indicatorRow.currentItem = null;
3837 }
@@ -241,18 +240,5 @@ Item {
241240 compare(get_indicator_item_at(3).dimmed, true, "Other indicators should dim when in locked state");
242241 compare(get_indicator_item_at(4).dimmed, true, "Other indicators should dim when in locked state");
243242 }
244−
245− function test_active_overview() {
246− init_test();
247−
248− indicatorRow.overviewActive = true;
249− indicatorRow.state = "commit";
250−
251− compare(get_indicator_item_at(0).dimmed, true, "Indicator should dim when in overview");
252− compare(get_indicator_item_at(1).dimmed, true, "Indicator should dim when in overview");
253− compare(get_indicator_item_at(2).dimmed, true, "Indicator should dim when in overview");
254− compare(get_indicator_item_at(3).dimmed, true, "Indicator should dim when in overview");
255− compare(get_indicator_item_at(4).dimmed, true, "Indicator should dim when in overview");
256− }
257243 }
258244}
tests/qmltests/Panel/tst_Indicators.qml+1−39
@@ -69,7 +69,6 @@ Item {
6969
7070 onClicked: {
7171 if (!indicators.shown) {
72− indicators.openOverview();
7372 indicators.show();
7473 } else {
7574 indicators.hide();
@@ -89,47 +88,10 @@ Item {
8988 tryCompare(indicators, "state", "initial");
9089 }
9190
92− // Showing the indicators should fully open the indicator panel with the overview menu visible.
91+ // Showing the indicators should fully open the indicator panel.
9392 function test_show() {
9493 indicators.show()
9594 tryCompare(indicators, "fullyOpened", true);
96−
97− // A show must open the indicators.
98− compare(findChild(indicators, "indicatorRow").overviewActive, true, "Overview indicator should be active when opened overview.")
99− }
100−
101− // Opening the overview menu will activate the overview panel.
102− function test_open_overview() {
103− indicators.openOverview();
104− compare(findChild(indicators, "indicatorRow").overviewActive, true, "Overview should be active when opened overview.")
105− }
106−
107− // Showing the indicators, then changing the progress (simulating drag) should keep the overview panel open until
108− // the reveal state is reached.
109− function test_slow_close_open_overview() {
110−
111− var indicator_row = findChild(indicators, "indicatorRow");
112− verify(indicator_row != undefined);
113−
114− indicators.show()
115− // wait for animation to end. (progress needs to be updated)
116− tryCompare(indicators.showAnimation, "running", false);
117− compare(indicator_row.overviewActive, true, "Overview should be active when opened overview.")
118−
119− // iteratively decrease the progress and ensure that it keeps the correct behaviour
120− var current_progress = indicators.progress - shell.height/20;
121− while (current_progress > 0) {
122− indicators.progress = current_progress;
123−
124− if (indicators.state == "commit" || indicators.state == "locked") {
125− compare(indicator_row.overviewActive, true, "Overview should be active when in locked or commit state after show.")
126− }
127− else if (indicators.state == "reveal" || indicators.state == "hint") {
128− compare(indicator_row.overviewActive, false, "Overview should be not active when not in commit or locked state.")
129− }
130−
131− current_progress = current_progress - shell.height/20;
132− }
13395 }
13496
13597 // Test the change in the revealer lateral position changes the current panel menu to fit the position
tests/qmltests/Panel/tst_MenuContent.qml+10−80
@@ -52,8 +52,8 @@ Item {
5252 height: parent.height - 50
5353 }
5454
55− Item {
56− id: click_me
55+ Rectangle {
56+ color: "#bbbbbb"
5757
5858 height: 50
5959 anchors {
@@ -62,50 +62,16 @@ Item {
6262 right: parent.right
6363 }
6464
65− Rectangle {
66− color: "#999999"
67−
68− anchors {
69− top: parent.top
70− left: parent.left
71− right: parent.horizontalCenter
72− bottom: parent.bottom
73− }
74−
75− Text {
76− text: "Devices"
77− anchors.fill: parent
78− horizontalAlignment: Text.AlignHCenter
79− verticalAlignment: Text.AlignVCenter
80− }
81−
82− MouseArea {
83− anchors.fill: parent
84− onClicked: menuContent.showOverview()
85− }
65+ Text {
66+ text: "Next Indicator"
67+ anchors.fill: parent
68+ horizontalAlignment: Text.AlignHCenter
69+ verticalAlignment: Text.AlignVCenter
8670 }
8771
88− Rectangle {
89− color: "#bbbbbb"
90−
91− anchors {
92− top: parent.top
93− left: parent.horizontalCenter
94− right: parent.right
95− bottom: parent.bottom
96− }
97−
98− Text {
99− text: "Next Indicator"
100− anchors.fill: parent
101− horizontalAlignment: Text.AlignHCenter
102− verticalAlignment: Text.AlignVCenter
103− }
104−
105− MouseArea {
106− anchors.fill: parent
107− onClicked: activate_next_content()
108− }
72+ MouseArea {
73+ anchors.fill: parent
74+ onClicked: activate_next_content()
10975 }
11076 }
11177
@@ -120,7 +86,6 @@ Item {
12086 function activate_content(index)
12187 {
12288 menuContent.currentIndex = index
123− menuContent.showMenu();
12489 }
12590
12691 function get_test_menu_objecName(index) {
@@ -151,7 +116,6 @@ Item {
151116 when: windowShown
152117
153118 function init() {
154− menuContent.hideAll();
155119 if (menuContent.__contentActive)
156120 menuContent.releaseContent();
157121 tryCompare(menuContent, "__contentActive", false);
@@ -174,40 +138,6 @@ Item {
174138 compare(menus.currentIndex, menu_index, "Current menu index does not match selected menu index");
175139 tryCompareFunction(current_menu_equals_test_menu, true);
176140 }
177− // overview should not be visible.
178− tryCompare(findChild(menuContent, "overview"), "visible", false);
179− }
180−
181− function test_show_overview() {
182− menuContent.showOverview();
183−
184− var overview = findChild(menuContent, "overview");
185− tryCompare(overview, "visible", true);
186− tryCompare(overview, "enabled", true);
187− tryCompare(overview, "opacity", 1.0);
188−
189− // menus should not be enabled.
190− tryCompare(findChild(menuContent, "menus"), "opacity", 0);
191− tryCompare(findChild(menuContent, "menus"), "enabled", false);
192− }
193−
194− function test_overview_menuSelected_signal() {
195− menuContent.showOverview();
196−
197− var overview = findChild(menuContent, "overview");
198− var menus = menu_content_test.findChild(menuContent, "menus")
199−
200− var menu_count = indicatorsModel.count;
201− verify(menu_count > 0, "Menu count should be greater than zero");
202− for (var i = 0; i < menu_count; i++) {
203− // manually emit signal from overview.
204− // we dont want to go with mouse events here, otherwise we're testing the overview and not the signal.
205− overview.menuSelected(i);
206−
207− test_menu_objectName = get_test_menu_objecName(i);
208− compare(menus.currentIndex, i, "Current menu index does not match selected menu index");
209− tryCompareFunction(current_menu_equals_test_menu, true);
210− }
211141 }
212142
213143 // Calling activateContent should call start on all menus
tests/qmltests/Panel/tst_Overview.qmldeleted−142
@@ -1,142 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import QtTest 1.0
19−import ".."
20−import "../../../Panel/Menus"
21−import "../../../Components"
22−import Unity.Test 0.1 as UT
23−import Unity.Indicators 0.1 as Indicators
24−
25−Rectangle {
26− id: shell
27− width: units.gu(40)
28− height: units.gu(80)
29− color: "black"
30−
31− Overview {
32− id: overview
33− anchors.fill: parent
34− indicatorsModel: mockModel
35− shown: true
36− }
37−
38− Item {
39− id: volumeControl
40− property int volume
41− function volumeUp() {
42− volume = Math.min(100, volume + 10);
43− }
44− function volumeDown() {
45− volume = Math.max(0, volume - 10);
46− }
47− }
48−
49− ListModel {
50− id: mockModel
51− ListElement {title: "fake1"; widgetSource: "qrc:/tests/indciators/qml/fake_menu_widget1.qml"; indicatorProperties: ""}
52− ListElement {title: "fake2"; widgetSource: "qrc:/tests/indciators/qml/fake_menu_widget2.qml"; indicatorProperties: ""}
53− ListElement {title: "fake3"; widgetSource: "qrc:/tests/indciators/qml/fake_menu_widget3.qml"; indicatorProperties: ""}
54− }
55−
56− ListModel {
57− id: mockModel2
58− }
59−
60− SignalSpy {
61− id: clickSpy
62− target: overview
63− signalName: "menuSelected"
64− }
65−
66− UT.UnityTestCase {
67− name: "Overview"
68− when: windowShown
69−
70− function initTestCase() {
71− // Spin the event loop once because the UI builds up delayed
72− wait(0);
73− }
74−
75− function test_menuSelected() {
76− overview.indicatorsModel = mockModel;
77−
78− for (var i = 0; i < mockModel.count; ++i) {
79− var button = findChild(overview, "overviewGridButton" + i);
80− clickSpy.clear();
81− mouseClick(button, button.width / 2, button.height / 2);
82− compare(clickSpy.count, 1, "Clicking on grid didn't work");
83− compare(clickSpy.signalArguments[0][0], i, "Clicking the grid returned a wrong index");
84− }
85− }
86−
87− function test_dynamic_addition() {
88− var overviewGrid = findChild(overview, "overviewGrid");
89−
90− for(var i = 0; i < mockModel.count; ++i) {
91− mockModel2.append(mockModel.get(i));
92− }
93− overview.indicatorsModel = mockModel2;
94− overviewGrid.forceLayout();
95− waitForRendering(overviewGrid);
96−
97− var button = findChild(overview, "overviewGridButton2");
98− verify(button !== undefined, "button2 wasn't found");
99− button = findChild(overview, "overviewGridButton3");
100− compare(button, undefined, "There should only be 3 buttons... found at least 4...");
101−
102− mockModel2.append({title: "humppa", widgetSource: "qrc:/tests/indciators/qml/fake_menu_widget4.qml", indicatorProperties: ""})
103− overviewGrid.forceLayout();
104− waitForRendering(overviewGrid);
105−
106− button = findChild(overview, "overviewGridButton3");
107− verify(button !== undefined, "button3 wasn't found");
108− }
109−
110− function test_volume_slider_data() {
111− return [
112− {tag: "0%", sliderPos:0},
113− {tag: "100%", sliderPos: 100},
114− {tag: "50%", sliderPos: 50}
115− ];
116− }
117−
118− function test_volume_slider(data) {
119− var volumeSlider = findChild(overview, "volumeSlider");
120− var startX = volumeSlider.width * volumeSlider.value / 100;
121− var startY = volumeSlider.y + volumeSlider.height / 2;
122− var stopX = (volumeSlider.width - units.gu(5)) * data.sliderPos / 100;
123− var stopY = volumeSlider.y + volumeSlider.height / 2;
124− mouseFlick(volumeSlider, startX, startY, stopX, stopY, true, true, 0.1);
125− }
126−
127− function test_volume_buttons(data) {
128− var volumeDownButton = findChild(overview, "minVolumeIcon");
129− var volumeUpButton = findChild(overview, "maxVolumeIcon");
130−
131− for (var i = 0; i < 10; ++i) {
132− mouseClick(volumeDownButton, volumeDownButton.width / 2, volumeDownButton.height / 2);
133− wait(0)
134− }
135− tryCompare(volumeControl, "volume", 0);
136− for (var i = 0; i < 10; ++i) {
137− mouseClick(volumeUpButton, 1, 1);
138− wait(0)
139− }
140− }
141− }
142−}
tests/qmltests/Panel/tst_Panel.qml+33−33
@@ -62,14 +62,14 @@ Item {
6262
6363 function get_indicator_item(index) {
6464 var row_repeater = findChild(panel.indicators, "rowRepeater");
65− verify(row_repeater != undefined)
65+ verify(row_repeater != undefined);
6666 return row_repeater.itemAt(index);
6767 }
6868
6969 function get_indicator_item_position(index) {
7070
7171 var indicator_row = findChild(panel.indicators, "indicatorRow");
72− verify(indicator_row != undefined)
72+ verify(indicator_row != undefined);
7373
7474 var indicator_item = get_indicator_item(index);
7575 verify(indicator_item != undefined);
@@ -83,11 +83,11 @@ Item {
8383 panel.fullscreenMode = false;
8484 // Wait for the indicators to get into position.
8585 // (switches between normal and fullscreen modes are animated)
86− tryCompare(panel.indicators, "y", 0)
86+ tryCompare(panel.indicators, "y", 0);
8787
8888 var indicator_item_coord = get_indicator_item_position(0);
8989
90− touchPress(panel, indicator_item_coord.x, panel.panelHeight / 2)
90+ touchPress(panel, indicator_item_coord.x, panel.panelHeight / 2);
9191
9292 // hint animation should be run, meaning that indicators will move downwards
9393 // by hintValue pixels without any drag taking place
@@ -96,7 +96,7 @@ Item {
9696 tryCompare(panel.indicators, "partiallyOpened", true);
9797 tryCompare(panel.indicators, "fullyOpened", false);
9898
99− touchRelease(panel, indicator_item_coord.x, panel.panelHeight/2)
99+ touchRelease(panel, indicator_item_coord.x, panel.panelHeight/2);
100100 }
101101
102102 // Pressing on the top edge of the screen should have no effect if the panel
@@ -105,31 +105,31 @@ Item {
105105 panel.fullscreenMode = true;
106106 // Wait for the indicators to get into position.
107107 // (switches between normal and fullscreen modes are animated)
108− tryCompare(panel.indicators, "y", -panel.panelHeight)
108+ tryCompare(panel.indicators, "y", -panel.panelHeight);
109109
110110 var indicator_item_coord = get_indicator_item_position(0);
111111
112− touchPress(panel, indicator_item_coord.x, panel.panelHeight / 2)
112+ touchPress(panel, indicator_item_coord.x, panel.panelHeight / 2);
113113
114114 // Give some time for a hint animation to change things, if any
115− wait(500)
115+ wait(500);
116116
117117 // no hint animation when fullscreen
118− compare(panel.indicators.y, -panel.panelHeight)
118+ compare(panel.indicators.y, -panel.panelHeight);
119119 var indicatorRow = findChild(panel.indicators, "indicatorRow");
120− verify(indicatorRow != undefined)
121− compare(indicatorRow.y, 0)
122− compare(panel.indicators.height, panel.indicators.panelHeight)
120+ verify(indicatorRow != undefined);
121+ compare(indicatorRow.y, 0);
122+ compare(panel.indicators.height, panel.indicators.panelHeight);
123123 compare(panel.indicators.partiallyOpened, false,
124124 "Indicator should not be partially opened when panel is pressed in" +
125− " fullscreenmode")
125+ " fullscreenmode");
126126 compare(panel.indicators.fullyOpened, false, "Indicator should not be partially" +
127− " opened when panel is pressed in fullscreenmode")
127+ " opened when panel is pressed in fullscreenmode");
128128
129− touchRelease(panel, indicator_item_coord.x, panel.panelHeight/2)
129+ touchRelease(panel, indicator_item_coord.x, panel.panelHeight/2);
130130 }
131131
132− function test_drag_show_data() { return get_window_data() }
132+ function test_drag_show_data() { return get_window_data(); }
133133
134134 // Dragging from a indicator item in the panel will gradually expose the
135135 // indicators, first by running the hint animation, then after dragging down will
@@ -138,50 +138,50 @@ Item {
138138 panel.fullscreenMode = data.fullscreenFlag;
139139
140140 var indicator_row = findChild(panel.indicators, "indicatorRow");
141− verify(indicator_row != undefined)
141+ verify(indicator_row != undefined);
142142
143143 var row_repeater = findChild(panel.indicators, "rowRepeater");
144− verify(indicator_row != undefined)
144+ verify(indicator_row != undefined);
145145
146146 var menu_content = findChild(panel.indicators, "menuContent");
147− verify(indicator_row != undefined)
147+ verify(indicator_row != undefined);
148148
149149 // Wait for the indicators to get into position.
150150 // (switches between normal and fullscreen modes are animated)
151151 if (data.fullscreenFlag) {
152− tryCompare(panel.indicators, "y", -panel.panelHeight)
152+ tryCompare(panel.indicators, "y", -panel.panelHeight);
153153 } else {
154− tryCompare(panel.indicators, "y", 0)
154+ tryCompare(panel.indicators, "y", 0);
155155 }
156156
157157 // do this for each indicator item
158158 for (var i = 0; i < row_repeater.count; i++) {
159159
160160 var indicator_item = get_indicator_item(i);
161− verify(indicator_item != undefined)
161+ verify(indicator_item != undefined);
162162
163163 var indicator_item_coord = get_indicator_item_position(i);
164164
165165 touchPress(panel,
166− indicator_item_coord.x, panel.panelHeight / 2)
166+ indicator_item_coord.x, panel.panelHeight / 2);
167167
168168 // 1) Drag the mouse down
169169 touchFlick(panel,
170170 indicator_item_coord.x, panel.panelHeight / 2,
171171 indicator_item_coord.x, panel.height * 0.8,
172− false /* beginTouch */, false /* endTouch */)
172+ false /* beginTouch */, false /* endTouch */);
173173
174174 // Indicators height should follow the drag, and therefore increase accordingly.
175175 // They should be at least half-way through the screen
176176 tryCompareFunction(
177177 function() {return panel.indicators.height >= panel.height * 0.5},
178− true)
178+ true);
179179
180− touchRelease(panel, indicator_item_coord.x, panel.height * 0.8)
180+ touchRelease(panel, indicator_item_coord.x, panel.height * 0.8);
181181
182182 compare(indicator_row.currentItem, indicator_item,
183− "Incorrect item activated at position " + i)
184− compare(menu_content.__shown, true, "Menu conetent should be enabled for item at position " + i);
183+ "Incorrect item activated at position " + i);
184+ compare(menu_content.currentIndex, i, "Menu conetent should be enabled for item at position " + i);
185185
186186 // init for next indicator_item
187187 init();
@@ -195,23 +195,23 @@ Item {
195195 var search_indicator = findChild(panel, "search");
196196 verify(search_indicator != undefined);
197197
198− tap(search_indicator, 1, 1)
198+ tap(search_indicator, 1, 1);
199199
200200 compare(search_clicked, true,
201− "Tapping search indicator while it was enabled did not emit searchClicked signal")
201+ "Tapping search indicator while it was enabled did not emit searchClicked signal");
202202 }
203203
204204 function test_search_click_when_not_visible() {
205205 panel.fullscreenMode = false;
206− panel.searchVisible = false
206+ panel.searchVisible = false;
207207
208208 var search_indicator = findChild(panel, "search");
209209 verify(search_indicator != undefined);
210210
211− tap(search_indicator, 1, 1)
211+ tap(search_indicator, 1, 1);
212212
213213 compare(search_clicked, false,
214− "Tapping search indicator while it was not visible emitted searchClicked signal")
214+ "Tapping search indicator while it was not visible emitted searchClicked signal");
215215 }
216216 }
217217}