on xenial help sign in
Merge trunk.
f2d60dbMichał Sawicz
CMakeLists.txt+5−5
@@ -48,11 +48,11 @@ add_custom_target(cppcheck COMMAND cppcheck --enable=all -q --error-exitcode=2
48 ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/tests)
48 ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/tests)
49
49
50include(FindPkgConfig)
50include(FindPkgConfig)
51−find_package(Qt5Core)
51+find_package(Qt5Core 5.2 REQUIRED)
52−find_package(Qt5Qml)
52+find_package(Qt5Qml 5.2 REQUIRED)
53−find_package(Qt5Quick)
53+find_package(Qt5Quick 5.2 REQUIRED)
54−find_package(Qt5Gui)
54+find_package(Qt5Gui 5.2 REQUIRED)
55−find_package(Qt5DBus)
55+find_package(Qt5DBus 5.2 REQUIRED)
56
56
57# Standard install paths
57# Standard install paths
58include(GNUInstallDirs)
58include(GNUInstallDirs)
CODING+11−11
@@ -20,7 +20,7 @@ install dependencies
20If its your first time, install build dependencies
20If its your first time, install build dependencies
21
21
22$ cd ~/unity8/trunk
22$ cd ~/unity8/trunk
23−$ ./build --setup
23+$ ./build.sh --setup
24
24
25 this will:
25 this will:
26 - install the required dependencies to build, as well as run on the desktop
26 - install the required dependencies to build, as well as run on the desktop
@@ -31,7 +31,7 @@ build Unity 8
31-------------
31-------------
32
32
33$ cd ~/unity8/trunk
33$ cd ~/unity8/trunk
34−$ ./build
34+$ ./build.sh
35
35
36You may also rebuild with the -c for clean, which just deletes the build
36You may also rebuild with the -c for clean, which just deletes the build
37directory.
37directory.
@@ -43,10 +43,10 @@ Running Unity 8 on your desktop
43run the Unity 8 shell
43run the Unity 8 shell
44---------------------
44---------------------
45$ cd ~/unity8/trunk
45$ cd ~/unity8/trunk
46−$ ./run
46+$ ./run.sh
47
47
48Options can be passed to test the lock screen
48Options can be passed to test the lock screen
49−$ ./run -p OR -k
49+$ ./run.sh -p OR -k
50
50
51-p is for pin lock, for which the default prompt answer is "1234"
51-p is for pin lock, for which the default prompt answer is "1234"
52-k is for keylock passphrase, for which the default prompt answer is "password"
52-k is for keylock passphrase, for which the default prompt answer is "password"
@@ -78,19 +78,19 @@ Running Unity 8 on devices
78 on the device yourself)
78 on the device yourself)
79
79
80$ cd ~/unity/trunk
80$ cd ~/unity/trunk
81−$ ./run_on_device --setup
81+$ ./run_on_device.sh --setup
82 this will:
82 this will:
83 - install your public SSH key on the device
83 - install your public SSH key on the device
84 - install the needed dependencies
84 - install the needed dependencies
85
85
86−$ ./run_on_device
86+$ ./run_on_device.sh
87 this will:
87 this will:
88 - rsync the code to the device
88 - rsync the code to the device
89 - build on the device
89 - build on the device
90 - replace the running shell
90 - replace the running shell
91
91
92Options can be passed to test the lock screen
92Options can be passed to test the lock screen
93−$ ./run_on_device -p OR -k
93+$ ./run_on_device.sh -p OR -k
94
94
95-p is for pin lock, for which the default prompt answer is "1234"
95-p is for pin lock, for which the default prompt answer is "1234"
96-k is for keylock passphrase, for which the default prompt answer is "password"
96-k is for keylock passphrase, for which the default prompt answer is "password"
@@ -107,9 +107,9 @@ Notes
107- exporting ANDROID_SERIAL=$your_device_serial or
107- exporting ANDROID_SERIAL=$your_device_serial or
108 ANDROID_SERIAL=$your_device_ip:5555 will make adb not complain about
108 ANDROID_SERIAL=$your_device_ip:5555 will make adb not complain about
109 multiple devices
109 multiple devices
110−- you can export TARGET_IP=$your_device_ip TARGET_SSH_PORT=22 for run_on_device
110+- you can export TARGET_IP=$your_device_ip TARGET_SSH_PORT=22 for run_on_device.sh
111 to not use adb forwarding - useful if you use multiple devices
111 to not use adb forwarding - useful if you use multiple devices
112−- using Ninja (package ninja-build - run_on_device -s installs this now)
112+- using Ninja (package ninja-build - run_on_device.sh -s installs this now)
113 will improve build times (especially in the nothing-to-build case)
113 will improve build times (especially in the nothing-to-build case)
114
114
115
115
@@ -131,7 +131,7 @@ Running tests
131=============
131=============
132
132
133Tests are run from the build directory (which will be ./builddir if you used
133Tests are run from the build directory (which will be ./builddir if you used
134−the ./build script).
134+the ./build.sh script).
135
135
136To run the tests that do not require any graphical capability and therefore
136To run the tests that do not require any graphical capability and therefore
137are pretty fast run:
137are pretty fast run:
@@ -171,7 +171,7 @@ Running autopilot tests
171=======================
171=======================
172
172
173Autopilot tests are run from the build directory (which will be ./builddir if you used
173Autopilot tests are run from the build directory (which will be ./builddir if you used
174−the ./build script).
174+the ./build.sh script).
175
175
176$ make autopilot
176$ make autopilot
177
177
build → build.shrenamed+1−2
@@ -43,13 +43,12 @@ install_dependencies() {
43 gsettings-desktop-schemas \
43 gsettings-desktop-schemas \
44 gsettings-ubuntu-schemas \
44 gsettings-ubuntu-schemas \
45 qmenumodel-qml \
45 qmenumodel-qml \
46− qtdeclarative5-dee-plugin \
46+ qml-module-qtquick-xmllistmodel \
47 qtdeclarative5-gsettings1.0 \
47 qtdeclarative5-gsettings1.0 \
48 qtdeclarative5-ubuntu-ui-toolkit-plugin \
48 qtdeclarative5-ubuntu-ui-toolkit-plugin \
49 qtdeclarative5-ubuntu-settings-components \
49 qtdeclarative5-ubuntu-settings-components \
50 qtdeclarative5-ubuntu-thumbnailer0.1 \
50 qtdeclarative5-ubuntu-thumbnailer0.1 \
51 unity-notifications-impl \
51 unity-notifications-impl \
52− qtdeclarative5-xmllistmodel-plugin \
53 ubuntu-mobile-icons \
52 ubuntu-mobile-icons \
54 unity-scope-home \
53 unity-scope-home \
55 unity-lens-applications \
54 unity-lens-applications \
debian/changelog+72
@@ -1,3 +1,75 @@
1+unity8 (7.86+14.10.20140513-0ubuntu1) utopic; urgency=low
2+
3+ [ Andrea Cimitan ]
4+ * Improve padding in Text preview widget. (LP: #1316683)
5+
6+ [ CI bot ]
7+ * Resync trunk
8+
9+ [ Nick Dedekind ]
10+ * Removed binding loop from Unity.Indicators.MenuContentActivator
11+ Change handler for QMLListProperty used by MenuContent.qml:
12+ menuActivator.content[index].active If we're already asking for the
13+ index, we know it exists already. No need to send a
14+ changeNotification on an implied creation.
15+
16+ [ Josh Arenson ]
17+ * Implements usage-style documentation for unity8 executable. Fixes
18+ lp:1269282 (LP: #1269282)
19+
20+ [ Albert Astals ]
21+ * Create specialized Card code in Javascript instead of having various
22+ copied&pasted files (LP: #1297197)
23+
24+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 13 May 2014 08:34:02 +0000
25+
26+unity8 (7.86+14.10.20140507.3-0ubuntu1) utopic; urgency=low
27+
28+ [ Michał Sawicz ]
29+ * Remove HUD from the bottom edge. Again.
30+
31+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 07 May 2014 11:14:30 +0000
32+
33+unity8 (7.86+14.10.20140505-0ubuntu1) utopic; urgency=low
34+
35+ [ Ted Gould ]
36+ * Provide a dbus interface for setting the count and countVisible
37+ properties. (LP: #1301400)
38+
39+ [ Michał Sawicz ]
40+ * Pass env variables to initctl start.
41+ * Suffix .sh to our scripts and clean up debian/rules.
42+ * Adapt to Debian Qt package renames and drop unneeded Dee plugin
43+ dependency.
44+
45+ [ Ying-Chun Liu ]
46+ * Add Zoomable Image for Preview widgets.
47+
48+ [ Albert Astals ]
49+ * Remove support for Qt <= 5.2.1
50+
51+ [ Mirco Müller ]
52+ * Implemented feature-request from Design for modal snap-decision
53+ notifications on the phone. See LP #1285712 (LP: #1285712)
54+
55+ [ Andrea Cimitan ]
56+ * Make progressbas in preview widget big as the button
57+
58+ [ CI bot ]
59+ * Resync trunk
60+
61+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 05 May 2014 12:09:43 +0000
62+
63+unity8 (7.86+14.10.20140502.6-0ubuntu1) utopic; urgency=low
64+
65+ [ tpeeters ]
66+ * Adapt to new TabBar
67+
68+ [ Tim Peeters ]
69+ * Adapt to new TabBar
70+
71+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Fri, 02 May 2014 16:44:52 +0000
72+
1unity8 (7.86+14.10.20140429.2-0ubuntu1) utopic; urgency=medium
73unity8 (7.86+14.10.20140429.2-0ubuntu1) utopic; urgency=medium
2
74
3 [ Andrea Cimitan ]
75 [ Andrea Cimitan ]
debian/control+9−10
@@ -26,19 +26,19 @@ Build-Depends: cmake,
26 python3-all:any,
26 python3-all:any,
27 python3-setuptools,
27 python3-setuptools,
28 python:any (>= 2.7),
28 python:any (>= 2.7),
29+ qml-module-qtquick-xmllistmodel,
30+ qml-module-qtquick2,
31+ qml-module-qttest,
29 qt5-default,
32 qt5-default,
30− qtbase5-dev,
33+ qtbase5-dev (>= 5.2.1),
31 qtbase5-dev-tools,
34 qtbase5-dev-tools,
32− qtbase5-private-dev,
35+ qtbase5-private-dev (>= 5.2.1),
33− qtdeclarative5-dev,
36+ qtdeclarative5-dev (>= 5.2.1),
34 qtdeclarative5-dev-tools,
37 qtdeclarative5-dev-tools,
35− qtdeclarative5-private-dev,
38+ qtdeclarative5-private-dev (>= 5.2.1),
36 qtdeclarative5-qtmultimedia-plugin,
39 qtdeclarative5-qtmultimedia-plugin,
37− qtdeclarative5-qtquick2-plugin,
38− qtdeclarative5-test-plugin,
39 qtdeclarative5-ubuntu-settings-components,
40 qtdeclarative5-ubuntu-settings-components,
40 qtdeclarative5-ubuntu-ui-toolkit-plugin,
41 qtdeclarative5-ubuntu-ui-toolkit-plugin,
41− qtdeclarative5-xmllistmodel-plugin,
42 ttf-ubuntu-font-family,
42 ttf-ubuntu-font-family,
43Standards-Version: 3.9.4
43Standards-Version: 3.9.4
44Homepage: http://launchpad.net/unity
44Homepage: http://launchpad.net/unity
@@ -76,10 +76,9 @@ Depends: gsettings-desktop-schemas,
76 libglib2.0-bin,
76 libglib2.0-bin,
77 libunity-mir1 (>= 0.4),
77 libunity-mir1 (>= 0.4),
78 qmenumodel-qml (>= 0.2.7),
78 qmenumodel-qml (>= 0.2.7),
79− qtdeclarative5-dee-plugin,
79+ qml-module-qtquick-xmllistmodel,
80 qtdeclarative5-gsettings1.0,
80 qtdeclarative5-gsettings1.0,
81 qtdeclarative5-ubuntu-settings-components,
81 qtdeclarative5-ubuntu-settings-components,
82− qtdeclarative5-xmllistmodel-plugin,
83 unity-launcher-impl-3,
82 unity-launcher-impl-3,
84 unity8-common (= ${source:Version}),
83 unity8-common (= ${source:Version}),
85 unity8-private (= ${binary:Version}),
84 unity8-private (= ${binary:Version}),
@@ -102,7 +101,7 @@ Depends: qtdeclarative5-ubuntu-thumbnailer0.1 | ubuntu-thumbnailer-impl,
102 qtdeclarative5-unity-notifications-plugin | unity-notifications-impl,
101 qtdeclarative5-unity-notifications-plugin | unity-notifications-impl,
103 ubuntu-thumbnailer-impl-0,
102 ubuntu-thumbnailer-impl-0,
104 unity-application-impl-2,
103 unity-application-impl-2,
105− unity-notifications-impl-2,
104+ unity-notifications-impl-3,
106 unity-plugin-scopes | unity-scopes-impl,
105 unity-plugin-scopes | unity-scopes-impl,
107 unity-scopes-impl-0,
106 unity-scopes-impl-0,
108 unity8-fake-env | unity-application-impl,
107 unity8-fake-env | unity-application-impl,
debian/rules+1−2
@@ -6,8 +6,7 @@
6export DPKG_GENSYMBOLS_CHECK_LEVEL=4
6export DPKG_GENSYMBOLS_CHECK_LEVEL=4
7export NO_PNG_PKG_MANGLE=1
7export NO_PNG_PKG_MANGLE=1
8
8
9−.PHONY: build
10−build %:
9+%:
11 dh $@ --parallel --fail-missing --with python2,python3
10 dh $@ --parallel --fail-missing --with python2,python3
12
11
13override_dh_auto_clean:
12override_dh_auto_clean:
debian/unity8-private.install+1−1
@@ -1,5 +1,5 @@
1usr/lib/*/unity8/qml/AccountsService
1usr/lib/*/unity8/qml/AccountsService
2−usr/lib/*/unity8/qml/DashViews
2+usr/lib/*/unity8/qml/Dash
3usr/lib/*/unity8/qml/HudClient
3usr/lib/*/unity8/qml/HudClient
4usr/lib/*/unity8/qml/LightDM
4usr/lib/*/unity8/qml/LightDM
5usr/lib/*/unity8/qml/Powerd
5usr/lib/*/unity8/qml/Powerd
debian/unity8.install−1
@@ -1,7 +1,6 @@
1data/unity8.conf usr/share/upstart/sessions/
1data/unity8.conf usr/share/upstart/sessions/
2usr/bin/unity8
2usr/bin/unity8
3usr/share/applications/unity8.desktop
3usr/share/applications/unity8.desktop
4−usr/share/unity8/Bottombar
5usr/share/unity8/Greeter
4usr/share/unity8/Greeter
6usr/share/unity8/Hud
5usr/share/unity8/Hud
7usr/share/unity8/Launcher
6usr/share/unity8/Launcher
plugins/CMakeLists.txt+1−1
@@ -14,7 +14,7 @@ endmacro()
14add_subdirectory(AccountsService)
14add_subdirectory(AccountsService)
15add_subdirectory(HudClient)
15add_subdirectory(HudClient)
16add_subdirectory(LightDM)
16add_subdirectory(LightDM)
17−add_subdirectory(DashViews)
17+add_subdirectory(Dash)
18add_subdirectory(Powerd)
18add_subdirectory(Powerd)
19add_subdirectory(SessionBroadcast)
19add_subdirectory(SessionBroadcast)
20add_subdirectory(Ubuntu)
20add_subdirectory(Ubuntu)
plugins/DashViews/CMakeLists.txt → plugins/Dash/CMakeLists.txtrenamed+4−4
@@ -27,15 +27,15 @@ set(QMLPLUGIN_SRC
27 organicgrid.cpp
27 organicgrid.cpp
28 )
28 )
29
29
30−add_library(DashViews-qml MODULE
30+add_library(Dash-qml MODULE
31 ${QMLPLUGIN_SRC}
31 ${QMLPLUGIN_SRC}
32 )
32 )
33
33
34−target_link_libraries(DashViews-qml
34+target_link_libraries(Dash-qml
35 ${Qt5Gui_LIBRARIES}
35 ${Qt5Gui_LIBRARIES}
36 ${Qt5Quick_LIBRARIES}
36 ${Qt5Quick_LIBRARIES}
37 )
37 )
38
38
39−qt5_use_modules(DashViews-qml Qml Quick)
39+qt5_use_modules(Dash-qml Qml Quick)
40
40
41−add_unity8_plugin(DashViews 0.1 DashViews TARGETS DashViews-qml)
41+add_unity8_plugin(Dash 0.1 Dash TARGETS Dash-qml)
plugins/Dash/CardCreator.jsnew file+518
@@ -0,0 +1,518 @@
1+/*
2+ * Copyright (C) 2014 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+.pragma library
18+
19+var kBackgroundLoaderCode = 'Loader {\n\
20+ id: backgroundLoader; \n\
21+ objectName: "backgroundLoader"; \n\
22+ anchors.fill: parent; \n\
23+ asynchronous: root.asynchronous; \n\
24+ visible: status == Loader.Ready; \n\
25+ sourceComponent: UbuntuShape { \n\
26+ objectName: "background"; \n\
27+ radius: "medium"; \n\
28+ color: getColor(0) || "white"; \n\
29+ gradientColor: getColor(1) || color; \n\
30+ anchors.fill: parent; \n\
31+ image: backgroundImage.source ? backgroundImage : null; \n\
32+ property real luminance: 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b; \n\
33+ property Image backgroundImage: Image { \n\
34+ objectName: "backgroundImage"; \n\
35+ source: { \n\
36+ if (cardData && typeof cardData["background"] === "string") return cardData["background"]; \n\
37+ else if (template && typeof template["card-background"] === "string") return template["card-background"]; \n\
38+ else return ""; \n\
39+ } \n\
40+ } \n\
41+ function getColor(index) { \n\
42+ if (cardData && typeof cardData["background"] === "object" \n\
43+ && (cardData["background"]["type"] === "color" || cardData["background"]["type"] === "gradient")) { \n\
44+ return cardData["background"]["elements"][index]; \n\
45+ } else if (template && typeof template["card-background"] === "object" \n\
46+ && (template["card-background"]["type"] === "color" || template["card-background"]["type"] === "gradient")) { \n\
47+ return template["card-background"]["elements"][index]; \n\
48+ } else return undefined; \n\
49+ } \n\
50+ } \n\
51+ }\n';
52+
53+// %1 is used as anchors of artShapeHolder
54+// %2 is used as image width
55+// %3 is used as image height
56+var kArtShapeHolderCode = 'Item { \n\
57+ id: artShapeHolder; \n\
58+ height: root.fixedArtShapeSize.height != -1 ? root.fixedArtShapeSize.height : artShapeLoader.height; \n\
59+ width: root.fixedArtShapeSize.width != -1 ? root.fixedArtShapeSize.width : artShapeLoader.width; \n\
60+ anchors { %1 } \n\
61+ Loader { \n\
62+ id: artShapeLoader; \n\
63+ objectName: "artShapeLoader"; \n\
64+ active: cardData && cardData["art"] || false; \n\
65+ asynchronous: root.asynchronous; \n\
66+ visible: status == Loader.Ready; \n\
67+ sourceComponent: UbuntuShape { \n\
68+ id: artShape; \n\
69+ objectName: "artShape"; \n\
70+ radius: "medium"; \n\
71+ readonly property real aspect: components !== undefined ? components["art"]["aspect-ratio"] : 1; \n\
72+ readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect; \n\
73+ Component.onCompleted: updateWidthHeightBindings(); \n\
74+ onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings(); \n\
75+ visible: image.status == Image.Ready; \n\
76+ function updateWidthHeightBindings() { \n\
77+ if (aspectSmallerThanImageAspect) { \n\
78+ width = Qt.binding(function() { return !visible ? 0 : image.width }); \n\
79+ height = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.height : width / image.aspect }); \n\
80+ } else { \n\
81+ width = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.width : height * image.aspect }); \n\
82+ height = Qt.binding(function() { return !visible ? 0 : image.height }); \n\
83+ } \n\
84+ } \n\
85+ image: Image { \n\
86+ objectName: "artImage"; \n\
87+ source: cardData && cardData["art"] || ""; \n\
88+ cache: true; \n\
89+ asynchronous: root.asynchronous; \n\
90+ fillMode: components && components["art"]["fill-mode"] === "fit" ? Image.PreserveAspectFit: Image.PreserveAspectCrop; \n\
91+ readonly property real aspect: implicitWidth / implicitHeight; \n\
92+ width: %2; \n\
93+ height: %3; \n\
94+ } \n\
95+ } \n\
96+ } \n\
97+ }\n';
98+
99+var kOverlayLoaderCode = 'Loader { \n\
100+ id: overlayLoader; \n\
101+ anchors { \n\
102+ left: artShapeHolder.left; \n\
103+ right: artShapeHolder.right; \n\
104+ bottom: artShapeHolder.bottom; \n\
105+ } \n\
106+ active: artShapeLoader.active && artShapeLoader.item && artShapeLoader.item.image.status === Image.Ready || false; \n\
107+ asynchronous: root.asynchronous; \n\
108+ visible: showHeader && status == Loader.Ready; \n\
109+ sourceComponent: ShaderEffect { \n\
110+ id: overlay; \n\
111+ height: fixedHeaderHeight != -1 ? fixedHeaderHeight : headerHeight; \n\
112+ opacity: 0.6; \n\
113+ property var source: ShaderEffectSource { \n\
114+ id: shaderSource; \n\
115+ sourceItem: artShapeLoader.item; \n\
116+ onVisibleChanged: if (visible) scheduleUpdate(); \n\
117+ live: false; \n\
118+ sourceRect: Qt.rect(0, artShapeLoader.height - overlay.height, artShapeLoader.width, overlay.height); \n\
119+ } \n\
120+ vertexShader: " \n\
121+ uniform highp mat4 qt_Matrix; \n\
122+ attribute highp vec4 qt_Vertex; \n\
123+ attribute highp vec2 qt_MultiTexCoord0; \n\
124+ varying highp vec2 coord; \n\
125+ void main() { \n\
126+ coord = qt_MultiTexCoord0; \n\
127+ gl_Position = qt_Matrix * qt_Vertex; \n\
128+ }"; \n\
129+ fragmentShader: " \n\
130+ varying highp vec2 coord; \n\
131+ uniform sampler2D source; \n\
132+ uniform lowp float qt_Opacity; \n\
133+ void main() { \n\
134+ lowp vec4 tex = texture2D(source, coord); \n\
135+ gl_FragColor = vec4(0, 0, 0, tex.a) * qt_Opacity; \n\
136+ }"; \n\
137+ } \n\
138+ }\n';
139+
140+// %1 is used as anchors of row
141+// %2 is used as first child of the row
142+// %3 is used as second child of the row
143+var kHeaderRow2Code = 'Row { \n\
144+ id: row; \n\
145+ objectName: "outerRow"; \n\
146+ property real margins: units.gu(1); \n\
147+ spacing: margins; \n\
148+ anchors { %1 } \n\
149+ anchors.right: parent.right; \n\
150+ anchors.margins: margins;\n\
151+ data: [ %2\n\
152+ ,\n\
153+ %3 \n\
154+ ] \n\
155+ }\n';
156+
157+// %1 is used as anchors of row
158+// %2 is used as first child of the row
159+// %3 is used as second child of the row
160+// %4 is used as third child of the row
161+var kHeaderRow3Code = 'Row { \n\
162+ id: row; \n\
163+ objectName: "outerRow"; \n\
164+ property real margins: units.gu(1); \n\
165+ spacing: margins; \n\
166+ anchors { %1 } \n\
167+ anchors.right: parent.right; \n\
168+ anchors.margins: margins;\n\
169+ data: [ %2\n\
170+ ,\n\
171+ %3 \n\
172+ ,\n\
173+ %4 \n\
174+ ] \n\
175+ }\n';
176+
177+// %1 is used as first child of the column
178+// %2 is used as second child of the column
179+var kHeaderColumnCode = 'Column { \n\
180+ anchors.verticalCenter: parent.verticalCenter; \n\
181+ spacing: units.dp(2); \n\
182+ width: parent.width - x;\n\
183+ data: [ %1\n\
184+ ,\n\
185+ %2 \n\
186+ ] \n\
187+ }\n';
188+
189+// %1 is used as anchors of mascotShapeLoader
190+var kMascotShapeLoaderCode = 'Loader { \n\
191+ id: mascotShapeLoader; \n\
192+ objectName: "mascotShapeLoader"; \n\
193+ asynchronous: root.asynchronous; \n\
194+ active: mascotImage.status === Image.Ready; \n\
195+ visible: showHeader && active && status == Loader.Ready; \n\
196+ width: units.gu(6); \n\
197+ height: units.gu(5.625); \n\
198+ sourceComponent: UbuntuShape { image: mascotImage } \n\
199+ anchors { %1 } \n\
200+ }\n';
201+
202+// %1 is used as anchors of mascotImage
203+// %2 is used as visible of mascotImage
204+var kMascotImageCode = 'Image { \n\
205+ id: mascotImage; \n\
206+ objectName: "mascotImage"; \n\
207+ anchors { %1 } \n\
208+ readonly property int maxSize: Math.max(width, height) * 4; \n\
209+ source: cardData && cardData["mascot"]; \n\
210+ width: units.gu(6); \n\
211+ height: units.gu(5.625); \n\
212+ sourceSize { width: maxSize; height: maxSize } \n\
213+ fillMode: Image.PreserveAspectCrop; \n\
214+ horizontalAlignment: Image.AlignHCenter; \n\
215+ verticalAlignment: Image.AlignVCenter; \n\
216+ visible: %2; \n\
217+ }\n';
218+
219+// %1 is used as anchors of titleLabel
220+// %1 is used as color of titleLabel
221+// %3 is used as extra condition for visible of titleLabel
222+var kTitleLabelCode = 'Label { \n\
223+ id: titleLabel; \n\
224+ objectName: "titleLabel"; \n\
225+ anchors { %1 } \n\
226+ elide: Text.ElideRight; \n\
227+ fontSize: "small"; \n\
228+ wrapMode: Text.Wrap; \n\
229+ maximumLineCount: 2; \n\
230+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); \n\
231+ color: %2; \n\
232+ visible: showHeader %3; \n\
233+ text: root.title; \n\
234+ font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal; \n\
235+ horizontalAlignment: root.headerAlignment; \n\
236+ }\n';
237+
238+// %1 is used as anchors of subtitleLabel
239+// %2 is used as color of subtitleLabel
240+var kSubtitleLabelCode = 'Label { \n\
241+ id: subtitleLabel; \n\
242+ objectName: "subtitleLabel"; \n\
243+ anchors { %1 } \n\
244+ elide: Text.ElideRight; \n\
245+ fontSize: "small"; \n\
246+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); \n\
247+ color: %2; \n\
248+ visible: titleLabel.visible && titleLabel.text; \n\
249+ text: cardData && cardData["subtitle"] || ""; \n\
250+ font.weight: Font.Light; \n\
251+ horizontalAlignment: root.headerAlignment; \n\
252+ }\n';
253+
254+// %1 is used as top anchor of summary
255+// %2 is used as topMargin anchor of summary
256+// %3 is used as color of summary
257+var kSummaryLabelCode = 'Label { \n\
258+ id: summary; \n\
259+ objectName: "summaryLabel"; \n\
260+ anchors { \n\
261+ top: %1; \n\
262+ left: parent.left; \n\
263+ right: parent.right; \n\
264+ margins: units.gu(1); \n\
265+ topMargin: %2; \n\
266+ } \n\
267+ wrapMode: Text.Wrap; \n\
268+ maximumLineCount: 5; \n\
269+ elide: Text.ElideRight; \n\
270+ text: cardData && cardData["summary"] || ""; \n\
271+ height: text ? implicitHeight : 0; \n\
272+ fontSize: "small"; \n\
273+ color: %3; \n\
274+ }\n';
275+
276+function cardString(template, components) {
277+ var code;
278+ code = 'AbstractButton { \n\
279+ id: root; \n\
280+ property var template; \n\
281+ property var components; \n\
282+ property var cardData; \n\
283+ property real fontScale: 1.0; \n\
284+ property int headerAlignment: Text.AlignLeft; \n\
285+ property int fixedHeaderHeight: -1; \n\
286+ property size fixedArtShapeSize: Qt.size(-1, -1); \n\
287+ readonly property string title: cardData && cardData["title"] || ""; \n\
288+ property bool asynchronous: true; \n\
289+ property bool showHeader: true; \n\
290+ implicitWidth: childrenRect.width; \n';
291+
292+ var hasArt = components["art"] && components["art"]["field"] || false;
293+ var hasSummary = components["summary"] || false;
294+ var artAndSummary = hasArt && hasSummary;
295+ var isHorizontal = template["card-layout"] === "horizontal";
296+ var hasBackground = !isHorizontal && (template["card-background"] || components["background"] || artAndSummary);
297+ var hasTitle = components["title"] || false;
298+ var hasMascot = components["mascot"] || false;
299+ var headerAsOverlay = hasArt && template && template["overlay"] === true && (hasTitle || hasMascot);
300+ var hasSubtitle = components["subtitle"] || false;
301+ var hasHeaderRow = hasMascot && hasTitle;
302+
303+ if (hasBackground) {
304+ code += kBackgroundLoaderCode;
305+ }
306+
307+ if (hasArt) {
308+ code += 'readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);\n';
309+
310+ var widthCode, heightCode;
311+ var anchors;
312+ if (isHorizontal) {
313+ anchors = 'left: parent.left';
314+ if (hasMascot || hasTitle) {
315+ widthCode = 'height * artShape.aspect'
316+ heightCode = 'headerHeight';
317+ } else {
318+ // This side of the else is a bit silly, who wants an horizontal layout without mascot and title?
319+ // So we define a "random" height of the image height + 2 gu for the margins
320+ widthCode = 'height * artShape.aspect'
321+ heightCode = 'units.gu(7.625)';
322+ }
323+ } else {
324+ anchors = 'horizontalCenter: parent.horizontalCenter;';
325+ widthCode = 'root.width'
326+ heightCode = 'width / artShape.aspect';
327+ }
328+
329+ code += kArtShapeHolderCode.arg(anchors).arg(widthCode).arg(heightCode);
330+ } else {
331+ code += 'readonly property size artShapeSize: Qt.size(-1, -1);\n'
332+ }
333+
334+ if (headerAsOverlay) {
335+ code += kOverlayLoaderCode;
336+ }
337+
338+ var headerVerticalAnchors;
339+ if (headerAsOverlay) {
340+ headerVerticalAnchors = 'bottom: artShapeHolder.bottom; \n\
341+ bottomMargin: units.gu(1);\n';
342+ } else {
343+ if (hasArt) {
344+ if (isHorizontal) {
345+ headerVerticalAnchors = 'top: artShapeHolder.top; \n\
346+ topMargin: units.gu(1);\n';
347+ } else {
348+ headerVerticalAnchors = 'top: artShapeHolder.bottom; \n\
349+ topMargin: units.gu(1);\n';
350+ }
351+ } else {
352+ headerVerticalAnchors = 'top: parent.top; \n\
353+ topMargin: units.gu(1);\n';
354+ }
355+ }
356+ var headerLeftAnchor;
357+ var headerLeftAnchorHasMagin = false;
358+ if (isHorizontal && hasArt) {
359+ headerLeftAnchor = 'left: artShapeHolder.right; \n\
360+ leftMargin: units.gu(1);\n';
361+ headerLeftAnchorHasMagin = true;
362+ } else {
363+ headerLeftAnchor = 'left: parent.left;\n';
364+ }
365+
366+ if (hasHeaderRow) {
367+ code += 'readonly property int headerHeight: row.height + row.margins * 2;\n'
368+ } else if (hasMascot) {
369+ code += 'readonly property int headerHeight: mascotImage.height + units.gu(1) * 2;\n'
370+ } else if (hasSubtitle) {
371+ code += 'readonly property int headerHeight: titleLabel.height + titleLabel.anchors.topMargin * 2 + subtitleLabel.height + subtitleLabel.anchors.topMargin;\n'
372+ } else if (hasTitle) {
373+ code += 'readonly property int headerHeight: titleLabel.height + titleLabel.anchors.topMargin * 2;\n'
374+ } else {
375+ code += 'readonly property int headerHeight: 0;\n'
376+ }
377+
378+ var mascotShapeCode = "";
379+ var mascotCode = "";
380+ if (hasMascot) {
381+ var useMascotShape = !hasBackground && !headerAsOverlay;
382+ var anchors = "";
383+ if (!hasHeaderRow) {
384+ anchors += headerLeftAnchor;
385+ anchors += headerVerticalAnchors;
386+ if (!headerLeftAnchorHasMagin) {
387+ anchors += 'leftMargin: units.gu(1);\n'
388+ }
389+ } else {
390+ anchors = "verticalCenter: parent.verticalCenter;"
391+ }
392+
393+ if (useMascotShape) {
394+ mascotShapeCode = kMascotShapeLoaderCode.arg(anchors);
395+ }
396+
397+ var mascotImageVisible = useMascotShape ? 'false' : 'showHeader';
398+ mascotCode = kMascotImageCode.arg(anchors).arg(mascotImageVisible);
399+ }
400+
401+ var summaryColorWithBackground = 'backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < 0.7 ? "white" : "grey"';
402+
403+ var titleSubtitleCode = "";
404+ if (hasTitle) {
405+ var color;
406+ if (headerAsOverlay) {
407+ color = '"white"';
408+ } else if (hasSummary) {
409+ color = 'summary.color';
410+ } else if (hasBackground) {
411+ color = summaryColorWithBackground;
412+ } else {
413+ color = '"grey"';
414+ }
415+
416+ var titleAnchors;
417+ var subtitleAnchors;
418+ if (hasMascot && hasSubtitle) {
419+ // Using row + column
420+ titleAnchors = 'left: parent.left; right: parent.right';
421+ subtitleAnchors = titleAnchors;
422+ } else if (hasMascot) {
423+ // Using row + label
424+ titleAnchors = 'verticalCenter: parent.verticalCenter;\n'
425+ } else {
426+ if (headerAsOverlay) {
427+ // Using anchors to the overlay
428+ titleAnchors = 'left: parent.left; \n\
429+ leftMargin: units.gu(1); \n\
430+ right: parent.right; \n\
431+ top: overlayLoader.top; \n\
432+ topMargin: units.gu(1);\n';
433+ } else {
434+ // Using anchors to the mascot/parent
435+ titleAnchors = "right: parent.right;";
436+ titleAnchors += headerLeftAnchor;
437+ titleAnchors += headerVerticalAnchors;
438+ }
439+ subtitleAnchors = 'left: titleLabel.left; \n\
440+ leftMargin: titleLabel.leftMargin; \n\
441+ right: titleLabel.right; \n\
442+ top: titleLabel.bottom; \n\
443+ topMargin: units.dp(2);\n';
444+ }
445+
446+ var titleLabelVisibleExtra = (headerAsOverlay ? '&& overlayLoader.active': '');
447+ var titleCode = kTitleLabelCode.arg(titleAnchors).arg(color).arg(titleLabelVisibleExtra);
448+ var subtitleCode = "";
449+ if (hasSubtitle) {
450+ subtitleCode += kSubtitleLabelCode.arg(subtitleAnchors).arg(color);
451+ }
452+
453+ if (hasMascot && hasSubtitle) {
454+ // If using row + column wrap the code in the column
455+ titleSubtitleCode = kHeaderColumnCode.arg(titleCode).arg(subtitleCode);
456+ } else {
457+ titleSubtitleCode = titleCode + subtitleCode;
458+ }
459+ }
460+
461+ if (hasHeaderRow) {
462+ if (mascotShapeCode != "") {
463+ code += kHeaderRow3Code.arg(headerVerticalAnchors + headerLeftAnchor).arg(mascotShapeCode).arg(mascotCode).arg(titleSubtitleCode);
464+ } else {
465+ code += kHeaderRow2Code.arg(headerVerticalAnchors + headerLeftAnchor).arg(mascotCode).arg(titleSubtitleCode);
466+ }
467+ } else {
468+ code += mascotShapeCode + mascotCode + titleSubtitleCode;
469+ }
470+
471+ if (hasSummary) {
472+ var summaryTopAnchor;
473+ if (isHorizontal && hasArt) summaryTopAnchor = "artShapeHolder.bottom";
474+ else if (headerAsOverlay && hasArt) summaryTopAnchor = "artShapeHolder.bottom";
475+ else if (hasHeaderRow) summaryTopAnchor = "row.bottom";
476+ else if (hasMascot) summaryTopAnchor = "mascotImage.bottom";
477+ else if (hasSubtitle) summaryTopAnchor = "subtitleLabel.bottom";
478+ else if (hasTitle) summaryTopAnchor = "titleLabel.bottom";
479+ else if (hasArt) summaryTopAnchor = "artShapeHolder.bottom";
480+ else summaryTopAnchor = "parent.top";
481+
482+ var color;
483+ if (hasBackground) {
484+ color = summaryColorWithBackground;
485+ } else {
486+ color = '"grey"';
487+ }
488+
489+ var summaryTopMargin = (hasMascot || hasSubtitle ? 'anchors.margins' : '0');
490+
491+ code += kSummaryLabelCode.arg(summaryTopAnchor).arg(summaryTopMargin).arg(color);
492+ }
493+
494+ if (hasSummary) {
495+ code += 'implicitHeight: summary.y + summary.height + (summary.text ? units.gu(1) : 0);\n';
496+ } else if (hasHeaderRow) {
497+ code += 'implicitHeight: row.y + row.height + units.gu(1);\n';
498+ } else if (hasMascot) {
499+ code += 'implicitHeight: mascotImage.y + mascotImage.height;\n';
500+ } else if (hasSubtitle) {
501+ code += 'implicitHeight: subtitleLabel.y + subtitleLabel.height + units.gu(1);\n';
502+ } else if (hasTitle) {
503+ code += 'implicitHeight: titleLabel.y + titleLabel.height + units.gu(1);\n';
504+ }
505+ // Close the AbstractButton
506+ code += '}\n';
507+
508+ return code;
509+}
510+
511+function createCardComponent(parent, template, components) {
512+ var imports = 'import QtQuick 2.2; \n\
513+ import Ubuntu.Components 0.1; \n\
514+ import Ubuntu.Thumbnailer 0.1;\n';
515+ var card = cardString(template, components);
516+ var code = imports + 'Component {\n' + card + '}\n';
517+ return Qt.createQmlObject(code, parent, "createCardComponent");
518+}
plugins/Dash/CardCreatorCache.qmlnew file+40
@@ -0,0 +1,40 @@
1+/*
2+ * Copyright (C) 2014 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+pragma Singleton
18+import QtQuick 2.2
19+import "CardCreator.js" as CardCreator
20+
21+QtObject {
22+ id: root
23+
24+ property var cache: new Object();
25+
26+ function getCardComponent(template, components) {
27+ if (template === undefined || components === undefined)
28+ return undefined;
29+
30+ var tString = JSON.stringify(template);
31+ var cString = JSON.stringify(components);
32+ var allString = tString + cString;
33+ var component = cache[allString];
34+ if (component === undefined) {
35+ component = CardCreator.createCardComponent(root, template, components);
36+ cache[allString] = component;
37+ }
38+ return component;
39+ }
40+}
plugins/DashViews/abstractdashview.cpp → plugins/Dash/abstractdashview.cpprenamed−34
@@ -46,17 +46,10 @@ void AbstractDashView::setModel(QAbstractItemModel *model)
46 if (!m_delegateModel) {
46 if (!m_delegateModel) {
47 createDelegateModel();
47 createDelegateModel();
48 } else {
48 } else {
49−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
50− disconnect(m_delegateModel, SIGNAL(modelUpdated(QQuickChangeSet,bool)), this, SLOT(onModelUpdated(QQuickChangeSet,bool)));
51− }
52− m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
53− connect(m_delegateModel, SIGNAL(modelUpdated(QQuickChangeSet,bool)), this, SLOT(onModelUpdated(QQuickChangeSet,bool)));
54−#else
55 disconnect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
49 disconnect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
56 }
50 }
57 m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
51 m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
58 connect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
52 connect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
59−#endif
60
53
61 cleanupExistingItems();
54 cleanupExistingItems();
62
55
@@ -181,13 +174,8 @@ void AbstractDashView::resetDelegateCreationEnd()
181
174
182void AbstractDashView::createDelegateModel()
175void AbstractDashView::createDelegateModel()
183{
176{
184−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
185− m_delegateModel = new QQuickVisualDataModel(qmlContext(this), this);
186− connect(m_delegateModel, SIGNAL(createdItem(int,QQuickItem*)), this, SLOT(itemCreated(int,QQuickItem*)));
187−#else
188 m_delegateModel = new QQmlDelegateModel(qmlContext(this), this);
177 m_delegateModel = new QQmlDelegateModel(qmlContext(this), this);
189 connect(m_delegateModel, SIGNAL(createdItem(int,QObject*)), this, SLOT(itemCreated(int,QObject*)));
178 connect(m_delegateModel, SIGNAL(createdItem(int,QObject*)), this, SLOT(itemCreated(int,QObject*)));
190−#endif
191 if (isComponentComplete())
179 if (isComponentComplete())
192 m_delegateModel->componentComplete();
180 m_delegateModel->componentComplete();
193}
181}
@@ -253,16 +241,9 @@ QQuickItem *AbstractDashView::createItem(int modelIndex, bool asynchronous)
253 return nullptr;
241 return nullptr;
254
242
255 m_asyncRequestedIndex = -1;
243 m_asyncRequestedIndex = -1;
256−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
257− QQuickItem *item = m_delegateModel->item(modelIndex, asynchronous);
258−#else
259 QObject* object = m_delegateModel->object(modelIndex, asynchronous);
244 QObject* object = m_delegateModel->object(modelIndex, asynchronous);
260 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
245 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
261−#endif
262 if (!item) {
246 if (!item) {
263−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
264− m_asyncRequestedIndex = modelIndex;
265−#else
266 if (object) {
247 if (object) {
267 m_delegateModel->release(object);
248 m_delegateModel->release(object);
268 if (!m_delegateValidated) {
249 if (!m_delegateValidated) {
@@ -273,7 +254,6 @@ QQuickItem *AbstractDashView::createItem(int modelIndex, bool asynchronous)
273 } else {
254 } else {
274 m_asyncRequestedIndex = modelIndex;
255 m_asyncRequestedIndex = modelIndex;
275 }
256 }
276−#endif
277 return nullptr;
257 return nullptr;
278 } else {
258 } else {
279 addItemToView(modelIndex, item);
259 addItemToView(modelIndex, item);
@@ -283,13 +263,8 @@ QQuickItem *AbstractDashView::createItem(int modelIndex, bool asynchronous)
283
263
284void AbstractDashView::releaseItem(QQuickItem *item)
264void AbstractDashView::releaseItem(QQuickItem *item)
285{
265{
286−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
287− QQuickVisualModel::ReleaseFlags flags = m_delegateModel->release(item);
288− if (flags & QQuickVisualModel::Destroyed) {
289−#else
290 QQmlDelegateModel::ReleaseFlags flags = m_delegateModel->release(item);
266 QQmlDelegateModel::ReleaseFlags flags = m_delegateModel->release(item);
291 if (flags & QQmlDelegateModel::Destroyed) {
267 if (flags & QQmlDelegateModel::Destroyed) {
292−#endif
293 item->setParentItem(nullptr);
268 item->setParentItem(nullptr);
294 }
269 }
295}
270}
@@ -299,10 +274,6 @@ void AbstractDashView::setImplicitHeightDirty()
299 m_implicitHeightDirty = true;
274 m_implicitHeightDirty = true;
300}
275}
301
276
302−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
303−void AbstractDashView::itemCreated(int modelIndex, QQuickItem *item)
304−{
305−#else
306void AbstractDashView::itemCreated(int modelIndex, QObject *object)
277void AbstractDashView::itemCreated(int modelIndex, QObject *object)
307{
278{
308 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
279 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
@@ -310,7 +281,6 @@ void AbstractDashView::itemCreated(int modelIndex, QObject *object)
310 qWarning() << "AbstractDashView::itemCreated got a non item for index" << modelIndex;
281 qWarning() << "AbstractDashView::itemCreated got a non item for index" << modelIndex;
311 return;
282 return;
312 }
283 }
313−#endif
314 item->setParentItem(this);
284 item->setParentItem(this);
315
285
316 // We only need to call createItem if we are here because of an asynchronous generation
286 // We only need to call createItem if we are here because of an asynchronous generation
@@ -325,11 +295,7 @@ void AbstractDashView::itemCreated(int modelIndex, QObject *object)
325 }
295 }
326}
296}
327
297
328−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
329−void AbstractDashView::onModelUpdated(const QQuickChangeSet &changeSet, bool reset)
330−#else
331void AbstractDashView::onModelUpdated(const QQmlChangeSet &changeSet, bool reset)
298void AbstractDashView::onModelUpdated(const QQmlChangeSet &changeSet, bool reset)
332−#endif
333{
299{
334 if (reset) {
300 if (reset) {
335 cleanupExistingItems();
301 cleanupExistingItems();
plugins/DashViews/abstractdashview.h → plugins/Dash/abstractdashview.hrenamed−17
@@ -23,12 +23,8 @@ class QAbstractItemModel;
23class QQmlComponent;
23class QQmlComponent;
24#pragma GCC diagnostic push
24#pragma GCC diagnostic push
25#pragma GCC diagnostic ignored "-pedantic"
25#pragma GCC diagnostic ignored "-pedantic"
26−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
27−#include <private/qquickvisualdatamodel_p.h>
28−#else
29#include <private/qqmldelegatemodel_p.h>
26#include <private/qqmldelegatemodel_p.h>
30#include <qqmlinfo.h>
27#include <qqmlinfo.h>
31−#endif
32#pragma GCC diagnostic pop
28#pragma GCC diagnostic pop
33
29
34class AbstractDashView : public QQuickItem
30class AbstractDashView : public QQuickItem
@@ -94,13 +90,8 @@ protected:
94 void setImplicitHeightDirty();
90 void setImplicitHeightDirty();
95
91
96private Q_SLOTS:
92private Q_SLOTS:
97−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
98− void itemCreated(int modelIndex, QQuickItem *item);
99− void onModelUpdated(const QQuickChangeSet &changeSet, bool reset);
100−#else
101 void itemCreated(int modelIndex, QObject *object);
93 void itemCreated(int modelIndex, QObject *object);
102 void onModelUpdated(const QQmlChangeSet &changeSet, bool reset);
94 void onModelUpdated(const QQmlChangeSet &changeSet, bool reset);
103−#endif
104 void onHeightChanged();
95 void onHeightChanged();
105
96
106private:
97private:
@@ -117,17 +108,9 @@ private:
117 virtual void doRelayout() = 0;
108 virtual void doRelayout() = 0;
118 virtual void updateItemCulling(qreal visibleFromY, qreal visibleToY) = 0;
109 virtual void updateItemCulling(qreal visibleFromY, qreal visibleToY) = 0;
119 virtual void calculateImplicitHeight() = 0;
110 virtual void calculateImplicitHeight() = 0;
120−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
121− virtual void processModelRemoves(const QVector<QQuickChangeSet::Remove> &removes) = 0;
122−#else
123 virtual void processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes) = 0;
111 virtual void processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes) = 0;
124−#endif
125
112
126−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
127− QQuickVisualDataModel *m_delegateModel;
128−#else
129 QQmlDelegateModel *m_delegateModel;
113 QQmlDelegateModel *m_delegateModel;
130−#endif
131
114
132 // Index we are waiting because we requested it asynchronously
115 // Index we are waiting because we requested it asynchronously
133 int m_asyncRequestedIndex;
116 int m_asyncRequestedIndex;
plugins/DashViews/horizontaljournal.cpp → plugins/Dash/horizontaljournal.cpprenamed−12
@@ -28,12 +28,8 @@
28#include <qqmlengine.h>
28#include <qqmlengine.h>
29#pragma GCC diagnostic push
29#pragma GCC diagnostic push
30#pragma GCC diagnostic ignored "-pedantic"
30#pragma GCC diagnostic ignored "-pedantic"
31−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
32−#include <private/qquickvisualdatamodel_p.h>
33−#else
34#include <private/qqmldelegatemodel_p.h>
31#include <private/qqmldelegatemodel_p.h>
35#include <qqmlinfo.h>
32#include <qqmlinfo.h>
36−#endif
37#include <private/qquickitem_p.h>
33#include <private/qquickitem_p.h>
38#pragma GCC diagnostic pop
34#pragma GCC diagnostic pop
39
35
@@ -188,17 +184,9 @@ void HorizontalJournal::calculateImplicitHeight()
188 }
184 }
189}
185}
190
186
191−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
192−void HorizontalJournal::processModelRemoves(const QVector<QQuickChangeSet::Remove> &removes)
193−#else
194void HorizontalJournal::processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes)
187void HorizontalJournal::processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes)
195−#endif
196{
188{
197−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
198− Q_FOREACH(const QQuickChangeSet::Remove &remove, removes) {
199−#else
200 Q_FOREACH(const QQmlChangeSet::Remove &remove, removes) {
189 Q_FOREACH(const QQmlChangeSet::Remove &remove, removes) {
201−#endif
202 for (int i = remove.count - 1; i >= 0; --i) {
190 for (int i = remove.count - 1; i >= 0; --i) {
203 const int indexToRemove = remove.index + i;
191 const int indexToRemove = remove.index + i;
204 // We only support removing from the end so
192 // We only support removing from the end so
plugins/DashViews/horizontaljournal.h → plugins/Dash/horizontaljournal.hrenamed−4
@@ -52,11 +52,7 @@ private:
52 void calculateImplicitHeight() override;
52 void calculateImplicitHeight() override;
53 void doRelayout() override;
53 void doRelayout() override;
54 void updateItemCulling(qreal visibleFromY, qreal visibleToY) override;
54 void updateItemCulling(qreal visibleFromY, qreal visibleToY) override;
55−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
56− void processModelRemoves(const QVector<QQuickChangeSet::Remove> &removes) override;
57−#else
58 void processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes) override;
55 void processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes) override;
59−#endif
60
56
61 int m_firstVisibleIndex;
57 int m_firstVisibleIndex;
62 QList<QQuickItem*> m_visibleItems;
58 QList<QQuickItem*> m_visibleItems;
plugins/DashViews/listviewwithpageheader.cpp → plugins/Dash/listviewwithpageheader.cpprenamed−50
@@ -97,11 +97,7 @@
97#include <qqmlengine.h>
97#include <qqmlengine.h>
98#pragma GCC diagnostic push
98#pragma GCC diagnostic push
99#pragma GCC diagnostic ignored "-pedantic"
99#pragma GCC diagnostic ignored "-pedantic"
100−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
101−#include <private/qquickvisualdatamodel_p.h>
102−#else
103#include <private/qqmldelegatemodel_p.h>
100#include <private/qqmldelegatemodel_p.h>
104−#endif
105#include <private/qqmlglobal_p.h>
101#include <private/qqmlglobal_p.h>
106#include <private/qquickitem_p.h>
102#include <private/qquickitem_p.h>
107#include <private/qquickanimation_p.h>
103#include <private/qquickanimation_p.h>
@@ -191,17 +187,10 @@ void ListViewWithPageHeader::setModel(QAbstractItemModel *model)
191 if (!m_delegateModel) {
187 if (!m_delegateModel) {
192 createDelegateModel();
188 createDelegateModel();
193 } else {
189 } else {
194−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
195− disconnect(m_delegateModel, SIGNAL(modelUpdated(QQuickChangeSet,bool)), this, SLOT(onModelUpdated(QQuickChangeSet,bool)));
196− }
197− m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
198− connect(m_delegateModel, SIGNAL(modelUpdated(QQuickChangeSet,bool)), this, SLOT(onModelUpdated(QQuickChangeSet,bool)));
199−#else
200 disconnect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
190 disconnect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
201 }
191 }
202 m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
192 m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
203 connect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
193 connect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
204−#endif
205 Q_EMIT modelChanged();
194 Q_EMIT modelChanged();
206 polish();
195 polish();
207 // TODO?
196 // TODO?
@@ -570,13 +559,8 @@ void ListViewWithPageHeader::viewportMoved(Qt::Orientations orient)
570
559
571void ListViewWithPageHeader::createDelegateModel()
560void ListViewWithPageHeader::createDelegateModel()
572{
561{
573−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
574− m_delegateModel = new QQuickVisualDataModel(qmlContext(this), this);
575− connect(m_delegateModel, SIGNAL(createdItem(int,QQuickItem*)), this, SLOT(itemCreated(int,QQuickItem*)));
576−#else
577 m_delegateModel = new QQmlDelegateModel(qmlContext(this), this);
562 m_delegateModel = new QQmlDelegateModel(qmlContext(this), this);
578 connect(m_delegateModel, SIGNAL(createdItem(int,QObject*)), this, SLOT(itemCreated(int,QObject*)));
563 connect(m_delegateModel, SIGNAL(createdItem(int,QObject*)), this, SLOT(itemCreated(int,QObject*)));
579−#endif
580 if (isComponentComplete())
564 if (isComponentComplete())
581 m_delegateModel->componentComplete();
565 m_delegateModel->componentComplete();
582 updateWatchedRoles();
566 updateWatchedRoles();
@@ -657,13 +641,8 @@ bool ListViewWithPageHeader::addVisibleItems(qreal fillFrom, qreal fillTo, bool
657void ListViewWithPageHeader::reallyReleaseItem(ListItem *listItem)
641void ListViewWithPageHeader::reallyReleaseItem(ListItem *listItem)
658{
642{
659 QQuickItem *item = listItem->m_item;
643 QQuickItem *item = listItem->m_item;
660−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
661− QQuickVisualModel::ReleaseFlags flags = m_delegateModel->release(item);
662− if (flags & QQuickVisualModel::Destroyed) {
663−#else
664 QQmlDelegateModel::ReleaseFlags flags = m_delegateModel->release(item);
644 QQmlDelegateModel::ReleaseFlags flags = m_delegateModel->release(item);
665 if (flags & QQmlDelegateModel::Destroyed) {
645 if (flags & QQmlDelegateModel::Destroyed) {
666−#endif
667 item->setParentItem(nullptr);
646 item->setParentItem(nullptr);
668 }
647 }
669 delete listItem->m_sectionItem;
648 delete listItem->m_sectionItem;
@@ -796,16 +775,9 @@ ListViewWithPageHeader::ListItem *ListViewWithPageHeader::createItem(int modelIn
796 return nullptr;
775 return nullptr;
797
776
798 m_asyncRequestedIndex = -1;
777 m_asyncRequestedIndex = -1;
799−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
800− QQuickItem *item = m_delegateModel->item(modelIndex, asynchronous);
801−#else
802 QObject* object = m_delegateModel->object(modelIndex, asynchronous);
778 QObject* object = m_delegateModel->object(modelIndex, asynchronous);
803 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
779 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
804−#endif
805 if (!item) {
780 if (!item) {
806−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
807− m_asyncRequestedIndex = modelIndex;
808−#else
809 if (object) {
781 if (object) {
810 m_delegateModel->release(object);
782 m_delegateModel->release(object);
811 if (!m_delegateValidated) {
783 if (!m_delegateValidated) {
@@ -816,7 +788,6 @@ ListViewWithPageHeader::ListItem *ListViewWithPageHeader::createItem(int modelIn
816 } else {
788 } else {
817 m_asyncRequestedIndex = modelIndex;
789 m_asyncRequestedIndex = modelIndex;
818 }
790 }
819−#endif
820 return 0;
791 return 0;
821 } else {
792 } else {
822// qDebug() << "ListViewWithPageHeader::createItem::We have the item" << modelIndex << item;
793// qDebug() << "ListViewWithPageHeader::createItem::We have the item" << modelIndex << item;
@@ -872,10 +843,6 @@ ListViewWithPageHeader::ListItem *ListViewWithPageHeader::createItem(int modelIn
872 }
843 }
873}
844}
874
845
875−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
876−void ListViewWithPageHeader::itemCreated(int modelIndex, QQuickItem *item)
877−{
878−#else
879void ListViewWithPageHeader::itemCreated(int modelIndex, QObject *object)
846void ListViewWithPageHeader::itemCreated(int modelIndex, QObject *object)
880{
847{
881 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
848 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
@@ -883,7 +850,6 @@ void ListViewWithPageHeader::itemCreated(int modelIndex, QObject *object)
883 qWarning() << "ListViewWithPageHeader::itemCreated got a non item for index" << modelIndex;
850 qWarning() << "ListViewWithPageHeader::itemCreated got a non item for index" << modelIndex;
884 return;
851 return;
885 }
852 }
886−#endif
887// qDebug() << "ListViewWithPageHeader::itemCreated" << modelIndex << item;
853// qDebug() << "ListViewWithPageHeader::itemCreated" << modelIndex << item;
888 // Check we are not being taken down and don't paint anything
854 // Check we are not being taken down and don't paint anything
889 // TODO Check if we still need this in 5.2
855 // TODO Check if we still need this in 5.2
@@ -924,21 +890,13 @@ void ListViewWithPageHeader::onHeightChanged()
924}
890}
925
891
926
892
927−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
928−void ListViewWithPageHeader::onModelUpdated(const QQuickChangeSet &changeSet, bool /*reset*/)
929−#else
930void ListViewWithPageHeader::onModelUpdated(const QQmlChangeSet &changeSet, bool /*reset*/)
893void ListViewWithPageHeader::onModelUpdated(const QQmlChangeSet &changeSet, bool /*reset*/)
931−#endif
932{
894{
933 // TODO Do something with reset
895 // TODO Do something with reset
934// qDebug() << "ListViewWithPageHeader::onModelUpdated" << changeSet << reset;
896// qDebug() << "ListViewWithPageHeader::onModelUpdated" << changeSet << reset;
935 const auto oldFirstVisibleIndex = m_firstVisibleIndex;
897 const auto oldFirstVisibleIndex = m_firstVisibleIndex;
936
898
937−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
938− Q_FOREACH(const QQuickChangeSet::Remove &remove, changeSet.removes()) {
939−#else
940 Q_FOREACH(const QQmlChangeSet::Remove &remove, changeSet.removes()) {
899 Q_FOREACH(const QQmlChangeSet::Remove &remove, changeSet.removes()) {
941−#endif
942// qDebug() << "ListViewWithPageHeader::onModelUpdated Remove" << remove.index << remove.count;
900// qDebug() << "ListViewWithPageHeader::onModelUpdated Remove" << remove.index << remove.count;
943 if (remove.index + remove.count > m_firstVisibleIndex && remove.index < m_firstVisibleIndex + m_visibleItems.count()) {
901 if (remove.index + remove.count > m_firstVisibleIndex && remove.index < m_firstVisibleIndex + m_visibleItems.count()) {
944 const qreal oldFirstValidIndexPos = m_visibleItems.first()->y();
902 const qreal oldFirstValidIndexPos = m_visibleItems.first()->y();
@@ -992,11 +950,7 @@ void ListViewWithPageHeader::onModelUpdated(const QQmlChangeSet &changeSet, bool
992 }
950 }
993 }
951 }
994
952
995−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
996− Q_FOREACH(const QQuickChangeSet::Insert &insert, changeSet.inserts()) {
997−#else
998 Q_FOREACH(const QQmlChangeSet::Insert &insert, changeSet.inserts()) {
953 Q_FOREACH(const QQmlChangeSet::Insert &insert, changeSet.inserts()) {
999−#endif
1000// qDebug() << "ListViewWithPageHeader::onModelUpdated Insert" << insert.index << insert.count;
954// qDebug() << "ListViewWithPageHeader::onModelUpdated Insert" << insert.index << insert.count;
1001 const bool insertingInValidIndexes = insert.index > m_firstVisibleIndex && insert.index < m_firstVisibleIndex + m_visibleItems.count();
955 const bool insertingInValidIndexes = insert.index > m_firstVisibleIndex && insert.index < m_firstVisibleIndex + m_visibleItems.count();
1002 const bool firstItemWithViewOnTop = insert.index == 0 && m_firstVisibleIndex == 0 && m_visibleItems.first()->y() + m_clipItem->y() > contentY();
956 const bool firstItemWithViewOnTop = insert.index == 0 && m_firstVisibleIndex == 0 && m_visibleItems.first()->y() + m_clipItem->y() > contentY();
@@ -1054,11 +1008,7 @@ void ListViewWithPageHeader::onModelUpdated(const QQmlChangeSet &changeSet, bool
1054 }
1008 }
1055 }
1009 }
1056
1010
1057−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
1058− Q_FOREACH(const QQuickChangeSet::Change &change, changeSet.changes()) {
1059−#else
1060 Q_FOREACH(const QQmlChangeSet::Change &change, changeSet.changes()) {
1011 Q_FOREACH(const QQmlChangeSet::Change &change, changeSet.changes()) {
1061−#endif
1062// qDebug() << "ListViewWithPageHeader::onModelUpdated Change" << change.index << change.count;
1012// qDebug() << "ListViewWithPageHeader::onModelUpdated Change" << change.index << change.count;
1063 for (int i = change.index; i < change.count; ++i) {
1013 for (int i = change.index; i < change.count; ++i) {
1064 ListItem *item = itemAtIndex(i);
1014 ListItem *item = itemAtIndex(i);
plugins/DashViews/listviewwithpageheader.h → plugins/Dash/listviewwithpageheader.hrenamed−20
@@ -17,21 +17,13 @@
17#ifndef LISTVIEWWITHPAGEHEADER_H
17#ifndef LISTVIEWWITHPAGEHEADER_H
18#define LISTVIEWWITHPAGEHEADER_H
18#define LISTVIEWWITHPAGEHEADER_H
19
19
20−#pragma GCC diagnostic push
21−#pragma GCC diagnostic ignored "-pedantic"
22#include <private/qquickitemchangelistener_p.h>
20#include <private/qquickitemchangelistener_p.h>
23#include <private/qquickflickable_p.h>
21#include <private/qquickflickable_p.h>
24−#pragma GCC diagnostic pop
25
22
26class QAbstractItemModel;
23class QAbstractItemModel;
27class QQuickNumberAnimation;
24class QQuickNumberAnimation;
28−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
29−class QQuickChangeSet;
30−class QQuickVisualDataModel;
31−#else
32class QQmlChangeSet;
25class QQmlChangeSet;
33class QQmlDelegateModel;
26class QQmlDelegateModel;
34−#endif
35
27
36
28
37/**
29/**
@@ -117,19 +109,11 @@ protected:
117 void updatePolish();
109 void updatePolish();
118
110
119private Q_SLOTS:
111private Q_SLOTS:
120−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
121− void itemCreated(int modelIndex, QQuickItem *item);
122−#else
123 void itemCreated(int modelIndex, QObject *object);
112 void itemCreated(int modelIndex, QObject *object);
124−#endif
125 void onContentHeightChanged();
113 void onContentHeightChanged();
126 void onContentWidthChanged();
114 void onContentWidthChanged();
127 void onHeightChanged();
115 void onHeightChanged();
128−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
129− void onModelUpdated(const QQuickChangeSet &changeSet, bool reset);
130−#else
131 void onModelUpdated(const QQmlChangeSet &changeSet, bool reset);
116 void onModelUpdated(const QQmlChangeSet &changeSet, bool reset);
132−#endif
133 void onShowHeaderAnimationFinished();
117 void onShowHeaderAnimationFinished();
134
118
135private:
119private:
@@ -168,11 +152,7 @@ private:
168 QQuickItem *getSectionItem(int modelIndex, bool alreadyInserted);
152 QQuickItem *getSectionItem(int modelIndex, bool alreadyInserted);
169 QQuickItem *getSectionItem(const QString &sectionText);
153 QQuickItem *getSectionItem(const QString &sectionText);
170
154
171−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
172− QQuickVisualDataModel *m_delegateModel;
173−#else
174 QQmlDelegateModel *m_delegateModel;
155 QQmlDelegateModel *m_delegateModel;
175−#endif
176
156
177 // Index we are waiting because we requested it asynchronously
157 // Index we are waiting because we requested it asynchronously
178 int m_asyncRequestedIndex;
158 int m_asyncRequestedIndex;
plugins/DashViews/organicgrid.cpp → plugins/Dash/organicgrid.cpprenamed−8
@@ -237,17 +237,9 @@ void OrganicGrid::calculateImplicitHeight()
237 }
237 }
238}
238}
239
239
240−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
241−void OrganicGrid::processModelRemoves(const QVector<QQuickChangeSet::Remove> &removes)
242−#else
243void OrganicGrid::processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes)
240void OrganicGrid::processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes)
244−#endif
245{
241{
246−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
247− Q_FOREACH(const QQuickChangeSet::Remove &remove, removes) {
248−#else
249 Q_FOREACH(const QQmlChangeSet::Remove &remove, removes) {
242 Q_FOREACH(const QQmlChangeSet::Remove &remove, removes) {
250−#endif
251 for (int i = remove.count - 1; i >= 0; --i) {
243 for (int i = remove.count - 1; i >= 0; --i) {
252 const int indexToRemove = remove.index + i;
244 const int indexToRemove = remove.index + i;
253 // We only support removing from the end
245 // We only support removing from the end
plugins/DashViews/organicgrid.h → plugins/Dash/organicgrid.hrenamed−4
@@ -79,11 +79,7 @@ private:
79 void doRelayout() override;
79 void doRelayout() override;
80 void updateItemCulling(qreal visibleFromY, qreal visibleToY) override;
80 void updateItemCulling(qreal visibleFromY, qreal visibleToY) override;
81 void calculateImplicitHeight() override;
81 void calculateImplicitHeight() override;
82−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
83− void processModelRemoves(const QVector<QQuickChangeSet::Remove> &removes) override;
84−#else
85 void processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes) override;
82 void processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes) override;
86−#endif
87
83
88 QSizeF m_smallDelegateSize;
84 QSizeF m_smallDelegateSize;
89 QSizeF m_bigDelegateSize;
85 QSizeF m_bigDelegateSize;
plugins/DashViews/plugin.cpp → plugins/Dash/plugin.cpprenamed+2−2
@@ -24,9 +24,9 @@
24
24
25#include <QAbstractItemModel>
25#include <QAbstractItemModel>
26
26
27−void DashViewsPlugin::registerTypes(const char *uri)
27+void DashPlugin::registerTypes(const char *uri)
28{
28{
29− Q_ASSERT(uri == QLatin1String("DashViews"));
29+ Q_ASSERT(uri == QLatin1String("Dash"));
30 qmlRegisterType<QAbstractItemModel>();
30 qmlRegisterType<QAbstractItemModel>();
31 qmlRegisterType<HorizontalJournal>(uri, 0, 1, "HorizontalJournal");
31 qmlRegisterType<HorizontalJournal>(uri, 0, 1, "HorizontalJournal");
32 qmlRegisterType<ListViewWithPageHeader>(uri, 0, 1, "ListViewWithPageHeader");
32 qmlRegisterType<ListViewWithPageHeader>(uri, 0, 1, "ListViewWithPageHeader");
plugins/DashViews/plugin.h → plugins/Dash/plugin.hrenamed+3−3
@@ -15,13 +15,13 @@
15 *
15 *
16 */
16 */
17
17
18−#ifndef DASHVIEWS_PLUGIN_H
18+#ifndef DASH_PLUGIN_H
19−#define DASHVIEWS_PLUGIN_H
19+#define DASH_PLUGIN_H
20
20
21#include <QtQml/QQmlEngine>
21#include <QtQml/QQmlEngine>
22#include <QtQml/QQmlExtensionPlugin>
22#include <QtQml/QQmlExtensionPlugin>
23
23
24−class DashViewsPlugin : public QQmlExtensionPlugin
24+class DashPlugin : public QQmlExtensionPlugin
25{
25{
26 Q_OBJECT
26 Q_OBJECT
27 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
27 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
plugins/Dash/qmldirnew file+4
@@ -0,0 +1,4 @@
1+module Dash
2+plugin Dash-qml
3+typeinfo Dash.qmltypes
4+singleton CardCreatorCache 0.1 CardCreatorCache.qml
plugins/DashViews/verticaljournal.cpp → plugins/Dash/verticaljournal.cpprenamed−8
@@ -239,17 +239,9 @@ void VerticalJournal::updateItemCulling(qreal visibleFromY, qreal visibleToY)
239 }
239 }
240}
240}
241
241
242−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
243−void VerticalJournal::processModelRemoves(const QVector<QQuickChangeSet::Remove> &removes)
244−#else
245void VerticalJournal::processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes)
242void VerticalJournal::processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes)
246−#endif
247{
243{
248−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
249− Q_FOREACH(const QQuickChangeSet::Remove &remove, removes) {
250−#else
251 Q_FOREACH(const QQmlChangeSet::Remove &remove, removes) {
244 Q_FOREACH(const QQmlChangeSet::Remove &remove, removes) {
252−#endif
253 for (int i = remove.count - 1; i >= 0; --i) {
245 for (int i = remove.count - 1; i >= 0; --i) {
254 const int indexToRemove = remove.index + i;
246 const int indexToRemove = remove.index + i;
255 // Since we only support removing from the end, indexToRemove
247 // Since we only support removing from the end, indexToRemove
plugins/DashViews/verticaljournal.h → plugins/Dash/verticaljournal.hrenamed−4
@@ -90,11 +90,7 @@ private:
90 void calculateImplicitHeight() override;
90 void calculateImplicitHeight() override;
91 void doRelayout() override;
91 void doRelayout() override;
92 void updateItemCulling(qreal visibleFromY, qreal visibleToY) override;
92 void updateItemCulling(qreal visibleFromY, qreal visibleToY) override;
93−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
94− void processModelRemoves(const QVector<QQuickChangeSet::Remove> &removes) override;
95−#else
96 void processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes) override;
93 void processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes) override;
97−#endif
98
94
99 QVector<QList<ViewItem>> m_columnVisibleItems;
95 QVector<QList<ViewItem>> m_columnVisibleItems;
100 QHash<int, int> m_indexColumnMap;
96 QHash<int, int> m_indexColumnMap;
plugins/DashViews/qmldirdeleted−3
@@ -1,3 +0,0 @@
1−module DashViews
2−plugin DashViews-qml
3−typeinfo DashViews.qmltypes
plugins/Unity/Indicators/menucontentactivator.cpp−1
@@ -316,7 +316,6 @@ MenuContentState* MenuContentActivatorPrivate::content_at(QQmlListProperty<MenuC
316 if (!d->m_content.contains(index)) {
316 if (!d->m_content.contains(index)) {
317 MenuContentState* content = new MenuContentState(false);
317 MenuContentState* content = new MenuContentState(false);
318 d->m_content[index] = content;
318 d->m_content[index] = content;
319− Q_EMIT p->contentChanged();
320 return content;
319 return content;
321 }
320 }
322
321
plugins/Unity/Launcher/backend/launcherbackend.cpp+266−16
@@ -34,10 +34,12 @@ public:
34 QString desktopFile;
34 QString desktopFile;
35 QString displayName;
35 QString displayName;
36 QString icon;
36 QString icon;
37+ int count;
38+ bool countVisible;
37};
39};
38
40
39LauncherBackend::LauncherBackend(QObject *parent):
41LauncherBackend::LauncherBackend(QObject *parent):
40− QObject(parent),
42+ QDBusVirtualObject(parent),
41 m_accounts(nullptr)
43 m_accounts(nullptr)
42{
44{
43#ifndef LAUNCHER_TESTING
45#ifndef LAUNCHER_TESTING
@@ -45,10 +47,25 @@ LauncherBackend::LauncherBackend(QObject *parent):
45#endif
47#endif
46 m_user = qgetenv("USER");
48 m_user = qgetenv("USER");
47 syncFromAccounts();
49 syncFromAccounts();
50+
51+ /* Set up ourselves on DBus */
52+ QDBusConnection con = QDBusConnection::sessionBus();
53+ if (!con.registerService("com.canonical.Unity.Launcher")) {
54+ qDebug() << "Unable to register launcher name";
55+ }
56+ if (!con.registerVirtualObject("/com/canonical/Unity/Launcher", this, QDBusConnection::VirtualObjectRegisterOption::SubPath)) {
57+ qDebug() << "Unable to register launcher object";
58+ }
48}
59}
49
60
50LauncherBackend::~LauncherBackend()
61LauncherBackend::~LauncherBackend()
51{
62{
63+ /* Remove oursevles from DBus */
64+ QDBusConnection con = QDBusConnection::sessionBus();
65+ con.unregisterService("com.canonical.Unity.Launcher");
66+ con.unregisterObject("/com/canonical/Unity/Launcher");
67+
68+ /* Clear data */
52 m_storedApps.clear();
69 m_storedApps.clear();
53
70
54 Q_FOREACH(LauncherBackendItem *item, m_itemCache) {
71 Q_FOREACH(LauncherBackendItem *item, m_itemCache) {
@@ -90,7 +107,7 @@ void LauncherBackend::setStoredApplications(const QStringList &appIds)
90
107
91QString LauncherBackend::desktopFile(const QString &appId) const
108QString LauncherBackend::desktopFile(const QString &appId) const
92{
109{
93− LauncherBackendItem *item = m_itemCache.value(appId);
110+ LauncherBackendItem *item = m_itemCache.value(appId, nullptr);
94 if (item) {
111 if (item) {
95 return item->desktopFile;
112 return item->desktopFile;
96 }
113 }
@@ -100,7 +117,7 @@ QString LauncherBackend::desktopFile(const QString &appId) const
100
117
101QString LauncherBackend::displayName(const QString &appId) const
118QString LauncherBackend::displayName(const QString &appId) const
102{
119{
103− LauncherBackendItem *item = m_itemCache.value(appId);
120+ LauncherBackendItem *item = m_itemCache.value(appId, nullptr);
104 if (item) {
121 if (item) {
105 return item->displayName;
122 return item->displayName;
106 }
123 }
@@ -118,16 +135,9 @@ QString LauncherBackend::displayName(const QString &appId) const
118QString LauncherBackend::icon(const QString &appId) const
135QString LauncherBackend::icon(const QString &appId) const
119{
136{
120 QString iconName;
137 QString iconName;
121− LauncherBackendItem *item = m_itemCache.value(appId);
138+ LauncherBackendItem *item = getItem(appId);
122 if (item) {
139 if (item) {
123 iconName = item->icon;
140 iconName = item->icon;
124− } else {
125− QString df = findDesktopFile(appId);
126− if (!df.isEmpty()) {
127− LauncherBackendItem *item = parseDesktopFile(df);
128− m_itemCache.insert(appId, item);
129− iconName = item->icon;
130− }
131 }
141 }
132
142
133 return iconName;
143 return iconName;
@@ -153,10 +163,70 @@ int LauncherBackend::progress(const QString &appId) const
153
163
154int LauncherBackend::count(const QString &appId) const
164int LauncherBackend::count(const QString &appId) const
155{
165{
156− // TODO: Return value for count emblem.
166+ int count = -1;
157− // TODO: emit countChanged() when this value changes.
167+ LauncherBackendItem *item = getItem(appId);
158− Q_UNUSED(appId)
168+
169+ if (item) {
170+ if (item->countVisible) {
171+ count = item->count;
172+ }
173+ }
174+
175+ return count;
176+}
177+
178+void LauncherBackend::setCount(const QString &appId, int count) const
179+{
180+ LauncherBackendItem *item = getItem(appId);
181+
182+ bool emitchange = false;
183+ if (item) {
184+ emitchange = (item->count != count);
185+ item->count = count;
186+ }
187+
188+ if (emitchange) {
189+ /* TODO: This needs to use the accessor to handle the visibility
190+ correctly, but when we have the two properties we can just use
191+ the local value */
192+ Q_EMIT countChanged(appId, this->count(appId));
193+ QVariant vcount(item->count);
194+ emitPropChangedDbus(appId, "count", vcount);
195+ }
196+}
197+
198+bool LauncherBackend::countVisible(const QString &appId) const
199+{
200+ bool visible = false;
201+ LauncherBackendItem *item = getItem(appId);
202+
203+ if (item) {
204+ visible = item->countVisible;
205+ }
206+
159− return 0;
207+ return visible;
208+}
209+
210+void LauncherBackend::setCountVisible(const QString &appId, bool visible) const
211+{
212+ LauncherBackendItem *item = getItem(appId);
213+
214+ bool emitchange = false;
215+ if (item) {
216+ emitchange = (item->countVisible != visible);
217+ item->countVisible = visible;
218+ } else {
219+ qDebug() << "Unable to find:" << appId;
220+ }
221+
222+ if (emitchange) {
223+ /* TODO: Because we're using visible in determining the
224+ count we need to emit a count changed as well */
225+ Q_EMIT countChanged(appId, this->count(appId));
226+ Q_EMIT countVisibleChanged(appId, item->countVisible);
227+ QVariant vCountVisible(item->countVisible);
228+ emitPropChangedDbus(appId, "countVisible", vCountVisible);
229+ }
160}
230}
161
231
162void LauncherBackend::setUser(const QString &username)
232void LauncherBackend::setUser(const QString &username)
@@ -275,6 +345,35 @@ LauncherBackendItem* LauncherBackend::parseDesktopFile(const QString &desktopFil
275 } else {
345 } else {
276 item->icon = "image://theme/" + iconString;
346 item->icon = "image://theme/" + iconString;
277 }
347 }
348+
349+ /* TODO: These should be looked up in a cache somewhere */
350+ item->count = 0;
351+ item->countVisible = false;
352+
353+ return item;
354+}
355+
356+/* Gets an item, and tries to create a new one if we need it to */
357+LauncherBackendItem* LauncherBackend::getItem(const QString &appId) const
358+{
359+ LauncherBackendItem *item = m_itemCache.value(appId, nullptr);
360+ if (!item) {
361+ QString df = findDesktopFile(appId);
362+ if (!df.isEmpty()) {
363+ item = parseDesktopFile(df);
364+ if (item) {
365+ m_itemCache[appId] = item;
366+ } else {
367+ qWarning() << "Unable to parse desktop file for" << appId << "path" << df;
368+ }
369+ } else {
370+ qDebug() << "Unable to find desktop file for:" << appId;
371+ }
372+ }
373+
374+ if (!item)
375+ qWarning() << "Unable to find item for: " << appId;
376+
278 return item;
377 return item;
279}
378}
280
379
@@ -285,7 +384,7 @@ void LauncherBackend::loadFromVariant(const QVariantMap &details)
285 }
384 }
286 QString appId = details.value("id").toString();
385 QString appId = details.value("id").toString();
287
386
288− LauncherBackendItem *item = m_itemCache.value(appId);
387+ LauncherBackendItem *item = m_itemCache.value(appId, nullptr);
289 if (item) {
388 if (item) {
290 delete item;
389 delete item;
291 }
390 }
@@ -295,6 +394,8 @@ void LauncherBackend::loadFromVariant(const QVariantMap &details)
295 item->desktopFile = details.value("desktopFile").toString();
394 item->desktopFile = details.value("desktopFile").toString();
296 item->displayName = details.value("name").toString();
395 item->displayName = details.value("name").toString();
297 item->icon = details.value("icon").toString();
396 item->icon = details.value("icon").toString();
397+ item->count = details.value("count").toInt();
398+ item->countVisible = details.value("countVisible").toBool();
298
399
299 m_itemCache.insert(appId, item);
400 m_itemCache.insert(appId, item);
300 m_storedApps.append(appId);
401 m_storedApps.append(appId);
@@ -308,6 +409,8 @@ QVariantMap LauncherBackend::itemToVariant(const QString &appId) const
308 details.insert("name", item->displayName);
409 details.insert("name", item->displayName);
309 details.insert("icon", item->icon);
410 details.insert("icon", item->icon);
310 details.insert("desktopFile", item->desktopFile);
411 details.insert("desktopFile", item->desktopFile);
412+ details.insert("count", item->count);
413+ details.insert("countVisible", item->countVisible);
311 return details;
414 return details;
312}
415}
313
416
@@ -318,3 +421,150 @@ bool LauncherBackend::isDefaultsItem(const QList<QVariantMap> &apps) const
318 // list of one item with the 'defaults' field set to true.
421 // list of one item with the 'defaults' field set to true.
319 return (apps.size() == 1 && apps[0].value("defaults").toBool());
422 return (apps.size() == 1 && apps[0].value("defaults").toBool());
320}
423}
424+
425+bool LauncherBackend::handleMessage(const QDBusMessage& message, const QDBusConnection& connection)
426+{
427+ /* Check to make sure we're getting properties on our interface */
428+ if (message.type() != QDBusMessage::MessageType::MethodCallMessage) {
429+ return false;
430+ }
431+ if (message.interface() != "org.freedesktop.DBus.Properties") {
432+ return false;
433+ }
434+ if (message.arguments()[0].toString() != "com.canonical.Unity.Launcher.Item") {
435+ return false;
436+ }
437+
438+ /* Break down the path to just the app id */
439+ QString pathtemp = message.path();
440+ if (!pathtemp.startsWith("/com/canonical/Unity/Launcher/")) {
441+ return false;
442+ }
443+ pathtemp.remove("/com/canonical/Unity/Launcher/");
444+ if (pathtemp.indexOf('/') >= 0) {
445+ return false;
446+ }
447+
448+ /* Find ourselves an appid */
449+ QString appid = decodeAppId(pathtemp);
450+ QVariantList retval;
451+
452+ if (message.member() == "Get") {
453+ if (message.arguments()[1].toString() == "count") {
454+ retval.append(QVariant::fromValue(QDBusVariant(this->count(appid))));
455+ } else if (message.arguments()[1].toString() == "countVisible") {
456+ retval.append(QVariant::fromValue(QDBusVariant(this->countVisible(appid))));
457+ }
458+ } else if (message.member() == "Set") {
459+ if (message.arguments()[1].toString() == "count") {
460+ this->setCount(appid, message.arguments()[2].value<QDBusVariant>().variant().toInt());
461+ } else if (message.arguments()[1].toString() == "countVisible") {
462+ this->setCountVisible(appid, message.arguments()[2].value<QDBusVariant>().variant().toBool());
463+ }
464+ } else if (message.member() == "GetAll") {
465+ retval.append(this->itemToVariant(appid));
466+ } else {
467+ return false;
468+ }
469+
470+ QDBusMessage reply = message.createReply(retval);
471+ return connection.send(reply);
472+}
473+
474+QString LauncherBackend::introspect(const QString &path) const
475+{
476+ /* This case we should just list the nodes */
477+ if (path == "/com/canonical/Unity/Launcher/" || path == "/com/canonical/Unity/Launcher") {
478+ QString nodes;
479+
480+ Q_FOREACH(const QString &appId, m_itemCache.keys()) {
481+ nodes.append("<node name=\"");
482+ nodes.append(encodeAppId(appId));
483+ nodes.append("\"/>\n");
484+ }
485+
486+ return nodes;
487+ }
488+
489+ /* Should not happen, but let's handle it */
490+ if (!path.startsWith("/com/canonical/Unity/Launcher")) {
491+ return "";
492+ }
493+
494+ /* Now we should be looking at a node */
495+ QString nodeiface =
496+ "<interface name=\"com.canonical.Unity.Launcher.Item\">"
497+ "<property name=\"count\" type=\"i\" access=\"readwrite\" />"
498+ "<property name=\"countVisible\" type=\"b\" access=\"readwrite\" />"
499+ "</interface>";
500+ return nodeiface;
501+}
502+
503+QString LauncherBackend::decodeAppId(const QString& path)
504+{
505+ QByteArray bytes = path.toUtf8();
506+ QByteArray decoded;
507+
508+ for (int i = 0; i < bytes.size(); ++i) {
509+ char chr = bytes.at(i);
510+
511+ if (chr == '_') {
512+ QString number;
513+ number.append(bytes.at(i+1));
514+ number.append(bytes.at(i+2));
515+
516+ bool okay;
517+ char newchar = number.toUInt(&okay, 16);
518+ if (okay)
519+ decoded.append(newchar);
520+
521+ i += 2;
522+ } else {
523+ decoded.append(chr);
524+ }
525+ }
526+
527+ return QString::fromUtf8(decoded);
528+}
529+
530+QString LauncherBackend::encodeAppId(const QString& appId)
531+{
532+ QByteArray bytes = appId.toUtf8();
533+ QString encoded;
534+
535+ for (int i = 0; i < bytes.size(); ++i) {
536+ uchar chr = bytes.at(i);
537+
538+ if ((chr >= 'a' && chr <= 'z') ||
539+ (chr >= 'A' && chr <= 'Z') ||
540+ (chr >= '0' && chr <= '9'&& i != 0)) {
541+ encoded.append(chr);
542+ } else {
543+ QString hexval = QString("_%1").arg(chr, 2, 16, QChar('0'));
544+ encoded.append(hexval.toUpper());
545+ }
546+ }
547+
548+ return encoded;
549+}
550+
551+void LauncherBackend::emitPropChangedDbus(const QString& appId, const QString& property, QVariant &value) const
552+{
553+ QString path("/com/canonical/Unity/Launcher/");
554+ path.append(encodeAppId(appId));
555+
556+ QDBusMessage message = QDBusMessage::createSignal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged");
557+
558+ QList<QVariant> arguments;
559+ QVariantHash changedprops;
560+ changedprops[property] = QVariant::fromValue(QDBusVariant(value));
561+ QVariantList deletedprops;
562+
563+ arguments.append(changedprops);
564+ arguments.append(deletedprops);
565+
566+ message.setArguments(arguments);
567+
568+ QDBusConnection con = QDBusConnection::sessionBus();
569+ con.send(message);
570+}
plugins/Unity/Launcher/backend/launcherbackend.h+52−4
@@ -24,6 +24,7 @@
24#include <QObject>
24#include <QObject>
25#include <QSettings>
25#include <QSettings>
26#include <QStringList>
26#include <QStringList>
27+#include <QDBusVirtualObject>
27
28
28class AccountsServiceDBusAdaptor;
29class AccountsServiceDBusAdaptor;
29
30
@@ -32,11 +33,13 @@ class AccountsServiceDBusAdaptor;
32 */
33 */
33
34
34class LauncherBackendItem;
35class LauncherBackendItem;
36+class LauncherBackendTest;
35
37
36−class LauncherBackend : public QObject
38+class LauncherBackend : public QDBusVirtualObject
37{
39{
38 Q_OBJECT
40 Q_OBJECT
39
41
42+ friend LauncherBackendTest;
40
43
41public:
44public:
42 LauncherBackend(QObject *parent = 0);
45 LauncherBackend(QObject *parent = 0);
@@ -116,16 +119,53 @@ public:
116 */
119 */
117 int count(const QString &appId) const;
120 int count(const QString &appId) const;
118
121
122+ /**
123+ * @brief Set the count on an item
124+ * @param appId The ID of the application
125+ * @param count Count to show on the application
126+ */
127+ void setCount(const QString &appId, int count) const;
128+
129+ /**
130+ * @brief Get whether the count should be visible
131+ * @param appId The ID of the application.
132+ * @returns Whether to show a count on the launcher
133+ */
134+ bool countVisible(const QString &appId) const;
135+
136+ /**
137+ * @brief Set the visibility of the count item
138+ * @param appId The ID of the application
139+ * @param visible Whether the count should be visible
140+ */
141+ void setCountVisible(const QString &appId, bool visible) const;
142+
119 /**
143 /**
120 * @brief Sets the username for which to look up launcher items.
144 * @brief Sets the username for which to look up launcher items.
121 * @param username The username to use.
145 * @param username The username to use.
122 */
146 */
123 void setUser(const QString &username);
147 void setUser(const QString &username);
124
148
149+ /**
150+ * @brief Handle a message to an application node
151+ * @param message DBus message to handle
152+ * @param connection DBus connection that we're using
153+ * @returns whether the message was handled
154+ */
155+ virtual bool handleMessage(const QDBusMessage& message, const QDBusConnection& connection);
156+
157+ /**
158+ * @brief Get introspection information on the objects we're exporting
159+ * @param path the dbus path containing the appid
160+ * @returns Introspection information for that node in the tree
161+ */
162+ virtual QString introspect (const QString &path) const;
163+
125Q_SIGNALS:
164Q_SIGNALS:
126− void quickListChanged(const QString &appId, const QList<QuickListEntry> &quickList);
165+ void quickListChanged(const QString &appId, const QList<QuickListEntry> &quickList) const;
127− void progressChanged(const QString &appId, int progress);
166+ void progressChanged(const QString &appId, int progress) const;
128− void countChanged(const QString &appId, int count);
167+ void countChanged(const QString &appId, int count) const;
168+ void countVisibleChanged(const QString &appId, bool visible) const;
129
169
130private:
170private:
131 QString findDesktopFile(const QString &appId) const;
171 QString findDesktopFile(const QString &appId) const;
@@ -143,6 +183,14 @@ private:
143
183
144 AccountsServiceDBusAdaptor *m_accounts;
184 AccountsServiceDBusAdaptor *m_accounts;
145 QString m_user;
185 QString m_user;
186+
187+ void emitPropChangedDbus(const QString& appId, const QString& property, QVariant &value) const;
188+
189+protected: /* Protected to allow testing */
190+ LauncherBackendItem* getItem(const QString& appId) const;
191+
192+ static QString decodeAppId(const QString& path);
193+ static QString encodeAppId(const QString& appId);
146};
194};
147
195
148#endif // LAUNCHERBACKEND_H
196#endif // LAUNCHERBACKEND_H
plugins/Utils/CMakeLists.txt−1
@@ -11,7 +11,6 @@ include_directories(
11)
11)
12
12
13set(QMLPLUGIN_SRC
13set(QMLPLUGIN_SRC
14− bottombarvisibilitycommunicatorshell.cpp
15 qlimitproxymodelqml.cpp
14 qlimitproxymodelqml.cpp
16 qsortfilterproxymodelqml.cpp
15 qsortfilterproxymodelqml.cpp
17 timeformatter.cpp
16 timeformatter.cpp
plugins/Utils/bottombarvisibilitycommunicatorshell.cppdeleted−49
@@ -1,49 +0,0 @@
1−/*
2− * Copyright (C) 2012 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−#include "bottombarvisibilitycommunicatorshell.h"
18−
19−BottomBarVisibilityCommunicatorShell::BottomBarVisibilityCommunicatorShell()
20− : m_forceHidden(false),
21− m_position(0)
22−{
23−}
24−
25−bool BottomBarVisibilityCommunicatorShell::forceHidden() const
26−{
27− return m_forceHidden;
28−}
29−
30−double BottomBarVisibilityCommunicatorShell::position() const
31−{
32− return m_position;
33−}
34−
35−void BottomBarVisibilityCommunicatorShell::setForceHidden(bool forceHidden)
36−{
37− if (forceHidden != m_forceHidden) {
38− m_forceHidden = forceHidden;
39− Q_EMIT forceHiddenChanged(forceHidden);
40− }
41−}
42−
43−void BottomBarVisibilityCommunicatorShell::setPosition(double position)
44−{
45− if (position != m_position) {
46− m_position = position;
47− Q_EMIT positionChanged(position);
48− }
49−}
plugins/Utils/bottombarvisibilitycommunicatorshell.hdeleted−59
@@ -1,59 +0,0 @@
1−/*
2− * Copyright (C) 2012 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−#ifndef BOTTOMBARVISIBILITYCOMMUNICATORSHELL_H
18−#define BOTTOMBARVISIBILITYCOMMUNICATORSHELL_H
19−
20−#include <QObject>
21−
22−class QDBusInterface;
23−
24−/** This is an internal class used to talk with the bottom bar used by either
25− * applications or the SDK.
26− * There is a method to force the bottom bar to be hidden or otherwise behave as usual
27− */
28−
29−class BottomBarVisibilityCommunicatorShell : public QObject
30−{
31− Q_OBJECT
32− Q_PROPERTY(bool forceHidden READ forceHidden WRITE setForceHidden NOTIFY forceHiddenChanged)
33− Q_PROPERTY(double position READ position WRITE setPosition NOTIFY positionChanged)
34−
35− Q_CLASSINFO("D-Bus Interface", "com.canonical.Shell.BottomBarVisibilityCommunicator")
36−public:
37− static BottomBarVisibilityCommunicatorShell& instance() {
38− static BottomBarVisibilityCommunicatorShell instance;
39− return instance;
40− }
41−
42− bool forceHidden() const;
43− void setForceHidden(bool forceHidden);
44−
45− double position() const;
46− void setPosition(double position);
47−
48−Q_SIGNALS:
49− void forceHiddenChanged(bool forceHidden);
50− void positionChanged(double position);
51−
52−private:
53− BottomBarVisibilityCommunicatorShell();
54−
55− bool m_forceHidden;
56− double m_position;
57−};
58−
59−#endif
plugins/Utils/plugin.cpp−10
@@ -26,16 +26,12 @@
26#include "plugin.h"
26#include "plugin.h"
27
27
28// local
28// local
29−#include "bottombarvisibilitycommunicatorshell.h"
30#include "qlimitproxymodelqml.h"
29#include "qlimitproxymodelqml.h"
31#include "qsortfilterproxymodelqml.h"
30#include "qsortfilterproxymodelqml.h"
32#include "timeformatter.h"
31#include "timeformatter.h"
33#include "unitymenumodelpaths.h"
32#include "unitymenumodelpaths.h"
34#include "easingcurve.h"
33#include "easingcurve.h"
35
34
36−static const char* BOTTOM_BAR_VISIBILITY_COMMUNICATOR_DBUS_PATH = "/BottomBarVisibilityCommunicator";
37−static const char* DBUS_SERVICE = "com.canonical.Shell.BottomBarVisibilityCommunicator";
38−
39void UtilsPlugin::registerTypes(const char *uri)
35void UtilsPlugin::registerTypes(const char *uri)
40{
36{
41 Q_ASSERT(uri == QLatin1String("Utils"));
37 Q_ASSERT(uri == QLatin1String("Utils"));
@@ -45,16 +41,10 @@ void UtilsPlugin::registerTypes(const char *uri)
45 qmlRegisterType<UnityMenuModelPaths>(uri, 0, 1, "UnityMenuModelPaths");
41 qmlRegisterType<UnityMenuModelPaths>(uri, 0, 1, "UnityMenuModelPaths");
46 qmlRegisterType<TimeFormatter>(uri, 0, 1, "TimeFormatter");
42 qmlRegisterType<TimeFormatter>(uri, 0, 1, "TimeFormatter");
47 qmlRegisterType<GDateTimeFormatter>(uri, 0, 1, "GDateTimeFormatter");
43 qmlRegisterType<GDateTimeFormatter>(uri, 0, 1, "GDateTimeFormatter");
48− qmlRegisterUncreatableType<BottomBarVisibilityCommunicatorShell>(uri, 0, 1, "BottomBarVisibilityCommunicatorShell", "Can't create BottomBarVisibilityCommunicatorShell");
49 qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve");
44 qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve");
50}
45}
51
46
52void UtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
47void UtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
53{
48{
54 QQmlExtensionPlugin::initializeEngine(engine, uri);
49 QQmlExtensionPlugin::initializeEngine(engine, uri);
55−
56− QDBusConnection::sessionBus().registerService(DBUS_SERVICE);
57− BottomBarVisibilityCommunicatorShell *bottomBarVisibilityCommunicator = &BottomBarVisibilityCommunicatorShell::instance();
58− QDBusConnection::sessionBus().registerObject(BOTTOM_BAR_VISIBILITY_COMMUNICATOR_DBUS_PATH, bottomBarVisibilityCommunicator, QDBusConnection::ExportAllContents);
59− engine->rootContext()->setContextProperty("bottomBarVisibilityCommunicatorShell", bottomBarVisibilityCommunicator);
60}
50}
po/fr.po+24−15
@@ -8,14 +8,14 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2014-04-10 11:13-0400\n"
10"POT-Creation-Date: 2014-04-10 11:13-0400\n"
11−"PO-Revision-Date: 2014-01-28 00:34+0000\n"
11+"PO-Revision-Date: 2014-05-08 17:29+0000\n"
12−"Last-Translator: Pierre <Unknown>\n"
12+"Last-Translator: Sébastien Maes <nautilussebastien@gmail.com>\n"
13"Language-Team: French <fr@li.org>\n"
13"Language-Team: French <fr@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-05-01 06:43+0000\n"
17+"X-Launchpad-Export-Date: 2014-05-10 08:01+0000\n"
18−"X-Generator: Launchpad (build 16985)\n"
18+"X-Generator: Launchpad (build 16996)\n"
19
19
20#: plugins/Unity/Launcher/launcheritem.cpp:43
20#: plugins/Unity/Launcher/launcheritem.cpp:43
21#: plugins/Unity/Launcher/launcheritem.cpp:73
21#: plugins/Unity/Launcher/launcheritem.cpp:73
@@ -24,7 +24,7 @@ msgstr "Conserver dans le lanceur"
24
24
25#: plugins/Unity/Launcher/launcheritem.cpp:73
25#: plugins/Unity/Launcher/launcheritem.cpp:73
26msgid "Unlock from Launcher"
26msgid "Unlock from Launcher"
27−msgstr ""
27+msgstr "Retirer du lanceur"
28
28
29#: qml/Components/EdgeDemoOverlay.qml:151
29#: qml/Components/EdgeDemoOverlay.qml:151
30msgid "Skip intro"
30msgid "Skip intro"
@@ -37,6 +37,7 @@ msgstr "Bord droit"
37#: qml/Components/EdgeDemo.qml:114
37#: qml/Components/EdgeDemo.qml:114
38msgid "Try swiping from the right edge to unlock the phone"
38msgid "Try swiping from the right edge to unlock the phone"
39msgstr ""
39msgstr ""
40+"Faites glisser votre doigt à partir du bord droit pour déverrouiller."
40
41
41#: qml/Components/EdgeDemo.qml:145
42#: qml/Components/EdgeDemo.qml:145
42msgid "Top edge"
43msgid "Top edge"
@@ -45,6 +46,8 @@ msgstr "Bord supérieur"
45#: qml/Components/EdgeDemo.qml:146
46#: qml/Components/EdgeDemo.qml:146
46msgid "Try swiping from the top edge to access the indicators"
47msgid "Try swiping from the top edge to access the indicators"
47msgstr ""
48msgstr ""
49+"Faites glisser votre doigt à partir du bord supérieur pour accéder aux "
50+"indicateurs."
48
51
49#: qml/Components/EdgeDemo.qml:171
52#: qml/Components/EdgeDemo.qml:171
50msgid "Close"
53msgid "Close"
@@ -53,6 +56,8 @@ msgstr "Fermer"
53#: qml/Components/EdgeDemo.qml:172
56#: qml/Components/EdgeDemo.qml:172
54msgid "Swipe up again to close the settings screen"
57msgid "Swipe up again to close the settings screen"
55msgstr ""
58msgstr ""
59+"Faites glisser à nouveau votre doigt vers le bord supérieur pour fermer "
60+"l'écran des paramètres"
56
61
57#: qml/Components/EdgeDemo.qml:199
62#: qml/Components/EdgeDemo.qml:199
58msgid "Left edge"
63msgid "Left edge"
@@ -61,16 +66,20 @@ msgstr "Bord gauche"
61#: qml/Components/EdgeDemo.qml:200
66#: qml/Components/EdgeDemo.qml:200
62msgid "Swipe from the left to reveal the launcher for quick access to apps"
67msgid "Swipe from the left to reveal the launcher for quick access to apps"
63msgstr ""
68msgstr ""
69+"Faites glisser votre doigt à partir du bord gauche pour afficher le lanceur "
70+"d'applications."
64
71
65#: qml/Components/EdgeDemo.qml:227
72#: qml/Components/EdgeDemo.qml:227
66msgid "Well done"
73msgid "Well done"
67−msgstr ""
74+msgstr "Félicitations"
68
75
69#: qml/Components/EdgeDemo.qml:228
76#: qml/Components/EdgeDemo.qml:228
70msgid ""
77msgid ""
71"You have now mastered the edge gestures and can start using the "
78"You have now mastered the edge gestures and can start using the "
72"phone<br><br>Tap on the screen to start"
79"phone<br><br>Tap on the screen to start"
73msgstr ""
80msgstr ""
81+"Vous maîtrisez maintenant les différents gestes et pouvez commencer à "
82+"utiliser le téléphone<br><br>Appuyez sur l'écran pour commencer"
74
83
75#: qml/Components/PageHeader.qml:365
84#: qml/Components/PageHeader.qml:365
76msgid "Recent searches"
85msgid "Recent searches"
@@ -78,28 +87,28 @@ msgstr "Recherches récentes"
78
87
79#: qml/Components/SeeMore.qml:35
88#: qml/Components/SeeMore.qml:35
80msgid "See more"
89msgid "See more"
81−msgstr ""
90+msgstr "Voir plus"
82
91
83#: qml/Components/SeeMore.qml:58
92#: qml/Components/SeeMore.qml:58
84msgid "See less"
93msgid "See less"
85−msgstr ""
94+msgstr "Voir moins"
86
95
87#: qml/Dash/DashApps.qml:37
96#: qml/Dash/DashApps.qml:37
88msgid "Recent"
97msgid "Recent"
89−msgstr ""
98+msgstr "Récent"
90
99
91#: qml/Dash/PreviewListView.qml:52
100#: qml/Dash/PreviewListView.qml:52
92#, qt-format
101#, qt-format
93msgid "%1 Preview"
102msgid "%1 Preview"
94−msgstr ""
103+msgstr "%1 Aperçu"
95
104
96#: qml/Dash/Previews/PreviewActionCombo.qml:34
105#: qml/Dash/Previews/PreviewActionCombo.qml:34
97msgid "More..."
106msgid "More..."
98−msgstr ""
107+msgstr "Plus..."
99
108
100#: qml/Dash/Previews/PreviewActionCombo.qml:34
109#: qml/Dash/Previews/PreviewActionCombo.qml:34
101msgid "Less..."
110msgid "Less..."
102−msgstr ""
111+msgstr "Moins..."
103
112
104#: qml/Dash/Previews/PreviewRatingInput.qml:81
113#: qml/Dash/Previews/PreviewRatingInput.qml:81
105msgid "Rate this"
114msgid "Rate this"
@@ -115,7 +124,7 @@ msgstr "Envoyer"
115
124
116#: qml/Greeter/Greeter.qml:151
125#: qml/Greeter/Greeter.qml:151
117msgid "Swipe to unlock"
126msgid "Swipe to unlock"
118−msgstr ""
127+msgstr "Faites glisser pour déverrouiller"
119
128
120#: qml/Greeter/Lockscreen.qml:149
129#: qml/Greeter/Lockscreen.qml:149
121msgid "Emergency Call"
130msgid "Emergency Call"
@@ -148,7 +157,7 @@ msgstr "Parlez maintenant…"
148
157
149#: qml/Hud/Hud.qml:94
158#: qml/Hud/Hud.qml:94
150msgid "Speaking..."
159msgid "Speaking..."
151−msgstr ""
160+msgstr "En cours d'écoute..."
152
161
153#: qml/Notifications/NotificationMenuItemFactory.qml:91
162#: qml/Notifications/NotificationMenuItemFactory.qml:91
154msgid "Show password"
163msgid "Show password"
@@ -156,7 +165,7 @@ msgstr "Afficher le mot de passe"
156
165
157#: qml/Notifications/NotificationMenuItemFactory.qml:103
166#: qml/Notifications/NotificationMenuItemFactory.qml:103
158msgid "Please enter SIM PIN"
167msgid "Please enter SIM PIN"
159−msgstr ""
168+msgstr "Veuillez entrer le code PIN de votre carte SIM"
160
169
161#: qml/Panel/SearchIndicator.qml:27
170#: qml/Panel/SearchIndicator.qml:27
162msgid "Search"
171msgid "Search"
po/gl.po+4−4
@@ -8,14 +8,14 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2014-04-10 11:13-0400\n"
10"POT-Creation-Date: 2014-04-10 11:13-0400\n"
11−"PO-Revision-Date: 2014-04-08 07:04+0000\n"
11+"PO-Revision-Date: 2014-05-03 07:31+0000\n"
12"Last-Translator: Marcos Lans <Unknown>\n"
12"Last-Translator: Marcos Lans <Unknown>\n"
13"Language-Team: Galician <gl@li.org>\n"
13"Language-Team: Galician <gl@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-05-01 06:43+0000\n"
17+"X-Launchpad-Export-Date: 2014-05-06 07:34+0000\n"
18−"X-Generator: Launchpad (build 16985)\n"
18+"X-Generator: Launchpad (build 16996)\n"
19
19
20#: plugins/Unity/Launcher/launcheritem.cpp:43
20#: plugins/Unity/Launcher/launcheritem.cpp:43
21#: plugins/Unity/Launcher/launcheritem.cpp:73
21#: plugins/Unity/Launcher/launcheritem.cpp:73
@@ -117,7 +117,7 @@ msgstr "Enviar"
117
117
118#: qml/Greeter/Greeter.qml:151
118#: qml/Greeter/Greeter.qml:151
119msgid "Swipe to unlock"
119msgid "Swipe to unlock"
120−msgstr ""
120+msgstr "Esvare para desbloquear"
121
121
122#: qml/Greeter/Lockscreen.qml:149
122#: qml/Greeter/Lockscreen.qml:149
123msgid "Emergency Call"
123msgid "Emergency Call"
po/lv.po+21−21
@@ -8,27 +8,27 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2014-04-10 11:13-0400\n"
10"POT-Creation-Date: 2014-04-10 11:13-0400\n"
11−"PO-Revision-Date: 2014-01-11 16:48+0000\n"
11+"PO-Revision-Date: 2014-05-07 18:17+0000\n"
12"Last-Translator: Jānis-Marks Gailis <jeanmarc.gailis@gmail.com>\n"
12"Last-Translator: Jānis-Marks Gailis <jeanmarc.gailis@gmail.com>\n"
13"Language-Team: Latvian <lv@li.org>\n"
13"Language-Team: Latvian <lv@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-05-01 06:43+0000\n"
17+"X-Launchpad-Export-Date: 2014-05-10 08:01+0000\n"
18−"X-Generator: Launchpad (build 16985)\n"
18+"X-Generator: Launchpad (build 16996)\n"
19
19
20#: plugins/Unity/Launcher/launcheritem.cpp:43
20#: plugins/Unity/Launcher/launcheritem.cpp:43
21#: plugins/Unity/Launcher/launcheritem.cpp:73
21#: plugins/Unity/Launcher/launcheritem.cpp:73
22msgid "Lock to Launcher"
22msgid "Lock to Launcher"
23−msgstr ""
23+msgstr "Pieslēgt palaidējam"
24
24
25#: plugins/Unity/Launcher/launcheritem.cpp:73
25#: plugins/Unity/Launcher/launcheritem.cpp:73
26msgid "Unlock from Launcher"
26msgid "Unlock from Launcher"
27−msgstr ""
27+msgstr "Atslēgt no palaidēja"
28
28
29#: qml/Components/EdgeDemoOverlay.qml:151
29#: qml/Components/EdgeDemoOverlay.qml:151
30msgid "Skip intro"
30msgid "Skip intro"
31−msgstr ""
31+msgstr "Izlaist Intro"
32
32
33#: qml/Components/EdgeDemo.qml:113
33#: qml/Components/EdgeDemo.qml:113
34msgid "Right edge"
34msgid "Right edge"
@@ -36,7 +36,7 @@ msgstr "Labā mala"
36
36
37#: qml/Components/EdgeDemo.qml:114
37#: qml/Components/EdgeDemo.qml:114
38msgid "Try swiping from the right edge to unlock the phone"
38msgid "Try swiping from the right edge to unlock the phone"
39−msgstr ""
39+msgstr "Mēģiniet iesvelt no labās malas, lai atbloķētu tālruni"
40
40
41#: qml/Components/EdgeDemo.qml:145
41#: qml/Components/EdgeDemo.qml:145
42msgid "Top edge"
42msgid "Top edge"
@@ -44,7 +44,7 @@ msgstr "Augšējā mala"
44
44
45#: qml/Components/EdgeDemo.qml:146
45#: qml/Components/EdgeDemo.qml:146
46msgid "Try swiping from the top edge to access the indicators"
46msgid "Try swiping from the top edge to access the indicators"
47−msgstr ""
47+msgstr "Mēģiniet iesvelt no augšējās malas, lai piekļūt pie indikatoriem"
48
48
49#: qml/Components/EdgeDemo.qml:171
49#: qml/Components/EdgeDemo.qml:171
50msgid "Close"
50msgid "Close"
@@ -78,15 +78,15 @@ msgstr "Nesen veiktās meklēšanas"
78
78
79#: qml/Components/SeeMore.qml:35
79#: qml/Components/SeeMore.qml:35
80msgid "See more"
80msgid "See more"
81−msgstr ""
81+msgstr "Redzēt vairāk"
82
82
83#: qml/Components/SeeMore.qml:58
83#: qml/Components/SeeMore.qml:58
84msgid "See less"
84msgid "See less"
85−msgstr ""
85+msgstr "Redzēt mazāk"
86
86
87#: qml/Dash/DashApps.qml:37
87#: qml/Dash/DashApps.qml:37
88msgid "Recent"
88msgid "Recent"
89−msgstr ""
89+msgstr "Nesens"
90
90
91#: qml/Dash/PreviewListView.qml:52
91#: qml/Dash/PreviewListView.qml:52
92#, qt-format
92#, qt-format
@@ -95,23 +95,23 @@ msgstr ""
95
95
96#: qml/Dash/Previews/PreviewActionCombo.qml:34
96#: qml/Dash/Previews/PreviewActionCombo.qml:34
97msgid "More..."
97msgid "More..."
98−msgstr ""
98+msgstr "Vairāk..."
99
99
100#: qml/Dash/Previews/PreviewActionCombo.qml:34
100#: qml/Dash/Previews/PreviewActionCombo.qml:34
101msgid "Less..."
101msgid "Less..."
102−msgstr ""
102+msgstr "Mazāk..."
103
103
104#: qml/Dash/Previews/PreviewRatingInput.qml:81
104#: qml/Dash/Previews/PreviewRatingInput.qml:81
105msgid "Rate this"
105msgid "Rate this"
106−msgstr ""
106+msgstr "Novērtēt šo"
107
107
108#: qml/Dash/Previews/PreviewRatingInput.qml:126
108#: qml/Dash/Previews/PreviewRatingInput.qml:126
109msgid "Add a review"
109msgid "Add a review"
110−msgstr ""
110+msgstr "Komentēt"
111
111
112#: qml/Dash/Previews/PreviewRatingInput.qml:166
112#: qml/Dash/Previews/PreviewRatingInput.qml:166
113msgid "Send"
113msgid "Send"
114−msgstr ""
114+msgstr "Sūtīt"
115
115
116#: qml/Greeter/Greeter.qml:151
116#: qml/Greeter/Greeter.qml:151
117msgid "Swipe to unlock"
117msgid "Swipe to unlock"
@@ -119,16 +119,16 @@ msgstr ""
119
119
120#: qml/Greeter/Lockscreen.qml:149
120#: qml/Greeter/Lockscreen.qml:149
121msgid "Emergency Call"
121msgid "Emergency Call"
122−msgstr ""
122+msgstr "Neatliekamās Palīdzības zvans"
123
123
124#: qml/Greeter/PassphraseLockscreen.qml:59
124#: qml/Greeter/PassphraseLockscreen.qml:59
125#, qt-format
125#, qt-format
126msgid "Hello %1"
126msgid "Hello %1"
127−msgstr ""
127+msgstr "Sveiki, %1"
128
128
129#: qml/Greeter/PassphraseLockscreen.qml:59
129#: qml/Greeter/PassphraseLockscreen.qml:59
130msgid "Hello"
130msgid "Hello"
131−msgstr ""
131+msgstr "Sveiki"
132
132
133#: qml/Hud/HudParametrizedActionsPage.qml:132
133#: qml/Hud/HudParametrizedActionsPage.qml:132
134msgid "Confirm"
134msgid "Confirm"
@@ -152,7 +152,7 @@ msgstr "Runa..."
152
152
153#: qml/Notifications/NotificationMenuItemFactory.qml:91
153#: qml/Notifications/NotificationMenuItemFactory.qml:91
154msgid "Show password"
154msgid "Show password"
155−msgstr ""
155+msgstr "Rādīt paroli"
156
156
157#: qml/Notifications/NotificationMenuItemFactory.qml:103
157#: qml/Notifications/NotificationMenuItemFactory.qml:103
158msgid "Please enter SIM PIN"
158msgid "Please enter SIM PIN"
@@ -165,4 +165,4 @@ msgstr "Meklēt"
165#: qml/Shell.qml:348
165#: qml/Shell.qml:348
166#, qt-format
166#, qt-format
167msgid "Please enter %1"
167msgid "Please enter %1"
168−msgstr ""
168+msgstr "Lūdzu ievadiet %1"
qml/Bottombar/Bottombar.qmldeleted−227
@@ -1,227 +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 "../Components"
19−import Utils 0.1
20−import Unity.Application 0.1
21−import Ubuntu.Gestures 0.1
22−import Ubuntu.Components 0.1
23−
24−Item {
25− id: bottombar
26−
27− // Whether there's an application on foreground (as opposed to have shell's Dash on foreground)
28− property bool applicationIsOnForeground
29−
30− property variant theHud
31− property bool enabled: false
32− property bool preventHiding: dragArea.dragging
33− readonly property real bottomEdgeButtonCenterDistance: units.gu(34)
34−
35− state: "hidden"
36−
37− function hide() {
38− dismissTimer.stop()
39− bottombar.state = "hidden"
40− }
41−
42− onApplicationIsOnForegroundChanged: {
43− if (!applicationIsOnForeground) {
44− hide()
45− }
46− }
47−
48− onStateChanged: {
49− if (state == "hidden") {
50− dismissTimer.stop()
51− bottomBarVisibilityCommunicatorShell.forceHidden = false
52− } else {
53− dismissTimer.restart()
54− }
55− }
56−
57− onPreventHidingChanged: {
58− if (!preventHiding) {
59− if (state == "hint" || state == "reveal")
60− hide()
61− }
62−
63− if (dismissTimer.running) {
64− dismissTimer.restart();
65− }
66− }
67−
68− Timer {
69− id: dismissTimer
70− interval: 1000
71− onTriggered: {
72− if (!bottombar.preventHiding) {
73− bottombar.state = "hidden"
74− } else {
75− dismissTimer.restart()
76− }
77− }
78− }
79−
80− HudButton {
81− id: hudButton
82−
83− readonly property bool centeredHud: parent.width < units.gu(68) // Nexus 7 has 67 gu width
84−
85− x: centeredHud ? parent.width / 2 - width / 2 : MathUtils.clamp(dragArea.touchStartX - (width / 2), 0, bottombar.width - width)
86− y: bottombar.height - bottomEdgeButtonCenterDistance - (height / 2) - bottomMargin
87− z: 1
88− visible: opacity != 0
89−
90− mouseOver: {
91− if (dragArea.status === DirectionalDragArea.Recognized) {
92− var touchLocal = mapFromItem(dragArea, dragArea.touchX, dragArea.touchY)
93− return touchLocal.x > 0 && touchLocal.x < width
94− && touchLocal.y > 0 && touchLocal.y < height
95− } else {
96− return false
97− }
98− }
99−
100− onClicked: theHud.show()
101−
102− Behavior on bottomMargin {
103− NumberAnimation{duration: hudButton.opacity < 0.01 ? 200 : 70; easing.type: Easing.OutQuart}
104− }
105−
106− Behavior on opacity {
107− NumberAnimation{duration: 200; easing.type: Easing.OutCubic}
108− }
109− }
110−
111− Connections {
112− target: theHud
113− onShownChanged: {
114− bottomBarVisibilityCommunicatorShell.forceHidden = theHud.shown
115− if (theHud.shown) {
116− bottombar.state = "hidden"
117− }
118− }
119− }
120−
121− EdgeDragArea {
122− id: dragArea
123− objectName: "hudDragArea"
124− width: parent.width
125− height: shell.edgeSize
126− anchors.bottom: parent.bottom
127−
128− distanceThreshold: units.gu(8)
129− enabled: !theHud.shown && bottombar.enabled && applicationIsOnForeground
130− direction: Direction.Upwards
131− maxSilenceTime: 2000
132−
133− property int previousStatus: -1
134− property real touchStartX: -1
135−
136− readonly property real distanceFromThreshold: (-distance) - distanceThreshold // distance is negative
137− readonly property real revealDistance: units.gu(2)
138− readonly property real commitDistance: units.gu(6)
139− readonly property real commitProgress: MathUtils.clamp(distanceFromThreshold / commitDistance, 0, 1)
140−
141− onStatusChanged: {
142− if (status === DirectionalDragArea.WaitingForTouch) {
143− if (previousStatus == DirectionalDragArea.Recognized) {
144− if (hudButton.mouseOver) {
145− hudButton.clicked()
146− }
147− }
148− } else if (status === DirectionalDragArea.Undecided) {
149− if (!hudButton.centeredHud) {
150− touchStartX = touchX
151− }
152− } else if (status === DirectionalDragArea.Recognized) {
153− bottombar.state = "hint"
154− }
155− previousStatus = status
156− }
157−
158− onDistanceChanged: {
159− if (status === DirectionalDragArea.Recognized) {
160− if (distanceFromThreshold > commitDistance)
161− bottombar.state = "shown"
162− else if (distanceFromThreshold > revealDistance)
163− bottombar.state = "reveal"
164− }
165− }
166− }
167−
168− Item {
169− id: dismissArea
170− anchors {
171− top: parent.top
172− left: parent.left
173− right: parent.right
174− }
175− height: parent.height - bottomBarVisibilityCommunicatorShell.position
176−
177− MouseArea {
178− anchors.fill: parent
179− enabled: bottombar.state == "shown"
180− onPressed: {
181− bottomBarVisibilityCommunicatorShell.forceHidden = true
182− bottombar.state = "hidden"
183− }
184− }
185−
186− InputFilterArea {
187− anchors.fill: parent
188− blockInput: (hudButton.opacity == 1)
189− }
190− }
191−
192− MouseArea {
193− anchors {
194− top: dismissArea.bottom
195− left: parent.left
196− right: parent.right
197− bottom: parent.bottom
198− }
199− enabled: bottombar.state == "shown" && bottomBarVisibilityCommunicatorShell.position > 0
200− onPressed: {
201− bottombar.state = "hidden"
202− }
203− }
204−
205− states: [
206− State {
207− name: "hidden"
208− PropertyChanges { target: hudButton; opacity: 0 }
209− PropertyChanges { target: hudButton; bottomMargin: units.gu(-2) }
210− },
211− State {
212− name: "hint"
213− extend: "hidden"
214− PropertyChanges { target: hudButton; opacity: 0.5 }
215− },
216− State {
217− name: "reveal"
218− extend: "hint"
219− PropertyChanges { target: hudButton; bottomMargin: units.gu(-2) + units.gu(2) * dragArea.commitProgress }
220− },
221− State {
222− name: "shown"
223− PropertyChanges { target: hudButton; opacity: 1 }
224− PropertyChanges { target: hudButton; bottomMargin: units.gu(0) }
225− }
226− ]
227−}
qml/Bottombar/HudButton.qmldeleted−64
@@ -1,64 +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: item
22−
23− property bool mouseOver
24−
25− property int bottomMargin: units.gu(2)
26−
27− signal clicked()
28−
29− readonly property real scaleOnMouseOver: 1.2
30−
31− width: hudButton.width * scaleOnMouseOver
32− height: hudButton.height * scaleOnMouseOver
33−
34− Item {
35− id: hudButton
36−
37− anchors.centerIn: parent
38− height: units.gu(12)
39− width: height
40− opacity: item.mouseOver || abstractButton.pressed ? 1 : 0.7
41− scale: item.mouseOver || abstractButton.pressed ? scaleOnMouseOver : 1
42− Behavior on opacity {NumberAnimation{duration: 200; easing.type: Easing.OutQuart}}
43− Behavior on scale {NumberAnimation{duration: 200; easing.type: Easing.OutQuart}}
44−
45− AbstractButton {
46− id: abstractButton
47− anchors.fill: parent
48− style: Image {
49− anchors.fill: parent
50− source: "graphics/hud_invoke_button_active.png"
51− }
52−
53− onClicked: item.clicked()
54− }
55−
56− Image {
57− width: units.gu(4)
58− height: width
59− source: "graphics/hud.png"
60− anchors.centerIn: parent
61− fillMode: Image.PreserveAspectFit
62− }
63− }
64−}
qml/Bottombar/graphics/hud@20.pngdeleted

Binary file not shown.

qml/Bottombar/graphics/hud_invoke_button_active@20.pngdeleted

Binary file not shown.

qml/CMakeLists.txt−1
@@ -5,7 +5,6 @@ install(FILES ${QML_JS_FILES}
5 )
5 )
6
6
7set(QML_DIRS
7set(QML_DIRS
8− Bottombar
9 Components
8 Components
10 Dash
9 Dash
11 graphics
10 graphics
qml/Components/LazyImage.qml+1
@@ -36,6 +36,7 @@ Item {
36 property alias cache: image.cache
36 property alias cache: image.cache
37 property alias horizontalAlignment: image.horizontalAlignment
37 property alias horizontalAlignment: image.horizontalAlignment
38 property alias verticalAlignment: image.verticalAlignment
38 property alias verticalAlignment: image.verticalAlignment
39+ property alias sourceImage: image
39
40
40 state: "default"
41 state: "default"
41
42
qml/Components/ZoomableImage.qmlnew file+153
@@ -0,0 +1,153 @@
1+/*
2+ * Copyright (C) 2014 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+/*! \brief Zoomable for image.
22+
23+ This widget shows image contained in source,
24+ can be zoomable accordingly with zoomable.
25+ */
26+
27+Item {
28+ id: root
29+ property alias source: lazyImage.source
30+ property var zoomable: false
31+ property alias imageState: lazyImage.state
32+ property alias scaleTo: lazyImage.scaleTo
33+ property alias asynchronous: lazyImage.asynchronous
34+
35+ Flickable {
36+ id: flickable
37+ objectName: "flickable"
38+ clip: true
39+ contentHeight: imageContainer.height
40+ contentWidth: imageContainer.width
41+
42+ onHeightChanged: image.resetScale()
43+ onWidthChanged: image.resetScale()
44+ anchors.fill: parent
45+
46+ Item {
47+ id: imageContainer
48+ objectName: "imageContainer"
49+ width: Math.max(image.width * image.scale, flickable.width)
50+ height: Math.max(image.height * image.scale, flickable.height)
51+
52+ Item {
53+ id: image
54+ objectName: "image"
55+ property alias imageState: lazyImage.state
56+ property var prevScale
57+ anchors.centerIn: parent
58+
59+ signal imageReloaded
60+
61+ LazyImage {
62+ id: lazyImage
63+ objectName: "lazyImage"
64+ smooth: !flickable.movingVertically
65+ anchors.fill: parent
66+ fillMode: Image.PreserveAspectFit
67+ scaleTo: "fit"
68+
69+ onStateChanged: {
70+ if (state == "ready") {
71+ image.imageReloaded();
72+ }
73+ }
74+ }
75+
76+ onImageReloaded: {
77+ image.height = lazyImage.sourceImage.implicitHeight
78+ image.width = lazyImage.sourceImage.implicitWidth
79+ image.resetScale();
80+ }
81+
82+ function resetScale() {
83+ image.scale = Math.min(flickable.width / image.width, flickable.height / image.height);
84+ pinchArea.minScale = image.scale;
85+ prevScale = Math.min(image.scale, 1);
86+ }
87+
88+ onScaleChanged: {
89+ var currentWidth = width * scale
90+ var currentHeight = height * scale
91+ var scaleRatio = scale / prevScale
92+ if (currentWidth > flickable.width) {
93+ var xpos = flickable.width / 2 + flickable.contentX;
94+ var xoff = xpos * scaleRatio;
95+ flickable.contentX = xoff - flickable.width / 2;
96+ }
97+ if (currentHeight > flickable.height) {
98+ var ypos = flickable.height / 2 + flickable.contentY;
99+ var yoff = ypos * scaleRatio;
100+ flickable.contentY = yoff - flickable.height / 2;
101+ }
102+ prevScale = scale;
103+ }
104+ }
105+ }
106+
107+ PinchArea {
108+ id: pinchArea
109+ objectName: "pinchArea"
110+ property real minScale: 1.0
111+ anchors.fill: parent
112+ enabled: zoomable ? zoomable : false
113+
114+ pinch.target: image
115+ pinch.minimumScale: minScale
116+ pinch.maximumScale: 10
117+
118+ onPinchFinished: flickable.returnToBounds()
119+ }
120+
121+ MouseArea {
122+ id: mouseArea
123+ objectName: "mouseArea"
124+
125+ anchors.fill: parent
126+ enabled: zoomable ? zoomable : false
127+
128+ onWheel: {
129+ var startScale = image.scale;
130+ if (wheel.angleDelta.y > 0) {
131+ image.scale = startScale + 0.1;
132+ } else if (wheel.angleDelta.y < 0) {
133+ if (image.scale > 0.1 && image.scale > pinchArea.minScale) {
134+ image.scale = startScale - 0.1;
135+ }
136+ }
137+ wheel.accepted = true;
138+ }
139+
140+ onPressed: {
141+ mouse.accepted = false;
142+ }
143+
144+ onReleased: {
145+ mouse.accepted = false;
146+ }
147+
148+ onClicked: {
149+ mouse.accepted = false;
150+ }
151+ }
152+ }
153+}
qml/Dash/Card.qmldeleted−236
@@ -1,236 +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−// For image://albumart and image://thumbnailer image providers
20−import Ubuntu.Thumbnailer 0.1
21−
22−AbstractButton {
23− id: root
24− property var template
25− property var components
26− property var cardData
27−
28− property real fontScale: 1.0
29− property int headerAlignment: Text.AlignLeft
30− readonly property int headerHeight: headerLoader.item ? headerLoader.item.height : 0
31− property int fixedHeaderHeight: -1
32− readonly property string title: cardData && cardData["title"] || ""
33−
34− property bool showHeader: true
35−
36− implicitWidth: childrenRect.width
37− implicitHeight: summary.y + summary.height + (summary.text && backgroundLoader.active ? units.gu(1) : 0)
38−
39− Loader {
40− id: backgroundLoader
41− objectName: "backgroundLoader"
42−
43− readonly property bool artAndSummary: components["art"]["field"] && components["summary"] || false
44− active: template["card-layout"] !== "horizontal" && (template["card-background"] || components["background"] || artAndSummary)
45− anchors.fill: parent
46−
47− sourceComponent: UbuntuShape {
48− objectName: "background"
49− radius: "medium"
50− color: getColor(0) || "white"
51− gradientColor: getColor(1) || color
52− anchors.fill: parent
53− image: backgroundImage.source ? backgroundImage : null
54−
55− property real luminance: 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b
56−
57− property Image backgroundImage: Image {
58− objectName: "backgroundImage"
59− source: {
60− if (cardData && typeof cardData["background"] === "string") return cardData["background"]
61− else if (template && typeof template["card-background"] === "string") return template["card-background"]
62− else return ""
63− }
64− }
65−
66− function getColor(index) {
67− if (cardData && typeof cardData["background"] === "object"
68− && (cardData["background"]["type"] === "color" || cardData["background"]["type"] === "gradient")) {
69− return cardData["background"]["elements"][index];
70− } else if (template && typeof template["card-background"] === "object"
71− && (template["card-background"]["type"] === "color" || template["card-background"]["type"] === "gradient")) {
72− return template["card-background"]["elements"][index];
73− } else return undefined;
74− }
75− }
76− }
77−
78− UbuntuShape {
79− id: artShape
80− radius: "medium"
81− objectName: "artShape"
82− anchors.horizontalCenter: template && template["card-layout"] === "horizontal" ? undefined : parent.horizontalCenter
83− anchors.left: template && template["card-layout"] === "horizontal" ? parent.left : undefined
84− visible: cardData && cardData["art"] || false
85−
86− readonly property real aspect: components !== undefined ? components["art"]["aspect-ratio"] : 1
87− readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect
88−
89− Component.onCompleted: updateWidthHeightBindings();
90− onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings();
91−
92− function updateWidthHeightBindings() {
93− if (aspectSmallerThanImageAspect) {
94− width = Qt.binding(function() { return !visible ? 0 : image.width });
95− height = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.height : width / image.aspect });
96− } else {
97− width = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.width : height * image.aspect });
98− height = Qt.binding(function() { return !visible ? 0 : image.height });
99− }
100− }
101−
102− image: Image {
103− objectName: "artImage"
104− source: cardData && cardData["art"] || ""
105− cache: true
106− // FIXME uncomment when having investigated / fixed the crash
107− //sourceSize.width: width > height ? width : 0
108− //sourceSize.height: height > width ? height : 0
109− fillMode: components && components["art"]["fill-mode"] === "fit" ? Image.PreserveAspectFit: Image.PreserveAspectCrop
110−
111− readonly property real aspect: implicitWidth / implicitHeight
112− readonly property bool isHorizontal: template && template["card-layout"] === "horizontal"
113−
114− Component.onCompleted: updateWidthHeightBindings();
115− onIsHorizontalChanged: updateWidthHeightBindings();
116−
117− function updateWidthHeightBindings() {
118− if (isHorizontal) {
119− width = Qt.binding(function() { return height * artShape.aspect });
120− height = Qt.binding(function() { return root.headerHeight });
121− } else {
122− width = Qt.binding(function() { return root.width });
123− height = Qt.binding(function() { return width / artShape.aspect });
124− }
125− }
126− }
127− }
128−
129− Loader {
130− id: overlayLoader
131− anchors {
132− left: artShape.left
133− right: artShape.right
134− bottom: artShape.bottom
135− }
136− active: template && template["overlay"] && artShape.visible && artShape.image.status === Image.Ready || false
137−
138− sourceComponent: ShaderEffect {
139− id: overlay
140−
141− height: headerLoader.item ? headerLoader.item.height : 0
142− opacity: headerLoader.item ? headerLoader.item.opacity * 0.6 : 0
143−
144− property var source: ShaderEffectSource {
145− id: shaderSource
146− sourceItem: artShape
147− onVisibleChanged: if (visible) scheduleUpdate()
148− live: false
149− sourceRect: Qt.rect(0, artShape.height - overlay.height, artShape.width, overlay.height)
150− }
151−
152− vertexShader: "
153− uniform highp mat4 qt_Matrix;
154− attribute highp vec4 qt_Vertex;
155− attribute highp vec2 qt_MultiTexCoord0;
156− varying highp vec2 coord;
157− void main() {
158− coord = qt_MultiTexCoord0;
159− gl_Position = qt_Matrix * qt_Vertex;
160− }"
161−
162− fragmentShader: "
163− varying highp vec2 coord;
164− uniform sampler2D source;
165− uniform lowp float qt_Opacity;
166− void main() {
167− lowp vec4 tex = texture2D(source, coord);
168− gl_FragColor = vec4(0, 0, 0, tex.a) * qt_Opacity;
169− }"
170− }
171− }
172−
173− Loader {
174− id: headerLoader
175− objectName: "cardHeaderLoader"
176−
177− anchors {
178− top: {
179− if (template) {
180− if (template["overlay"]) return overlayLoader.top;
181− if (template["card-layout"] === "horizontal") return artShape.top;
182− }
183− return artShape.bottom;
184− }
185− left: {
186− if (template) {
187− if (!template["overlay"] && template["card-layout"] === "horizontal") return artShape.right;
188− }
189− return parent.left;
190− }
191− right: parent.right
192− }
193− active: cardData && cardData["title"] || cardData && cardData["mascot"] || false
194−
195− sourceComponent: CardHeader {
196− id: header
197− objectName: "cardHeader"
198−
199− mascot: cardData && cardData["mascot"] || ""
200− title: root.title
201− subtitle: cardData && cardData["subtitle"] || ""
202−
203− titleWeight: components && components["subtitle"] ? Font.DemiBold : Font.Normal
204−
205− opacity: showHeader ? 1 : 0
206− inOverlay: root.template && root.template["overlay"] === true
207− fontColor: inOverlay ? "white" : summary.color
208− useMascotShape: !backgroundLoader.active && !inOverlay
209− headerAlignment: root.headerAlignment
210− height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight
211− fontScale: root.fontScale
212−
213− Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.SnapDuration } }
214− }
215− }
216−
217− Label {
218− id: summary
219− objectName: "summaryLabel"
220− anchors {
221− top: headerLoader.active ? headerLoader.bottom : artShape.bottom
222− left: parent.left
223− right: parent.right
224− margins: backgroundLoader.active ? units.gu(1) : 0
225− topMargin: 0
226− }
227− wrapMode: Text.Wrap
228− maximumLineCount: 5
229− elide: Text.ElideRight
230− text: cardData && cardData["summary"] || ""
231− height: text ? implicitHeight : 0
232− fontSize: "small"
233− // TODO karni: Change "grey" to Ubuntu.Components.Palette color once updated.
234− color: backgroundLoader.active && backgroundLoader.item.luminance < 0.7 ? "white" : "grey"
235− }
236−}
qml/Dash/CardCarousel.qml+13−10
@@ -49,21 +49,24 @@ DashRenderer {
49 property real fontScale: 1 / selectedItemScaleFactor
49 property real fontScale: 1 / selectedItemScaleFactor
50 property real headerHeight: cardTool.headerHeight / selectedItemScaleFactor
50 property real headerHeight: cardTool.headerHeight / selectedItemScaleFactor
51
51
52− itemComponent: Card {
52+ itemComponent: Loader {
53− id: card
53+ id: loader
54− objectName: "carouselDelegate" + index
55− fixedHeaderHeight: carousel.headerHeight
56− cardData: model
57− template: cardTool.template
58− components: cardTool.components
59
54
60 property bool explicitlyScaled
55 property bool explicitlyScaled
61 property var model
56 property var model
62−
63 enabled: false
57 enabled: false
64− showHeader: explicitlyScaled
65
58
66− fontScale: carousel.fontScale
59+ sourceComponent: cardTool.cardComponent
60+ onLoaded: {
61+ item.objectName = "carouselDelegate" + index;
62+ item.fixedHeaderHeight = Qt.binding(function() { return carousel.headerHeight; });
63+ item.height = Qt.binding(function() { return cardTool.cardHeight; });
64+ item.cardData = Qt.binding(function() { return model; });
65+ item.template = Qt.binding(function() { return cardTool.template; });
66+ item.components = Qt.binding(function() { return cardTool.components; });
67+ item.fontScale = Qt.binding(function() { return carousel.fontScale; });
68+ item.showHeader = Qt.binding(function() { return loader.explicitlyScaled; });
69+ }
67 }
70 }
68 }
71 }
69}
72}
qml/Dash/CardFilterGrid.qml+19−16
@@ -45,25 +45,28 @@ DashRenderer {
45 collapsedRowCount: Math.min(2, cardTool && cardTool.template && cardTool.template["collapsed-rows"] || 2)
45 collapsedRowCount: Math.min(2, cardTool && cardTool.template && cardTool.template["collapsed-rows"] || 2)
46 delegateCreationBegin: genericFilterGrid.delegateCreationBegin
46 delegateCreationBegin: genericFilterGrid.delegateCreationBegin
47 delegateCreationEnd: genericFilterGrid.delegateCreationEnd
47 delegateCreationEnd: genericFilterGrid.delegateCreationEnd
48− delegate: Loader {
48+ delegate: Item {
49− asynchronous: true
50 width: filterGrid.cellWidth
49 width: filterGrid.cellWidth
51 height: filterGrid.cellHeight
50 height: filterGrid.cellHeight
52− Card {
51+ Loader {
53− id: card
52+ id: loader
54− width: cardTool.cardWidth
53+ sourceComponent: cardTool.cardComponent
55− height: cardTool.cardHeight
56− fixedHeaderHeight: cardTool.headerHeight
57 anchors.horizontalCenter: parent.horizontalCenter
54 anchors.horizontalCenter: parent.horizontalCenter
55+ onLoaded: {
58− objectName: "delegate" + index
56+ item.objectName = "delegate" + index;
57+ item.width = Qt.binding(function() { return cardTool.cardWidth; });
58+ item.height = Qt.binding(function() { return cardTool.cardHeight; });
59+ item.fixedArtShapeSize = Qt.binding(function() { return cardTool.artShapeSize; });
59− cardData: model
60+ item.cardData = Qt.binding(function() { return model; });
60− template: cardTool.template
61+ item.template = Qt.binding(function() { return cardTool.template; });
61− components: cardTool.components
62+ item.components = Qt.binding(function() { return cardTool.components; });
62−
63− headerAlignment: cardTool.headerAlignment
63+ item.headerAlignment = Qt.binding(function() { return cardTool.headerAlignment; });
64−
64+ }
65+ Connections {
66+ target: loader.item
65− onClicked: genericFilterGrid.clicked(index, card.y)
67+ onClicked: genericFilterGrid.clicked(index, item.y)
66− onPressAndHold: genericFilterGrid.pressAndHold(index, card.y)
68+ onPressAndHold: genericFilterGrid.pressAndHold(index, item.y)
69+ }
67 }
70 }
68 }
71 }
69 }
72 }
qml/Dash/CardHeader.qmldeleted−126
@@ -1,126 +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: root
22− property url mascot: ""
23− property alias title: titleLabel.text
24− property var subtitle
25−
26− property alias titleWeight: titleLabel.font.weight
27− property alias titleSize: titleLabel.fontSize
28−
29− // FIXME: Saviq, used to scale fonts down in Carousel
30− property real fontScale: 1.0
31−
32− property alias headerAlignment: titleLabel.horizontalAlignment
33−
34− property bool inOverlay: false
35− property bool useMascotShape: true
36− property color fontColor: Theme.palette.selected.backgroundText
37−
38− visible: mascot != "" || title
39− implicitHeight: row.height > 0 ? row.height + row.margins * 2 : 0
40−
41− Row {
42− id: row
43− objectName: "outerRow"
44−
45− property real margins: units.gu(1)
46−
47− spacing: mascotShapeLoader.active || mascotImageLoader.active || inOverlay ? margins : 0
48− anchors {
49− top: parent.top; left: parent.left; right: parent.right
50− margins: margins
51− leftMargin: spacing
52− rightMargin: spacing
53− }
54−
55− Loader {
56− id: mascotShapeLoader
57− objectName: "mascotShapeLoader"
58−
59− active: useMascotShape && mascotImageLoader.item && mascotImageLoader.item.status === Image.Ready
60− visible: active
61− anchors.verticalCenter: parent.verticalCenter
62− // TODO karni: Icon aspect-ratio is 8:7.5. Revisit these values to avoid fraction of pixels.
63− width: units.gu(6)
64− height: units.gu(5.625)
65− readonly property int maxSize: Math.max(width, height) * 4
66−
67− sourceComponent: UbuntuShape {
68− image: mascotImageLoader.item
69− }
70− }
71−
72− Loader {
73− id: mascotImageLoader
74− active: root.mascot != ""
75− visible: active && !useMascotShape && item.status === Image.Ready
76− anchors.verticalCenter: parent.verticalCenter
77− sourceComponent: Image {
78− objectName: "mascotImage"
79−
80− source: root.mascot
81− width: source ? mascotShapeLoader.width : 0
82− height: mascotShapeLoader.height
83−
84− sourceSize { width: mascotShapeLoader.maxSize; height: mascotShapeLoader.maxSize }
85− fillMode: Image.PreserveAspectCrop
86− horizontalAlignment: Image.AlignHCenter
87− verticalAlignment: Image.AlignVCenter
88− }
89− }
90−
91− Column {
92− objectName: "column"
93− width: parent.width - x
94− spacing: units.dp(2)
95− anchors.verticalCenter: parent.verticalCenter
96−
97− Label {
98− id: titleLabel
99− objectName: "titleLabel"
100− anchors { left: parent.left; right: parent.right }
101− elide: Text.ElideRight
102− font.weight: Font.Normal
103− fontSize: "small"
104− wrapMode: Text.Wrap
105− maximumLineCount: 2
106− font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale)
107− color: fontColor
108− }
109−
110− Loader {
111− active: titleLabel.text && root.subtitle
112− anchors { left: parent.left; right: parent.right }
113− sourceComponent: Label {
114− id: subtitleLabel
115− objectName: "subtitleLabel"
116− elide: Text.ElideRight
117− fontSize: "small"
118− font.weight: Font.Light
119− font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale)
120− color: fontColor
121− text: root.subtitle
122− }
123− }
124− }
125− }
126−}
qml/Dash/CardTool.qml+30−22
@@ -15,6 +15,7 @@
15 */
15 */
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18+import Dash 0.1
18
19
19/*!
20/*!
20 \brief Tool for introspecting Card properties.
21 \brief Tool for introspecting Card properties.
@@ -65,6 +66,8 @@ Item {
65 return layout;
66 return layout;
66 }
67 }
67
68
69+ property var cardComponent: CardCreatorCache.getCardComponent(cardTool.template, cardTool.components);
70+
68 // FIXME: Saviq
71 // FIXME: Saviq
69 // Only way for the card below to actually be laid out completely.
72 // Only way for the card below to actually be laid out completely.
70 // If invisible or in "data" array, some components are not taken into account.
73 // If invisible or in "data" array, some components are not taken into account.
@@ -108,7 +111,7 @@ Item {
108 if (template["card-size"] >= 12 && template["card-size"] <= 38) return units.gu(template["card-size"]);
111 if (template["card-size"] >= 12 && template["card-size"] <= 38) return units.gu(template["card-size"]);
109 return units.gu(18.5);
112 return units.gu(18.5);
110 case "grid":
113 case "grid":
111− return card.implicitHeight
114+ return cardLoader.item ? cardLoader.item.implicitHeight : 0
112 case "carousel":
115 case "carousel":
113 return cardWidth / (components ? components["art"]["aspect-ratio"] : 1)
116 return cardWidth / (components ? components["art"]["aspect-ratio"] : 1)
114 case undefined:
117 case undefined:
@@ -122,7 +125,8 @@ Item {
122 /*!
125 /*!
123 type:real \brief Height of the card's header.
126 type:real \brief Height of the card's header.
124 */
127 */
125− readonly property alias headerHeight: card.headerHeight
128+ readonly property int headerHeight: cardLoader.item ? cardLoader.item.headerHeight : 0
129+ readonly property size artShapeSize: cardLoader.item ? cardLoader.item.artShapeSize : 0
126
130
127 /*!
131 /*!
128 \brief Desired alignment of header components.
132 \brief Desired alignment of header components.
@@ -161,15 +165,8 @@ Item {
161 }
165 }
162 }
166 }
163
167
164− Card {
168+ Loader {
165− id: card
169+ id: cardLoader
166− objectName: "cardToolCard"
167− template: cardTool.template
168− components: cardTool.components
169−
170− width: cardTool.cardWidth || implicitWidth
171− height: cardTool.cardHeight || implicitHeight
172−
173 property var fields: ["art", "mascot", "title", "subtitle", "summary"]
170 property var fields: ["art", "mascot", "title", "subtitle", "summary"]
174 property var maxData: {
171 property var maxData: {
175 "art": Qt.resolvedUrl("graphics/checkers.png"),
172 "art": Qt.resolvedUrl("graphics/checkers.png"),
@@ -178,19 +175,30 @@ Item {
178 "subtitle": "—",
175 "subtitle": "—",
179 "summary": "—\n—\n—\n—\n—"
176 "summary": "—\n—\n—\n—\n—"
180 }
177 }
181−
178+ sourceComponent: cardTool.cardComponent
179+ onLoaded: {
180+ item.objectName = "cardToolCard";
181+ item.asynchronous = false;
182+ item.template = Qt.binding(function() { return cardTool.template; });
183+ item.components = Qt.binding(function() { return cardTool.components; });
184+ item.width = Qt.binding(function() { return cardTool.cardWidth || item.implicitWidth; });
185+ item.height = Qt.binding(function() { return cardTool.cardHeight || item.implicitHeight; });
186+ }
187+ Connections {
188+ target: cardLoader.item
182− onComponentsChanged: {
189+ onComponentsChanged: {
183− var data = {};
190+ var data = {};
184− for (var k in fields) {
191+ for (var k in cardLoader.fields) {
185− var component = components[fields[k]];
192+ var component = cardLoader.item.components[cardLoader.fields[k]];
186− var key = fields[k];
193+ var key = cardLoader.fields[k];
187− if ((typeof component === "string" && component.length > 0) ||
194+ if ((typeof component === "string" && component.length > 0) ||
188− (typeof component === "object" && component !== null
195+ (typeof component === "object" && component !== null
189− && typeof component["field"] === "string" && component["field"].length > 0)) {
196+ && typeof component["field"] === "string" && component["field"].length > 0)) {
190− data[key] = maxData[key];
197+ data[key] = cardLoader.maxData[key];
198+ }
191 }
199 }
200+ cardLoader.item.cardData = data;
192 }
201 }
193− cardData = data;
194 }
202 }
195 }
203 }
196}
204}
qml/Dash/DashContent.qml+18−10
@@ -17,6 +17,7 @@
17import QtQuick 2.0
17import QtQuick 2.0
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19import Unity 0.2
19import Unity 0.2
20+import Utils 0.1
20import "../Components"
21import "../Components"
21
22
22Item {
23Item {
@@ -183,23 +184,30 @@ Item {
183 width: parent.width
184 width: parent.width
184 style: DashContentTabBarStyle {}
185 style: DashContentTabBarStyle {}
185
186
186− model: dashContentList.model
187+ SortFilterProxyModel {
188+ id: tabBarModel
187
189
190+ model: dashContentList.model
191+
192+ property int selectedIndex: -1
188− onSelectedIndexChanged: {
193+ onSelectedIndexChanged: {
189− if (dashContentList.currentIndex == -1 && tabBar.selectedIndex != -1) {
194+ if (dashContentList.currentIndex == -1 && tabBar.selectedIndex != -1) {
190− // TODO This together with the Timer below
195+ // TODO This together with the Timer below
191− // are a workaround for the first tab sometimes not showing the text.
196+ // are a workaround for the first tab sometimes not showing the text.
192− // But Tabs are going away in the future so not sure if makes
197+ // But Tabs are going away in the future so not sure if makes
193− // sense invetigating what's the problem at this stage
198+ // sense invetigating what's the problem at this stage
194− selectionModeTimer.restart();
199+ selectionModeTimer.restart();
200+ }
201+ dashContentList.currentIndex = selectedIndex;
195 }
202 }
196− dashContentList.currentIndex = selectedIndex;
197 }
203 }
198
204
205+ model: tabBarModel.count > 0 ? tabBarModel : null
206+
199 Connections {
207 Connections {
200 target: dashContentList
208 target: dashContentList
201 onCurrentIndexChanged: {
209 onCurrentIndexChanged: {
202− tabBar.selectedIndex = dashContentList.currentIndex
210+ tabBarModel.selectedIndex = dashContentList.currentIndex
203 }
211 }
204 }
212 }
205
213
qml/Dash/Previews/PreviewHeader.qml+86−9
@@ -15,9 +15,10 @@
15 */
15 */
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18+import Ubuntu.Components 0.1
18import "../"
19import "../"
19
20
20−/*! This preview widget shows a header that is the same as the card header
21+/*! This preview widget shows a header
21 * The title comes in widgetData["title"]
22 * The title comes in widgetData["title"]
22 * The mascot comes in widgetData["mascot"]
23 * The mascot comes in widgetData["mascot"]
23 * The subtitle comes in widgetData["subtitle"]
24 * The subtitle comes in widgetData["subtitle"]
@@ -28,15 +29,91 @@ PreviewWidget {
28
29
29 height: childrenRect.height
30 height: childrenRect.height
30
31
31− CardHeader {
32+ Item {
33+ id: headerRoot
32− objectName: "cardHeader"
34+ objectName: "innerPreviewHeader"
33− mascot: root.widgetData["mascot"] || ""
35+ readonly property url mascot: root.widgetData["mascot"] || ""
34− title: root.widgetData["title"] || ""
36+ readonly property string title: root.widgetData["title"] || ""
35− subtitle: root.widgetData["subtitle"] || ""
37+ readonly property string subtitle: root.widgetData["subtitle"] || ""
38+ readonly property color fontColor: "grey"
39+
40+ implicitHeight: row.height + row.margins * 2
36 width: parent.width
41 width: parent.width
37
42
38− titleSize: "large"
43+ Row {
39− // TODO Change "grey" to Ubuntu.Components.Palette color once updated.
44+ id: row
45+ objectName: "outerRow"
46+
47+ property real margins: units.gu(1)
48+
49+ spacing: mascotShapeLoader.active ? margins : 0
50+ anchors {
51+ top: parent.top; left: parent.left; right: parent.right
52+ margins: margins
53+ leftMargin: spacing
54+ rightMargin: spacing
55+ }
56+
57+ Loader {
58+ id: mascotShapeLoader
59+
60+ anchors.verticalCenter: parent.verticalCenter
61+ // TODO karni: Icon aspect-ratio is 8:7.5. Revisit these values to avoid fraction of pixels.
62+ width: units.gu(6)
63+ height: units.gu(5.625)
64+ readonly property int maxSize: Math.max(width, height) * 4
65+ asynchronous: true
66+
67+ sourceComponent: UbuntuShape {
68+ objectName: "mascotShape"
69+ visible: image.status === Image.Ready
70+ image: Image {
71+ source: headerRoot.mascot
72+ width: source ? mascotShapeLoader.width : 0
73+ height: mascotShapeLoader.height
74+
75+ sourceSize { width: mascotShapeLoader.maxSize; height: mascotShapeLoader.maxSize }
76+ fillMode: Image.PreserveAspectCrop
77+ horizontalAlignment: Image.AlignHCenter
78+ verticalAlignment: Image.AlignVCenter
79+ }
80+ }
81+ }
82+
83+ Column {
84+ objectName: "column"
85+ width: parent.width - x
86+ spacing: units.dp(2)
87+ anchors.verticalCenter: parent.verticalCenter
88+
89+ Label {
90+ id: titleLabel
91+ objectName: "titleLabel"
92+ anchors { left: parent.left; right: parent.right }
93+ elide: Text.ElideRight
94+ font.weight: Font.Normal
95+ fontSize: "large"
96+ wrapMode: Text.Wrap
97+ maximumLineCount: 2
40− fontColor: "grey"
98+ color: headerRoot.fontColor
99+ text: headerRoot.title
100+ }
101+
102+ Loader {
103+ active: titleLabel.text && headerRoot.subtitle
104+ anchors { left: parent.left; right: parent.right }
105+ sourceComponent: Label {
106+ id: subtitleLabel
107+ objectName: "subtitleLabel"
108+ elide: Text.ElideRight
109+ fontSize: "small"
110+ font.weight: Font.Light
111+ color: headerRoot.fontColor
112+ text: headerRoot.subtitle
113+ }
114+ }
115+ }
116+ }
41 }
117 }
118+
42}
119}
qml/Dash/Previews/PreviewProgress.qml+3−2
@@ -34,11 +34,12 @@ PreviewWidget {
34 ProgressBar {
34 ProgressBar {
35 id: progressBar
35 id: progressBar
36 objectName: "progressBar"
36 objectName: "progressBar"
37+ anchors.right: parent.right
37 value: 0
38 value: 0
38 maximumValue: 100
39 maximumValue: 100
39− implicitHeight: units.gu(5)
40+ implicitHeight: units.gu(4)
40 height: parent.height
41 height: parent.height
41− width: parent.width
42+ width: (root.width - units.gu(1)) / 2
42
43
43 property var source: widgetData["source"]
44 property var source: widgetData["source"]
44 // TODO Eventually we will need to support more sources other
45 // TODO Eventually we will need to support more sources other
qml/Dash/Previews/PreviewTextSummary.qml+4−2
@@ -37,6 +37,7 @@ PreviewWidget {
37 left: parent.left
37 left: parent.left
38 right: parent.right
38 right: parent.right
39 }
39 }
40+ height: visible ? implicitHeight : 0
40 fontSize: "large"
41 fontSize: "large"
41 // TODO karni: Yet another fix requiring Palette update.
42 // TODO karni: Yet another fix requiring Palette update.
42 color: "grey" //Theme.palette.selected.backgroundText
43 color: "grey" //Theme.palette.selected.backgroundText
@@ -68,7 +69,7 @@ PreviewWidget {
68 wrapMode: Text.Wrap
69 wrapMode: Text.Wrap
69
70
70 Behavior on height {
71 Behavior on height {
71− UbuntuNumberAnimation {}
72+ UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration }
72 }
73 }
73 }
74 }
74
75
@@ -79,8 +80,9 @@ PreviewWidget {
79 left: parent.left
80 left: parent.left
80 right: parent.right
81 right: parent.right
81 top: textLabel.bottom
82 top: textLabel.bottom
82− topMargin: units.gu(1)
83+ topMargin: visible ? units.gu(1) : 0
83 }
84 }
85+ height: visible ? implicitHeight : 0
84 visible: textLabel.lineCount > textLabel.maximumCollapsedLineCount
86 visible: textLabel.lineCount > textLabel.maximumCollapsedLineCount
85 }
87 }
86}
88}
qml/Dash/Previews/PreviewZoomableImage.qml+4−7
@@ -28,14 +28,11 @@ PreviewWidget {
28 id: root
28 id: root
29 implicitHeight: units.gu(22)
29 implicitHeight: units.gu(22)
30
30
31− LazyImage {
31+ ZoomableImage {
32+ id: image
32 objectName: "image"
33 objectName: "image"
33− anchors {
34− top: parent.top
35− bottom: parent.bottom
36− }
37− scaleTo: "height"
38 source: widgetData["source"]
34 source: widgetData["source"]
39− initialWidth: units.gu(13)
35+ zoomable: widgetData["zoomable"] ? widgetData["zoomable"] : false
36+ anchors.fill: parent
40 }
37 }
41}
38}
qml/Dash/ScopeListView.qml+1−1
@@ -15,7 +15,7 @@
15 */
15 */
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18−import DashViews 0.1
18+import Dash 0.1
19
19
20ListViewWithPageHeader {
20ListViewWithPageHeader {
21 maximumFlickVelocity: height * 10
21 maximumFlickVelocity: height * 10
qml/Notifications/Notifications.qml+11
@@ -16,6 +16,8 @@
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19+import Unity.Notifications 1.0 as UnityNotifications
20+import Utils 0.1
19import "../Components"
21import "../Components"
20
22
21ListView {
23ListView {
@@ -25,6 +27,15 @@ ListView {
25 interactive: false
27 interactive: false
26
28
27 property real margin
29 property real margin
30+ property bool useModal: snapDecisionProxyModel.count > 0
31+
32+ SortFilterProxyModel {
33+ id: snapDecisionProxyModel
34+
35+ model: notificationList.model
36+ filterRole: UnityNotifications.ModelInterface.RoleType
37+ filterRegExp: RegExp(UnityNotifications.Notification.SnapDecision)
38+ }
28 spacing: delegate.fullscreen ? 0 : units.gu(.5)
39 spacing: delegate.fullscreen ? 0 : units.gu(.5)
29
40
30 currentIndex: (currentIndex < 1 && count > 1) ? 1 : -1
41 currentIndex: (currentIndex < 1 && count > 1) ? 1 : -1
qml/Shell.qml+21−48
@@ -28,9 +28,7 @@ import "Dash"
28import "Greeter"
28import "Greeter"
29import "Launcher"
29import "Launcher"
30import "Panel"
30import "Panel"
31−import "Hud"
32import "Components"
31import "Components"
33−import "Bottombar"
34import "Notifications"
32import "Notifications"
35import Unity.Notifications 1.0 as NotificationBackend
33import Unity.Notifications 1.0 as NotificationBackend
36
34
@@ -308,7 +306,7 @@ FocusScope {
308
306
309 readonly property int backgroundTopMargin: -panel.panelHeight
307 readonly property int backgroundTopMargin: -panel.panelHeight
310
308
311− hides: [launcher, panel.indicators, hud]
309+ hides: [launcher, panel.indicators]
312 shown: false
310 shown: false
313 enabled: true
311 enabled: true
314 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
312 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
@@ -381,7 +379,7 @@ FocusScope {
381 objectName: "greeter"
379 objectName: "greeter"
382
380
383 available: true
381 available: true
384− hides: [launcher, panel.indicators, hud]
382+ hides: [launcher, panel.indicators]
385 shown: true
383 shown: true
386
384
387 defaultBackground: shell.background
385 defaultBackground: shell.background
@@ -424,7 +422,7 @@ FocusScope {
424 InputFilterArea {
422 InputFilterArea {
425 anchors.fill: parent
423 anchors.fill: parent
426 blockInput: ApplicationManager.focusedApplicationId.length === 0 || greeter.shown || lockscreen.shown || launcher.shown
424 blockInput: ApplicationManager.focusedApplicationId.length === 0 || greeter.shown || lockscreen.shown || launcher.shown
427− || panel.indicators.shown || hud.shown
425+ || panel.indicators.shown
428 }
426 }
429
427
430 Connections {
428 Connections {
@@ -488,47 +486,6 @@ FocusScope {
488 }
486 }
489 }
487 }
490
488
491− Hud {
492− id: hud
493−
494− width: parent.width > units.gu(60) ? units.gu(40) : parent.width
495− height: parent.height
496−
497− available: !greeter.shown && !panel.indicators.shown && !lockscreen.shown && edgeDemo.dashEnabled
498− shown: false
499− showAnimation: StandardAnimation { property: "y"; duration: hud.showableAnimationDuration; to: 0; easing.type: Easing.Linear }
500− hideAnimation: StandardAnimation { property: "y"; duration: hud.showableAnimationDuration; to: hudRevealer.closedValue; easing.type: Easing.Linear }
501−
502− Connections {
503− target: ApplicationManager
504− onFocusedApplicationIdChanged: hud.hide()
505− }
506− }
507−
508− Revealer {
509− id: hudRevealer
510−
511− enabled: hud.shown
512− width: hud.width
513− anchors.left: hud.left
514− height: parent.height
515− target: hud.revealerTarget
516− closedValue: height
517− openedValue: 0
518− direction: Qt.RightToLeft
519− orientation: Qt.Vertical
520− handleSize: hud.handleHeight
521− onCloseClicked: target.hide()
522− }
523−
524− Bottombar {
525− id: bottombar
526− theHud: hud
527− anchors.fill: parent
528− enabled: hud.available
529− applicationIsOnForeground: ApplicationManager.focusedApplicationId
530− }
531−
532 InputFilterArea {
489 InputFilterArea {
533 blockInput: launcher.shown
490 blockInput: launcher.shown
534 anchors {
491 anchors {
@@ -576,12 +533,28 @@ FocusScope {
576 onShownChanged: {
533 onShownChanged: {
577 if (shown) {
534 if (shown) {
578 panel.indicators.hide()
535 panel.indicators.hide()
579− hud.hide()
580− bottombar.hide()
581 }
536 }
582 }
537 }
583 }
538 }
584
539
540+ Rectangle {
541+ id: modalNotificationBackground
542+
543+ visible: notifications.useModal && !greeter.shown && (notifications.state == "narrow")
544+ color: "#000000"
545+ anchors.fill: parent
546+ opacity: 0.5
547+
548+ MouseArea {
549+ anchors.fill: parent
550+ }
551+
552+ InputFilterArea {
553+ anchors.fill: parent
554+ blockInput: modalNotificationBackground.visible
555+ }
556+ }
557+
585 Notifications {
558 Notifications {
586 id: notifications
559 id: notifications
587
560
run → run.shrenamed+1−1
@@ -84,6 +84,6 @@ else
84 echo "Unity8 is already running, please stop it first"
84 echo "Unity8 is already running, please stop it first"
85 exit 1
85 exit 1
86 fi
86 fi
87− /sbin/initctl start unity8 BINARY="`readlink -f $QML_PHONE_SHELL_PATH` $QML_PHONE_SHELL_ARGS $@"
87+ /sbin/initctl start unity8 BINARY="`readlink -f $QML_PHONE_SHELL_PATH` $QML_PHONE_SHELL_ARGS $@" QML2_IMPORT_PATH=$QML2_IMPORT_PATH LD_LIBRARY_PATH=$LD_LIBRARY_PATH
88 tailf -n 0 ~/.cache/upstart/unity8.log
88 tailf -n 0 ~/.cache/upstart/unity8.log
89fi
89fi
run_on_device → run_on_device.shrenamed+2−2
@@ -88,7 +88,7 @@ sync_code() {
88}
88}
89
89
90build() {
90build() {
91− exec_with_ssh PATH=/usr/lib/ccache:$PATH "cd $CODE_DIR/ && PATH=/usr/lib/ccache:$PATH ./build"
91+ exec_with_ssh PATH=/usr/lib/ccache:$PATH "cd $CODE_DIR/ && PATH=/usr/lib/ccache:$PATH ./build.sh"
92}
92}
93
93
94run() {
94run() {
@@ -105,7 +105,7 @@ run() {
105
105
106 exec_with_ssh "stop unity8"
106 exec_with_ssh "stop unity8"
107 exec_with_ssh "start maliit-server"
107 exec_with_ssh "start maliit-server"
108− exec_with_ssh "cd $CODE_DIR/ && ./run $ARGS -- $RUN_OPTIONS"
108+ exec_with_ssh "cd $CODE_DIR/ && ./run.sh $ARGS -- $RUN_OPTIONS"
109 exec_with_ssh "stop maliit-server"
109 exec_with_ssh "stop maliit-server"
110 exec_with_ssh "start unity8"
110 exec_with_ssh "start unity8"
111}
111}
src/ApplicationArguments.h+4−8
@@ -28,14 +28,10 @@ class ApplicationArguments : public QObject
28{
28{
29 Q_OBJECT
29 Q_OBJECT
30public:
30public:
31− ApplicationArguments(const QStringList& args) {
31+ // Not exposed to the app as setSize isn't invokable
32− if (args.contains(QLatin1String("-windowgeometry")) && args.size() > args.indexOf(QLatin1String("-windowgeometry")) + 1) {
32+ void setSize(int width, int height) {
33− QStringList geometryArg = args.at(args.indexOf(QLatin1String("-windowgeometry")) + 1).split('x');
34− if (geometryArg.size() == 2) {
35− m_size.rwidth() = geometryArg.at(0).toInt();
33+ m_size.rwidth() = width;
36− m_size.rheight() = geometryArg.at(1).toInt();
34+ m_size.rheight() = height;
37− }
38− }
39 }
35 }
40
36
41 Q_INVOKABLE bool hasGeometry() const { return m_size.isValid(); }
37 Q_INVOKABLE bool hasGeometry() const { return m_size.isValid(); }
src/main.cpp+43−6
@@ -18,6 +18,7 @@
18 */
18 */
19
19
20// Qt
20// Qt
21+#include <QCommandLineParser>
21#include <QtQuick/QQuickView>
22#include <QtQuick/QQuickView>
22#include <QtGui/QGuiApplication>
23#include <QtGui/QGuiApplication>
23#include <QtQml/QQmlEngine>
24#include <QtQml/QQmlEngine>
@@ -43,6 +44,32 @@ int startShell(int argc, const char** argv, void* server)
43
44
44 QGuiApplication::setApplicationName("Unity 8");
45 QGuiApplication::setApplicationName("Unity 8");
45 QGuiApplication *application;
46 QGuiApplication *application;
47+
48+ QCommandLineParser parser;
49+ parser.setApplicationDescription("Description: Unity 8 Shell");
50+ parser.addHelpOption();
51+
52+ QCommandLineOption fullscreenOption("fullscreen",
53+ "Run in fullscreen");
54+ parser.addOption(fullscreenOption);
55+
56+ QCommandLineOption framelessOption("frameless",
57+ "Run without window borders");
58+ parser.addOption(framelessOption);
59+
60+ QCommandLineOption mousetouchOption("mousetouch",
61+ "Allow the mouse to provide touch input");
62+ parser.addOption(mousetouchOption);
63+
64+ QCommandLineOption windowGeometryOption(QStringList() << "windowgeometry",
65+ "Specify the window geometry as [<width>x<height>]", "windowgeometry", "1");
66+ parser.addOption(windowGeometryOption);
67+
68+ QCommandLineOption testabilityOption("testability",
69+ "DISCOURAGED: Please set QT_LOAD_TESTABILITY instead. \n \
70+Load the testability driver");
71+ parser.addOption(testabilityOption);
72+
46 if (isUbuntuMirServer) {
73 if (isUbuntuMirServer) {
47 QLibrary unityMir("unity-mir", 1);
74 QLibrary unityMir("unity-mir", 1);
48 unityMir.load();
75 unityMir.load();
@@ -59,6 +86,11 @@ int startShell(int argc, const char** argv, void* server)
59 application = new QGuiApplication(argc, (char**)argv);
86 application = new QGuiApplication(argc, (char**)argv);
60 }
87 }
61
88
89+ // Treat args with single dashes the same as arguments with two dashes
90+ // Ex: -fullscreen == --fullscreen
91+ parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
92+ parser.process(*application);
93+
62 QString indicatorProfile = qgetenv("UNITY_INDICATOR_PROFILE");
94 QString indicatorProfile = qgetenv("UNITY_INDICATOR_PROFILE");
63 if (indicatorProfile.isEmpty()) {
95 if (indicatorProfile.isEmpty()) {
64 indicatorProfile = "phone";
96 indicatorProfile = "phone";
@@ -66,12 +98,17 @@ int startShell(int argc, const char** argv, void* server)
66
98
67 resolveIconTheme();
99 resolveIconTheme();
68
100
69− QStringList args = application->arguments();
101+ ApplicationArguments qmlArgs;
70− ApplicationArguments qmlArgs(args);
102+ if (parser.isSet(windowGeometryOption) &&
103+ parser.value(windowGeometryOption).split('x').size() == 2)
104+ {
105+ QStringList geom = parser.value(windowGeometryOption).split('x');
106+ qmlArgs.setSize(geom.at(0).toInt(), geom.at(1).toInt());
107+ }
71
108
72 // The testability driver is only loaded by QApplication but not by QGuiApplication.
109 // The testability driver is only loaded by QApplication but not by QGuiApplication.
73 // However, QApplication depends on QWidget which would add some unneeded overhead => Let's load the testability driver on our own.
110 // However, QApplication depends on QWidget which would add some unneeded overhead => Let's load the testability driver on our own.
74− if (args.contains(QLatin1String("-testability")) || getenv("QT_LOAD_TESTABILITY")) {
111+ if (parser.isSet(testabilityOption) || getenv("QT_LOAD_TESTABILITY")) {
75 QLibrary testLib(QLatin1String("qttestability"));
112 QLibrary testLib(QLatin1String("qttestability"));
76 if (testLib.load()) {
113 if (testLib.load()) {
77 typedef void (*TasInitialize)(void);
114 typedef void (*TasInitialize)(void);
@@ -94,14 +131,14 @@ int startShell(int argc, const char** argv, void* server)
94 view->engine()->setBaseUrl(QUrl::fromLocalFile(::qmlDirectory()));
131 view->engine()->setBaseUrl(QUrl::fromLocalFile(::qmlDirectory()));
95 view->rootContext()->setContextProperty("applicationArguments", &qmlArgs);
132 view->rootContext()->setContextProperty("applicationArguments", &qmlArgs);
96 view->rootContext()->setContextProperty("indicatorProfile", indicatorProfile);
133 view->rootContext()->setContextProperty("indicatorProfile", indicatorProfile);
97− if (args.contains(QLatin1String("-frameless"))) {
134+ if (parser.isSet(framelessOption)) {
98 view->setFlags(Qt::FramelessWindowHint);
135 view->setFlags(Qt::FramelessWindowHint);
99 }
136 }
100
137
101 // You will need this if you want to interact with touch-only components using a mouse
138 // You will need this if you want to interact with touch-only components using a mouse
102 // Needed only when manually testing on a desktop.
139 // Needed only when manually testing on a desktop.
103 MouseTouchAdaptor *mouseTouchAdaptor = 0;
140 MouseTouchAdaptor *mouseTouchAdaptor = 0;
104− if (args.contains(QLatin1String("-mousetouch"))) {
141+ if (parser.isSet(mousetouchOption)) {
105 mouseTouchAdaptor = new MouseTouchAdaptor;
142 mouseTouchAdaptor = new MouseTouchAdaptor;
106 application->installNativeEventFilter(mouseTouchAdaptor);
143 application->installNativeEventFilter(mouseTouchAdaptor);
107 }
144 }
@@ -125,7 +162,7 @@ int startShell(int argc, const char** argv, void* server)
125 view->setSource(source);
162 view->setSource(source);
126 view->setColor("transparent");
163 view->setColor("transparent");
127
164
128− if (qgetenv("QT_QPA_PLATFORM") == "ubuntu" || isUbuntuMirServer || args.contains(QLatin1String("-fullscreen"))) {
165+ if (qgetenv("QT_QPA_PLATFORM") == "ubuntu" || isUbuntuMirServer || parser.isSet(fullscreenOption)) {
129 view->showFullScreen();
166 view->showFullScreen();
130 } else {
167 } else {
131 view->show();
168 view->show();
tests/autopilot/unity8/shell/emulators/dash.py+3−4
@@ -161,7 +161,7 @@ class GenericScopeView(emulators.UnityEmulatorBase):
161
161
162 """
162 """
163 category_element = self._get_category_element(category)
163 category_element = self._get_category_element(category)
164− icon = category_element.select_single('Card', title=app_name)
164+ icon = category_element.select_single('AbstractButton', title=app_name)
165 # FIXME some categories need a long press in order to see the preview.
165 # FIXME some categories need a long press in order to see the preview.
166 # Some categories do not show previews, like recent apps.
166 # Some categories do not show previews, like recent apps.
167 # --elopio - 2014-1-14
167 # --elopio - 2014-1-14
@@ -191,7 +191,7 @@ class DashApps(GenericScopeView):
191
191
192 """
192 """
193 category_element = self._get_category_element(category)
193 category_element = self._get_category_element(category)
194− application_cards = category_element.select_many('Card')
194+ application_cards = category_element.select_many('AbstractButton')
195
195
196 # sort by y, x
196 # sort by y, x
197 application_cards = sorted(
197 application_cards = sorted(
@@ -201,8 +201,7 @@ class DashApps(GenericScopeView):
201 result = []
201 result = []
202 for card in application_cards:
202 for card in application_cards:
203 if card.objectName != 'cardToolCard':
203 if card.objectName != 'cardToolCard':
204− card_header = card.select_single('CardHeader')
205− result.append(card_header.title)
204+ result.append(card.title)
206 return result
205 return result
207
206
208
207
tests/autopilot/unity8/shell/tests/test_notifications.py+83
@@ -211,6 +211,89 @@ class InteractiveNotificationBase(NotificationsBase):
211 self.touch.tap_object(notification.select_single(objectName="button4"))
211 self.touch.tap_object(notification.select_single(objectName="button4"))
212 self.assert_notification_action_id_was_called("action_decline_4")
212 self.assert_notification_action_id_was_called("action_decline_4")
213
213
214+ def test_modal_sd_without_greeter (self):
215+ """A snap-decision on a phone should block input to shell beneath it when there's no greeter."""
216+ unity_proxy = self.launch_unity()
217+ unlock_unity(unity_proxy)
218+
219+ summary = "Incoming file"
220+ body = "Frank would like to send you the file: essay.pdf"
221+ icon_path = "sync-idle"
222+ hints = [
223+ ("x-canonical-snap-decisions", "true"),
224+ ("x-canonical-non-shaped-icon", "true"),
225+ ]
226+
227+ actions = [
228+ ('action_accept', 'Accept'),
229+ ('action_decline_1', 'Decline'),
230+ ]
231+
232+ self._create_interactive_notification(
233+ summary,
234+ body,
235+ icon_path,
236+ "NORMAL",
237+ actions,
238+ hints
239+ )
240+
241+ # verify that we cannot reveal the launcher (no longer interact with the shell)
242+ time.sleep(1)
243+ self.main_window.show_dash_swiping()
244+ launcher = self.main_window.get_launcher()
245+ self.assertThat(launcher.shown, Eventually(Equals(False)))
246+
247+ # verify and interact with the triggered snap-decision notification
248+ notify_list = self._get_notifications_list()
249+ get_notification = lambda: notify_list.wait_select_single(
250+ 'Notification', objectName='notification1')
251+ notification = get_notification()
252+ self._assert_notification(notification, summary, body, True, False, 1.0)
253+ self.touch.tap_object(notification.select_single(objectName="button0"))
254+ self.assert_notification_action_id_was_called("action_accept")
255+
256+ def test_modal_sd_with_greeter (self):
257+ """A snap-decision on a phone should not block input to the greeter beneath it."""
258+ unity_proxy = self.launch_unity()
259+
260+ summary = "Incoming file"
261+ body = "Frank would like to send you the file: essay.pdf"
262+ icon_path = "sync-idle"
263+ hints = [
264+ ("x-canonical-snap-decisions", "true"),
265+ ("x-canonical-non-shaped-icon", "true"),
266+ ]
267+
268+ actions = [
269+ ('action_accept', 'Accept'),
270+ ('action_decline_1', 'Decline'),
271+ ]
272+
273+ self._create_interactive_notification(
274+ summary,
275+ body,
276+ icon_path,
277+ "NORMAL",
278+ actions,
279+ hints
280+ )
281+
282+ # verify that we can swipe away the greeter (interact with the "shell")
283+ time.sleep(1)
284+ self.main_window.show_dash_swiping()
285+ greeter = self.main_window.get_greeter()
286+ self.assertThat(greeter.shown, Eventually(Equals(False)))
287+
288+ # verify and interact with the triggered snap-decision notification
289+ notify_list = self._get_notifications_list()
290+ get_notification = lambda: notify_list.wait_select_single(
291+ 'Notification', objectName='notification1')
292+ notification = get_notification()
293+ self._assert_notification(notification, summary, body, True, False, 1.0)
294+ self.touch.tap_object(notification.select_single(objectName="button0"))
295+ self.assert_notification_action_id_was_called("action_accept")
296+
214 def _create_interactive_notification(
297 def _create_interactive_notification(
215 self,
298 self,
216 summary="",
299 summary="",
tests/mocks/Unity/fake_categories.cpp+15−2
@@ -108,7 +108,12 @@ Categories::data(const QModelIndex& index, int role) const
108 case RoleRenderer:
108 case RoleRenderer:
109 {
109 {
110 QVariantMap map;
110 QVariantMap map;
111− map["category-layout"] = index.row() % 2 == 0 ? "grid" : "carousel";
111+ if (index.row() % 2 == 0) {
112+ map["category-layout"] = "grid";
113+ } else {
114+ map["category-layout"] = "carousel";
115+ map["overlay"] = true;
116+ }
112 map["card-size"] = "small";
117 map["card-size"] = "small";
113 return map;
118 return map;
114 }
119 }
@@ -146,7 +151,14 @@ Categories::data(const QModelIndex& index, int role) const
146 case RoleRenderer:
151 case RoleRenderer:
147 {
152 {
148 QVariantMap map;
153 QVariantMap map;
149− map["category-layout"] = index.row() % 2 == 0 ? "grid" : "carousel";
154+ if (index.row() % 2 == 0) {
155+ map["category-layout"] = "grid";
156+ } else {
157+ map["category-layout"] = "carousel";
158+ map["card-size"] = "medium";
159+ map["collapsed-rows"] = 2;
160+ map["overlay"] = true;
161+ }
150 map["card-size"] = "small";
162 map["card-size"] = "small";
151 return map;
163 return map;
152 }
164 }
@@ -157,6 +169,7 @@ Categories::data(const QModelIndex& index, int role) const
157 artMap["field"] = "art";
169 artMap["field"] = "art";
158 map["art"] = artMap;
170 map["art"] = artMap;
159 map["title"] = "HOLA";
171 map["title"] = "HOLA";
172+ map["subtitle"] = "HOLA";
160 return map;
173 return map;
161 }
174 }
162 case RoleProgressSource:
175 case RoleProgressSource:
tests/mocks/Unity/fake_resultsmodel.cpp+1
@@ -103,6 +103,7 @@ ResultsModel::data(const QModelIndex& index, int role) const
103 case RoleArt:
103 case RoleArt:
104 return qmlDirectory() + "graphics/applicationIcons/dash.png";
104 return qmlDirectory() + "graphics/applicationIcons/dash.png";
105 case RoleSubtitle:
105 case RoleSubtitle:
106+ return QString("Subtitle.%1.%2").arg(m_categoryId).arg(index.row());
106 case RoleMascot:
107 case RoleMascot:
107 case RoleEmblem:
108 case RoleEmblem:
108 case RoleOldPrice:
109 case RoleOldPrice:
tests/plugins/CMakeLists.txt+1−1
@@ -1,6 +1,6 @@
1add_subdirectory(AccountsService)
1add_subdirectory(AccountsService)
2add_subdirectory(LightDM)
2add_subdirectory(LightDM)
3−add_subdirectory(DashViews)
3+add_subdirectory(Dash)
4add_subdirectory(Ubuntu)
4add_subdirectory(Ubuntu)
5add_subdirectory(Unity)
5add_subdirectory(Unity)
6add_subdirectory(Utils)
6add_subdirectory(Utils)
tests/plugins/DashViews/CMakeLists.txt → tests/plugins/Dash/CMakeLists.txtrenamed+16−9
@@ -16,7 +16,7 @@ include_directories(
16 ${Qt5Quick_INCLUDE_DIRS}
16 ${Qt5Quick_INCLUDE_DIRS}
17 ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
17 ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
18 ${Qt5V8_PRIVATE_INCLUDE_DIR}
18 ${Qt5V8_PRIVATE_INCLUDE_DIR}
19− ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews
19+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/Dash
20 ${CMAKE_CURRENT_BINARY_DIR}
20 ${CMAKE_CURRENT_BINARY_DIR}
21 )
21 )
22
22
@@ -28,11 +28,11 @@ add_definitions(-DBUILT_PLUGINS_DIR="${CMAKE_BINARY_DIR}/plugins")
28macro(add_lvwph_test FILENAME TESTNAME)
28macro(add_lvwph_test FILENAME TESTNAME)
29 add_executable(${TESTNAME}TestExec
29 add_executable(${TESTNAME}TestExec
30 ${FILENAME}test.cpp
30 ${FILENAME}test.cpp
31− ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/listviewwithpageheader.cpp)
31+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/Dash/listviewwithpageheader.cpp)
32 qt5_use_modules(${TESTNAME}TestExec Test Core Qml)
32 qt5_use_modules(${TESTNAME}TestExec Test Core Qml)
33 target_link_libraries(${TESTNAME}TestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
33 target_link_libraries(${TESTNAME}TestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
34
34
35− add_binary_qml_test(${TESTNAME} "" "DashViews-qml")
35+ add_binary_qml_test(${TESTNAME} "" "Dash-qml")
36endmacro()
36endmacro()
37
37
38add_lvwph_test(listviewwithpageheader ListViewWithPageHeader)
38add_lvwph_test(listviewwithpageheader ListViewWithPageHeader)
@@ -42,24 +42,24 @@ add_lvwph_test(listviewwithpageheadersectionexternalmodel ListViewWithPageHeader
42macro(add_dashview_try_test FILENAME TESTNAME)
42macro(add_dashview_try_test FILENAME TESTNAME)
43 add_executable(${TESTNAME}TestExec
43 add_executable(${TESTNAME}TestExec
44 ${FILENAME}test.cpp
44 ${FILENAME}test.cpp
45− ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/${FILENAME}.cpp
45+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/Dash/${FILENAME}.cpp
46− ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/abstractdashview.cpp
46+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/Dash/abstractdashview.cpp
47 )
47 )
48 qt5_use_modules(${TESTNAME}TestExec Test Core Qml)
48 qt5_use_modules(${TESTNAME}TestExec Test Core Qml)
49 target_link_libraries(${TESTNAME}TestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
49 target_link_libraries(${TESTNAME}TestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
50
50
51− add_binary_qml_test(${TESTNAME} "" "DashViews-qml")
51+ add_binary_qml_test(${TESTNAME} "" "Dash-qml")
52
52
53 add_executable(${TESTNAME}tryExec
53 add_executable(${TESTNAME}tryExec
54 ${FILENAME}try.cpp
54 ${FILENAME}try.cpp
55− ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/${FILENAME}.cpp
55+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/Dash/${FILENAME}.cpp
56− ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/abstractdashview.cpp
56+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/Dash/abstractdashview.cpp
57 )
57 )
58 qt5_use_modules(${TESTNAME}tryExec Test Core Qml)
58 qt5_use_modules(${TESTNAME}tryExec Test Core Qml)
59 target_link_libraries(${TESTNAME}tryExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
59 target_link_libraries(${TESTNAME}tryExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
60 add_custom_target(try${TESTNAME}
60 add_custom_target(try${TESTNAME}
61 ${CMAKE_CURRENT_BINARY_DIR}/${TESTNAME}tryExec
61 ${CMAKE_CURRENT_BINARY_DIR}/${TESTNAME}tryExec
62− DEPENDS ${TESTNAME}tryExec DashViews-qml
62+ DEPENDS ${TESTNAME}tryExec Dash-qml
63 )
63 )
64endmacro()
64endmacro()
65
65
@@ -67,6 +67,13 @@ add_dashview_try_test(verticaljournal VerticalJournal)
67add_dashview_try_test(horizontaljournal HorizontalJournal)
67add_dashview_try_test(horizontaljournal HorizontalJournal)
68add_dashview_try_test(organicgrid OrganicGrid)
68add_dashview_try_test(organicgrid OrganicGrid)
69
69
70+# CardCreator test
71+add_executable(CardCreatorTestExec cardcreatortest.cpp)
72+qt5_use_modules(CardCreatorTestExec Test Core Qml)
73+target_link_libraries(CardCreatorTestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
74+add_binary_qml_test(CardCreator "" "Dash-qml")
75+
76+# plain qml test
70set(qmltest_DEFAULT_TARGETS qmluitests)
77set(qmltest_DEFAULT_TARGETS qmluitests)
71set(qmltest_DEFAULT_NO_ADD_TEST TRUE)
78set(qmltest_DEFAULT_NO_ADD_TEST TRUE)
72add_qml_test(. ListViewWithPageHeaderQML IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins)
79add_qml_test(. ListViewWithPageHeaderQML IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins)
tests/plugins/Dash/cardcreator/1.resnew file+77
@@ -0,0 +1,77 @@
1+AbstractButton {
2+ id: root;
3+ property var template;
4+ property var components;
5+ property var cardData;
6+ property real fontScale: 1.0;
7+ property int headerAlignment: Text.AlignLeft;
8+ property int fixedHeaderHeight: -1;
9+ property size fixedArtShapeSize: Qt.size(-1, -1);
10+ readonly property string title: cardData && cardData["title"] || "";
11+ property bool asynchronous: true;
12+ property bool showHeader: true;
13+ implicitWidth: childrenRect.width;
14+readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
15+Item {
16+ id: artShapeHolder;
17+ height: root.fixedArtShapeSize.height != -1 ? root.fixedArtShapeSize.height : artShapeLoader.height;
18+ width: root.fixedArtShapeSize.width != -1 ? root.fixedArtShapeSize.width : artShapeLoader.width;
19+ anchors { horizontalCenter: parent.horizontalCenter; }
20+ Loader {
21+ id: artShapeLoader;
22+ objectName: "artShapeLoader";
23+ active: cardData && cardData["art"] || false;
24+ asynchronous: root.asynchronous;
25+ visible: status == Loader.Ready;
26+ sourceComponent: UbuntuShape {
27+ id: artShape;
28+ objectName: "artShape";
29+ radius: "medium";
30+ readonly property real aspect: components !== undefined ? components["art"]["aspect-ratio"] : 1;
31+ readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect;
32+ Component.onCompleted: updateWidthHeightBindings();
33+ onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings();
34+ visible: image.status == Image.Ready;
35+ function updateWidthHeightBindings() {
36+ if (aspectSmallerThanImageAspect) {
37+ width = Qt.binding(function() { return !visible ? 0 : image.width });
38+ height = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.height : width / image.aspect });
39+ } else {
40+ width = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.width : height * image.aspect });
41+ height = Qt.binding(function() { return !visible ? 0 : image.height });
42+ }
43+ }
44+ image: Image {
45+ objectName: "artImage";
46+ source: cardData && cardData["art"] || "";
47+ cache: true;
48+ asynchronous: root.asynchronous;
49+ fillMode: components && components["art"]["fill-mode"] === "fit" ? Image.PreserveAspectFit: Image.PreserveAspectCrop;
50+ readonly property real aspect: implicitWidth / implicitHeight;
51+ width: root.width;
52+ height: width / artShape.aspect;
53+ }
54+ }
55+ }
56+ }
57+readonly property int headerHeight: titleLabel.height + titleLabel.anchors.topMargin * 2;
58+Label {
59+ id: titleLabel;
60+ objectName: "titleLabel";
61+ anchors { right: parent.right;left: parent.left;
62+top: artShapeHolder.bottom;
63+ topMargin: units.gu(1);
64+ }
65+ elide: Text.ElideRight;
66+ fontSize: "small";
67+ wrapMode: Text.Wrap;
68+ maximumLineCount: 2;
69+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
70+ color: "grey";
71+ visible: showHeader ;
72+ text: root.title;
73+ font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
74+ horizontalAlignment: root.headerAlignment;
75+ }
76+implicitHeight: titleLabel.y + titleLabel.height + units.gu(1);
77+}
tests/plugins/Dash/cardcreator/1.tstnew file+3
@@ -0,0 +1,3 @@
1+template: {"card-layout":"vertical","card-size":"small","category-layout":"grid","collapsed-rows":2}
2+components: {"art":{"aspect-ratio":1.6,"field":"art","fill-mode":"fit"},"title":{"field":"title"}}
3+result: 1.res
tests/plugins/Dash/cardcreator/2.resnew file+115
@@ -0,0 +1,115 @@
1+AbstractButton {
2+ id: root;
3+ property var template;
4+ property var components;
5+ property var cardData;
6+ property real fontScale: 1.0;
7+ property int headerAlignment: Text.AlignLeft;
8+ property int fixedHeaderHeight: -1;
9+ property size fixedArtShapeSize: Qt.size(-1, -1);
10+ readonly property string title: cardData && cardData["title"] || "";
11+ property bool asynchronous: true;
12+ property bool showHeader: true;
13+ implicitWidth: childrenRect.width;
14+Loader {
15+ id: backgroundLoader;
16+ objectName: "backgroundLoader";
17+ anchors.fill: parent;
18+ asynchronous: root.asynchronous;
19+ visible: status == Loader.Ready;
20+ sourceComponent: UbuntuShape {
21+ objectName: "background";
22+ radius: "medium";
23+ color: getColor(0) || "white";
24+ gradientColor: getColor(1) || color;
25+ anchors.fill: parent;
26+ image: backgroundImage.source ? backgroundImage : null;
27+ property real luminance: 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b;
28+ property Image backgroundImage: Image {
29+ objectName: "backgroundImage";
30+ source: {
31+ if (cardData && typeof cardData["background"] === "string") return cardData["background"];
32+ else if (template && typeof template["card-background"] === "string") return template["card-background"];
33+ else return "";
34+ }
35+ }
36+ function getColor(index) {
37+ if (cardData && typeof cardData["background"] === "object"
38+ && (cardData["background"]["type"] === "color" || cardData["background"]["type"] === "gradient")) {
39+ return cardData["background"]["elements"][index];
40+ } else if (template && typeof template["card-background"] === "object"
41+ && (template["card-background"]["type"] === "color" || template["card-background"]["type"] === "gradient")) {
42+ return template["card-background"]["elements"][index];
43+ } else return undefined;
44+ }
45+ }
46+ }
47+readonly property size artShapeSize: Qt.size(-1, -1);
48+readonly property int headerHeight: row.height + row.margins * 2;
49+Row {
50+ id: row;
51+ objectName: "outerRow";
52+ property real margins: units.gu(1);
53+ spacing: margins;
54+ anchors { top: parent.top;
55+ topMargin: units.gu(1);
56+ left: parent.left;
57+}
58+ anchors.right: parent.right;
59+ anchors.margins: margins;
60+data: [ Image {
61+ id: mascotImage;
62+ objectName: "mascotImage";
63+ anchors { verticalCenter: parent.verticalCenter; }
64+ readonly property int maxSize: Math.max(width, height) * 4;
65+ source: cardData && cardData["mascot"];
66+ width: units.gu(6);
67+ height: units.gu(5.625);
68+ sourceSize { width: maxSize; height: maxSize }
69+ fillMode: Image.PreserveAspectCrop;
70+ horizontalAlignment: Image.AlignHCenter;
71+ verticalAlignment: Image.AlignVCenter;
72+ visible: showHeader;
73+ }
74+,
75+Column {
76+ anchors.verticalCenter: parent.verticalCenter;
77+ spacing: units.dp(2);
78+ width: parent.width - x;
79+ data: [
80+Label {
81+ id: titleLabel;
82+ objectName: "titleLabel";
83+ anchors { left: parent.left; right: parent.right }
84+ elide: Text.ElideRight;
85+ fontSize: "small";
86+ wrapMode: Text.Wrap;
87+ maximumLineCount: 2;
88+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
89+ color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < 0.7 ? "white" : "grey";
90+ visible: showHeader ;
91+ text: root.title;
92+ font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
93+ horizontalAlignment: root.headerAlignment;
94+ }
95+,
96+Label {
97+ id: subtitleLabel;
98+ objectName: "subtitleLabel";
99+ anchors { left: parent.left; right: parent.right }
100+
101+ elide: Text.ElideRight;
102+ fontSize: "small";
103+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
104+ color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < 0.7 ? "white" : "grey";
105+ visible: titleLabel.visible && titleLabel.text;
106+ text: cardData && cardData["subtitle"] || "";
107+ font.weight: Font.Light;
108+ horizontalAlignment: root.headerAlignment;
109+ }
110+]
111+}
112+]
113+}
114+implicitHeight: row.y + row.height + units.gu(1);
115+}
tests/plugins/Dash/cardcreator/2.tstnew file+3
@@ -0,0 +1,3 @@
1+template: {"card-background":{"elements":["#E9E9E9"],"type":"color"},"card-layout":"vertical","card-size":"medium","category-layout":"grid","collapsed-rows":2}
2+components: {"art":{"aspect-ratio":1,"fill-mode":"crop"},"background":{"field":"background"},"mascot":{"field":"icon"},"subtitle":{"field":"author"},"title":{"field":"title"}}
3+result: 2.res
tests/plugins/Dash/cardcreator/3.resnew file+94
@@ -0,0 +1,94 @@
1+AbstractButton {
2+ id: root;
3+ property var template;
4+ property var components;
5+ property var cardData;
6+ property real fontScale: 1.0;
7+ property int headerAlignment: Text.AlignLeft;
8+ property int fixedHeaderHeight: -1;
9+ property size fixedArtShapeSize: Qt.size(-1, -1);
10+ readonly property string title: cardData && cardData["title"] || "";
11+ property bool asynchronous: true;
12+ property bool showHeader: true;
13+ implicitWidth: childrenRect.width;
14+readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
15+Item {
16+ id: artShapeHolder;
17+ height: root.fixedArtShapeSize.height != -1 ? root.fixedArtShapeSize.height : artShapeLoader.height;
18+ width: root.fixedArtShapeSize.width != -1 ? root.fixedArtShapeSize.width : artShapeLoader.width;
19+ anchors { horizontalCenter: parent.horizontalCenter; }
20+ Loader {
21+ id: artShapeLoader;
22+ objectName: "artShapeLoader";
23+ active: cardData && cardData["art"] || false;
24+ asynchronous: root.asynchronous;
25+ visible: status == Loader.Ready;
26+ sourceComponent: UbuntuShape {
27+ id: artShape;
28+ objectName: "artShape";
29+ radius: "medium";
30+ readonly property real aspect: components !== undefined ? components["art"]["aspect-ratio"] : 1;
31+ readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect;
32+ Component.onCompleted: updateWidthHeightBindings();
33+ onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings();
34+ visible: image.status == Image.Ready;
35+ function updateWidthHeightBindings() {
36+ if (aspectSmallerThanImageAspect) {
37+ width = Qt.binding(function() { return !visible ? 0 : image.width });
38+ height = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.height : width / image.aspect });
39+ } else {
40+ width = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.width : height * image.aspect });
41+ height = Qt.binding(function() { return !visible ? 0 : image.height });
42+ }
43+ }
44+ image: Image {
45+ objectName: "artImage";
46+ source: cardData && cardData["art"] || "";
47+ cache: true;
48+ asynchronous: root.asynchronous;
49+ fillMode: components && components["art"]["fill-mode"] === "fit" ? Image.PreserveAspectFit: Image.PreserveAspectCrop;
50+ readonly property real aspect: implicitWidth / implicitHeight;
51+ width: root.width;
52+ height: width / artShape.aspect;
53+ }
54+ }
55+ }
56+ }
57+readonly property int headerHeight: titleLabel.height + titleLabel.anchors.topMargin * 2 + subtitleLabel.height + subtitleLabel.anchors.topMargin;
58+Label {
59+ id: titleLabel;
60+ objectName: "titleLabel";
61+ anchors { right: parent.right;left: parent.left;
62+top: artShapeHolder.bottom;
63+ topMargin: units.gu(1);
64+}
65+ elide: Text.ElideRight;
66+ fontSize: "small";
67+ wrapMode: Text.Wrap;
68+ maximumLineCount: 2;
69+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
70+ color: "grey";
71+ visible: showHeader ;
72+ text: root.title;
73+ font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
74+ horizontalAlignment: root.headerAlignment;
75+ }
76+Label {
77+ id: subtitleLabel;
78+ objectName: "subtitleLabel";
79+ anchors { left: titleLabel.left;
80+ leftMargin: titleLabel.leftMargin;
81+ right: titleLabel.right;
82+ top: titleLabel.bottom;
83+ topMargin: units.dp(2); }
84+ elide: Text.ElideRight;
85+ fontSize: "small";
86+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
87+ color: "grey";
88+ visible: titleLabel.visible && titleLabel.text;
89+ text: cardData && cardData["subtitle"] || "";
90+ font.weight: Font.Light;
91+ horizontalAlignment: root.headerAlignment;
92+ }
93+implicitHeight: subtitleLabel.y + subtitleLabel.height + units.gu(1);
94+}
tests/plugins/Dash/cardcreator/3.tstnew file+3
@@ -0,0 +1,3 @@
1+template: {"card-layout":"vertical","card-size":"small","category-layout":"grid","collapsed-rows":2}
2+components: {"art":{"aspect-ratio":0.75,"field":"art","fill-mode":"crop"},"subtitle":{"field":"price"},"title":{"field":"title"}}
3+result: 3.res
tests/plugins/Dash/cardcreator/4.resnew file+95
@@ -0,0 +1,95 @@
1+AbstractButton {
2+ id: root;
3+ property var template;
4+ property var components;
5+ property var cardData;
6+ property real fontScale: 1.0;
7+ property int headerAlignment: Text.AlignLeft;
8+ property int fixedHeaderHeight: -1;
9+ property size fixedArtShapeSize: Qt.size(-1, -1);
10+ readonly property string title: cardData && cardData["title"] || "";
11+ property bool asynchronous: true;
12+ property bool showHeader: true;
13+ implicitWidth: childrenRect.width;
14+readonly property size artShapeSize: Qt.size(-1, -1);
15+readonly property int headerHeight: row.height + row.margins * 2;
16+Row {
17+ id: row;
18+ objectName: "outerRow";
19+ property real margins: units.gu(1);
20+ spacing: margins;
21+ anchors { top: parent.top;
22+ topMargin: units.gu(1);
23+ left: parent.left;
24+}
25+ anchors.right: parent.right;
26+ anchors.margins: margins;
27+data: [ Loader {
28+ id: mascotShapeLoader;
29+ objectName: "mascotShapeLoader";
30+ asynchronous: root.asynchronous;
31+ active: mascotImage.status === Image.Ready;
32+ visible: showHeader && active && status == Loader.Ready;
33+ width: units.gu(6);
34+ height: units.gu(5.625);
35+ sourceComponent: UbuntuShape { image: mascotImage }
36+ anchors { verticalCenter: parent.verticalCenter; }
37+ }
38+
39+,
40+Image {
41+ id: mascotImage;
42+ objectName: "mascotImage";
43+ anchors { verticalCenter: parent.verticalCenter; }
44+ readonly property int maxSize: Math.max(width, height) * 4;
45+ source: cardData && cardData["mascot"];
46+ width: units.gu(6);
47+ height: units.gu(5.625);
48+ sourceSize { width: maxSize; height: maxSize }
49+ fillMode: Image.PreserveAspectCrop;
50+ horizontalAlignment: Image.AlignHCenter;
51+ verticalAlignment: Image.AlignVCenter;
52+ visible: false;
53+ }
54+
55+,
56+Column {
57+ anchors.verticalCenter: parent.verticalCenter;
58+ spacing: units.dp(2);
59+ width: parent.width - x;
60+data: [ Label {
61+ id: titleLabel;
62+ objectName: "titleLabel";
63+ anchors { left: parent.left; right: parent.right }
64+ elide: Text.ElideRight;
65+ fontSize: "small";
66+ wrapMode: Text.Wrap;
67+ maximumLineCount: 2;
68+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
69+ color: "grey";
70+ visible: showHeader ;
71+ text: root.title;
72+ font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
73+ horizontalAlignment: root.headerAlignment;
74+ }
75+,
76+Label {
77+ id: subtitleLabel;
78+ objectName: "subtitleLabel";
79+ anchors { left: parent.left; right: parent.right }
80+
81+ elide: Text.ElideRight;
82+ fontSize: "small";
83+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
84+ color: "grey";
85+ visible: titleLabel.visible && titleLabel.text;
86+ text: cardData && cardData["subtitle"] || "";
87+ font.weight: Font.Light;
88+ horizontalAlignment: root.headerAlignment;
89+ }
90+]
91+}
92+]
93+}
94+implicitHeight: row.y + row.height + units.gu(1);
95+}
tests/plugins/Dash/cardcreator/4.tstnew file+3
@@ -0,0 +1,3 @@
1+template: {"card-layout":"horizontal","card-size":"large","category-layout":"grid","collapsed-rows":2}
2+components: {"art":{"aspect-ratio":1,"fill-mode":"crop"},"mascot":{"field":"mascot"},"subtitle":{"field":"domain"},"title":{"field":"title"}}
3+result: 4.res
tests/plugins/Dash/cardcreator/5.resnew file+137
@@ -0,0 +1,137 @@
1+AbstractButton {
2+ id: root;
3+ property var template;
4+ property var components;
5+ property var cardData;
6+ property real fontScale: 1.0;
7+ property int headerAlignment: Text.AlignLeft;
8+ property int fixedHeaderHeight: -1;
9+ property size fixedArtShapeSize: Qt.size(-1, -1);
10+ readonly property string title: cardData && cardData["title"] || "";
11+ property bool asynchronous: true;
12+ property bool showHeader: true;
13+ implicitWidth: childrenRect.width;
14+readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
15+Item {
16+ id: artShapeHolder;
17+ height: root.fixedArtShapeSize.height != -1 ? root.fixedArtShapeSize.height : artShapeLoader.height;
18+ width: root.fixedArtShapeSize.width != -1 ? root.fixedArtShapeSize.width : artShapeLoader.width;
19+ anchors { horizontalCenter: parent.horizontalCenter; }
20+ Loader {
21+ id: artShapeLoader;
22+ objectName: "artShapeLoader";
23+ active: cardData && cardData["art"] || false;
24+ asynchronous: root.asynchronous;
25+ visible: status == Loader.Ready;
26+ sourceComponent: UbuntuShape {
27+ id: artShape;
28+ objectName: "artShape";
29+ radius: "medium";
30+ readonly property real aspect: components !== undefined ? components["art"]["aspect-ratio"] : 1;
31+ readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect;
32+ Component.onCompleted: updateWidthHeightBindings();
33+ onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings();
34+ visible: image.status == Image.Ready;
35+ function updateWidthHeightBindings() {
36+ if (aspectSmallerThanImageAspect) {
37+ width = Qt.binding(function() { return !visible ? 0 : image.width });
38+ height = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.height : width / image.aspect });
39+ } else {
40+ width = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.width : height * image.aspect });
41+ height = Qt.binding(function() { return !visible ? 0 : image.height });
42+ }
43+ }
44+ image: Image {
45+ objectName: "artImage";
46+ source: cardData && cardData["art"] || "";
47+ cache: true;
48+ asynchronous: root.asynchronous;
49+ fillMode: components && components["art"]["fill-mode"] === "fit" ? Image.PreserveAspectFit: Image.PreserveAspectCrop;
50+ readonly property real aspect: implicitWidth / implicitHeight;
51+ width: root.width;
52+ height: width / artShape.aspect;
53+ }
54+ }
55+ }
56+ }
57+Loader {
58+ id: overlayLoader;
59+ anchors {
60+ left: artShapeHolder.left;
61+ right: artShapeHolder.right;
62+ bottom: artShapeHolder.bottom;
63+ }
64+ active: artShapeLoader.active && artShapeLoader.item && artShapeLoader.item.image.status === Image.Ready || false;
65+ asynchronous: root.asynchronous;
66+ visible: showHeader && status == Loader.Ready;
67+ sourceComponent: ShaderEffect {
68+ id: overlay;
69+ height: fixedHeaderHeight != -1 ? fixedHeaderHeight : headerHeight;
70+ opacity: 0.6;
71+ property var source: ShaderEffectSource {
72+ id: shaderSource;
73+ sourceItem: artShapeLoader.item;
74+ onVisibleChanged: if (visible) scheduleUpdate();
75+ live: false;
76+ sourceRect: Qt.rect(0, artShapeLoader.height - overlay.height, artShapeLoader.width, overlay.height);
77+ }
78+ vertexShader: "
79+ uniform highp mat4 qt_Matrix;
80+ attribute highp vec4 qt_Vertex;
81+ attribute highp vec2 qt_MultiTexCoord0;
82+ varying highp vec2 coord;
83+ void main() {
84+ coord = qt_MultiTexCoord0;
85+ gl_Position = qt_Matrix * qt_Vertex;
86+ }";
87+ fragmentShader: "
88+ varying highp vec2 coord;
89+ uniform sampler2D source;
90+ uniform lowp float qt_Opacity;
91+ void main() {
92+ lowp vec4 tex = texture2D(source, coord);
93+ gl_FragColor = vec4(0, 0, 0, tex.a) * qt_Opacity;
94+ }";
95+ }
96+ }
97+readonly property int headerHeight: titleLabel.height + titleLabel.anchors.topMargin * 2 + subtitleLabel.height + subtitleLabel.anchors.topMargin;
98+Label {
99+ id: titleLabel;
100+ objectName: "titleLabel";
101+ anchors { left: parent.left;
102+ leftMargin: units.gu(1);
103+ right: parent.right;
104+ top: overlayLoader.top;
105+ topMargin: units.gu(1);
106+}
107+ elide: Text.ElideRight;
108+ fontSize: "small";
109+ wrapMode: Text.Wrap;
110+ maximumLineCount: 2;
111+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
112+ color: "white";
113+ visible: showHeader && overlayLoader.active;
114+ text: root.title;
115+ font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
116+ horizontalAlignment: root.headerAlignment;
117+ }
118+Label {
119+ id: subtitleLabel;
120+ objectName: "subtitleLabel";
121+ anchors { left: titleLabel.left;
122+ leftMargin: titleLabel.leftMargin;
123+ right: titleLabel.right;
124+ top: titleLabel.bottom;
125+ topMargin: units.dp(2);
126+ }
127+ elide: Text.ElideRight;
128+ fontSize: "small";
129+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
130+ color: "white";
131+ visible: titleLabel.visible && titleLabel.text;
132+ text: cardData && cardData["subtitle"] || "";
133+ font.weight: Font.Light;
134+ horizontalAlignment: root.headerAlignment;
135+ }
136+implicitHeight: subtitleLabel.y + subtitleLabel.height + units.gu(1);
137+}
tests/plugins/Dash/cardcreator/5.tstnew file+3
@@ -0,0 +1,3 @@
1+template: {"card-layout":"vertical","card-size":"medium","category-layout":"carousel","collapsed-rows":2,"overlay":true}
2+components: {"art":{"aspect-ratio":1,"field":"art","fill-mode":"crop"},"subtitle":{"field":"artist"},"title":{"field":"title"}}
3+result: 5.res
tests/plugins/Dash/cardcreatortest.cppnew file+91
@@ -0,0 +1,91 @@
1+/*
2+ * Copyright (C) 2014 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+#include <QDir>
18+#include <QQmlEngine>
19+#include <QQuickItem>
20+#include <QQuickView>
21+#include <QtTestGui>
22+
23+class CardCreatorTest : public QObject
24+{
25+ Q_OBJECT
26+
27+private Q_SLOTS:
28+
29+ void initTestCase()
30+ {
31+ }
32+
33+ void init()
34+ {
35+ view = new QQuickView();
36+ view->engine()->addImportPath(BUILT_PLUGINS_DIR);
37+ view->setSource(QUrl::fromLocalFile(DASHVIEWSTEST_FOLDER "/cardcreatortest.qml"));
38+ view->show();
39+ QTest::qWaitForWindowExposed(view);
40+ }
41+
42+ void cleanup()
43+ {
44+ delete view;
45+ }
46+
47+ void testKnownCases()
48+ {
49+ const QString templateString("template: ");
50+ const QString componentsString("components: ");
51+ const QString resultString("result: ");
52+
53+ const QString testDirPath = DASHVIEWSTEST_FOLDER "/cardcreator/";
54+ QDir d(testDirPath);
55+ const QStringList testFiles = d.entryList(QStringList() << "*.tst");
56+ foreach(const QString &testFileName, testFiles) {
57+ qDebug() << testFileName;
58+ QFile testFile(testDirPath + testFileName);
59+ QVERIFY(testFile.open(QIODevice::ReadOnly));
60+ QTextStream ts(&testFile);
61+ const QStringList lines = ts.readAll().split("\n");
62+
63+ QVERIFY(lines[0].startsWith(templateString));
64+ QVERIFY(lines[1].startsWith(componentsString));
65+ QVERIFY(lines[2].startsWith(resultString));
66+ const QString templateJSON = lines[0].mid(templateString.length());
67+ const QString componentsJSON = lines[1].mid(componentsString.length());
68+ const QString resultFileName = lines[2].mid(resultString.length());
69+
70+ QVariant cardStringResult;
71+ QMetaObject::invokeMethod(view->rootObject(), "cardString", Q_RETURN_ARG(QVariant, cardStringResult), Q_ARG(QVariant, templateJSON), Q_ARG(QVariant, componentsJSON));
72+
73+ QFile testResultFile(testDirPath + resultFileName);
74+ QVERIFY(testResultFile.open(QIODevice::ReadOnly));
75+ QTextStream ts2(&testResultFile);
76+ const QString expectedResult = ts2.readAll();
77+ QCOMPARE(cardStringResult.toString().simplified(), expectedResult.simplified());
78+
79+ QVariant createCardComponentResult;
80+ QMetaObject::invokeMethod(view->rootObject(), "createCardComponent", Q_RETURN_ARG(QVariant, createCardComponentResult), Q_ARG(QVariant, templateJSON), Q_ARG(QVariant, componentsJSON));
81+ QVERIFY(createCardComponentResult.toBool());
82+ }
83+ }
84+
85+private:
86+ QQuickView *view;
87+};
88+
89+QTEST_MAIN(CardCreatorTest)
90+
91+#include "cardcreatortest.moc"
tests/plugins/Dash/cardcreatortest.qmlnew file+29
@@ -0,0 +1,29 @@
1+/*
2+ * Copyright (C) 2014 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.2
18+import "../../../plugins/Dash/CardCreator.js" as CardCreator
19+
20+Item {
21+ id: root
22+ function cardString(template, components) {
23+ return CardCreator.cardString(JSON.parse(template), JSON.parse(components));
24+ }
25+
26+ function createCardComponent(template, components) {
27+ return CardCreator.createCardComponent(root, JSON.parse(template), JSON.parse(components)) !== null;
28+ }
29+}
tests/plugins/DashViews/horizontaljournaltest.cpp → tests/plugins/Dash/horizontaljournaltest.cpprenamed

The content is the same.

tests/plugins/DashViews/horizontaljournaltest.qml → tests/plugins/Dash/horizontaljournaltest.qmlrenamed+1−1
@@ -15,7 +15,7 @@
15 */
15 */
16
16
17import QtQuick 2.1
17import QtQuick 2.1
18−import DashViews 0.1
18+import Dash 0.1
19
19
20Item {
20Item {
21
21
tests/plugins/DashViews/horizontaljournaltry.cpp → tests/plugins/Dash/horizontaljournaltry.cpprenamed

The content is the same.

tests/plugins/DashViews/horizontaljournaltry.qml → tests/plugins/Dash/horizontaljournaltry.qmlrenamed+1−1
@@ -15,7 +15,7 @@
15 */
15 */
16
16
17import QtQuick 2.1
17import QtQuick 2.1
18−import DashViews 0.1
18+import Dash 0.1
19
19
20Item {
20Item {
21 id: root
21 id: root
tests/plugins/DashViews/listviewwithpageheadersectionexternalmodeltest.cpp → tests/plugins/Dash/listviewwithpageheadersectionexternalmodeltest.cpprenamed−4
@@ -24,11 +24,7 @@
24#include <QtTestGui>
24#include <QtTestGui>
25#pragma GCC diagnostic push
25#pragma GCC diagnostic push
26#pragma GCC diagnostic ignored "-pedantic"
26#pragma GCC diagnostic ignored "-pedantic"
27−#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
28−#include <private/qquicklistmodel_p.h>
29−#else
30#include <private/qqmllistmodel_p.h>
27#include <private/qqmllistmodel_p.h>
31−#endif
32#include <private/qquickanimation_p.h>
28#include <private/qquickanimation_p.h>
33#include <private/qquickitem_p.h>
29#include <private/qquickitem_p.h>
34#pragma GCC diagnostic pop
30#pragma GCC diagnostic pop
tests/plugins/DashViews/listviewwithpageheadersectiontest.cpp → tests/plugins/Dash/listviewwithpageheadersectiontest.cpprenamed−12
@@ -23,11 +23,7 @@
23#include <QtTestGui>
23#include <QtTestGui>
24#pragma GCC diagnostic push
24#pragma GCC diagnostic push
25#pragma GCC diagnostic ignored "-pedantic"
25#pragma GCC diagnostic ignored "-pedantic"
26−#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
27−#include <private/qquicklistmodel_p.h>
28−#else
29#include <private/qqmllistmodel_p.h>
26#include <private/qqmllistmodel_p.h>
30−#endif
31#include <private/qquickanimation_p.h>
27#include <private/qquickanimation_p.h>
32#include <private/qquickitem_p.h>
28#include <private/qquickitem_p.h>
33#pragma GCC diagnostic pop
29#pragma GCC diagnostic pop
@@ -135,11 +131,7 @@ private Q_SLOTS:
135 view->engine()->addImportPath(BUILT_PLUGINS_DIR);
131 view->engine()->addImportPath(BUILT_PLUGINS_DIR);
136 view->setSource(QUrl::fromLocalFile(DASHVIEWSTEST_FOLDER "/listviewwithpageheadertestsection.qml"));
132 view->setSource(QUrl::fromLocalFile(DASHVIEWSTEST_FOLDER "/listviewwithpageheadertestsection.qml"));
137 lvwph = dynamic_cast<ListViewWithPageHeader*>(view->rootObject()->findChild<QQuickFlickable*>());
133 lvwph = dynamic_cast<ListViewWithPageHeader*>(view->rootObject()->findChild<QQuickFlickable*>());
138−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
139− model = view->rootObject()->findChild<QQuickListModel*>();
140−#else
141 model = view->rootObject()->findChild<QQmlListModel*>();
134 model = view->rootObject()->findChild<QQmlListModel*>();
142−#endif
143 otherDelegate = view->rootObject()->findChild<QQmlComponent*>();
135 otherDelegate = view->rootObject()->findChild<QQmlComponent*>();
144 QVERIFY(lvwph);
136 QVERIFY(lvwph);
145 QVERIFY(model);
137 QVERIFY(model);
@@ -2156,11 +2148,7 @@ private Q_SLOTS:
2156private:
2148private:
2157 QQuickView *view;
2149 QQuickView *view;
2158 ListViewWithPageHeader *lvwph;
2150 ListViewWithPageHeader *lvwph;
2159−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
2160− QQuickListModel *model;
2161−#else
2162 QQmlListModel *model;
2151 QQmlListModel *model;
2163−#endif
2164 QQmlComponent *otherDelegate;
2152 QQmlComponent *otherDelegate;
2165};
2153};
2166
2154
tests/plugins/DashViews/listviewwithpageheadertest.cpp → tests/plugins/Dash/listviewwithpageheadertest.cpprenamed−15
@@ -23,11 +23,7 @@
23#include <QtTestGui>
23#include <QtTestGui>
24#pragma GCC diagnostic push
24#pragma GCC diagnostic push
25#pragma GCC diagnostic ignored "-pedantic"
25#pragma GCC diagnostic ignored "-pedantic"
26−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
27−#include <private/qquicklistmodel_p.h>
28−#else
29#include <private/qqmllistmodel_p.h>
26#include <private/qqmllistmodel_p.h>
30−#endif
31#include <private/qquickanimation_p.h>
27#include <private/qquickanimation_p.h>
32#include <private/qquickitem_p.h>
28#include <private/qquickitem_p.h>
33#pragma GCC diagnostic pop
29#pragma GCC diagnostic pop
@@ -124,11 +120,7 @@ private Q_SLOTS:
124 view->engine()->addImportPath(BUILT_PLUGINS_DIR);
120 view->engine()->addImportPath(BUILT_PLUGINS_DIR);
125 view->setSource(QUrl::fromLocalFile(DASHVIEWSTEST_FOLDER "/listviewwithpageheadertest.qml"));
121 view->setSource(QUrl::fromLocalFile(DASHVIEWSTEST_FOLDER "/listviewwithpageheadertest.qml"));
126 lvwph = dynamic_cast<ListViewWithPageHeader*>(view->rootObject()->findChild<QQuickFlickable*>());
122 lvwph = dynamic_cast<ListViewWithPageHeader*>(view->rootObject()->findChild<QQuickFlickable*>());
127−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
128− model = view->rootObject()->findChild<QQuickListModel*>();
129−#else
130 model = view->rootObject()->findChild<QQmlListModel*>();
123 model = view->rootObject()->findChild<QQmlListModel*>();
131−#endif
132 otherDelegate = view->rootObject()->findChild<QQmlComponent*>();
124 otherDelegate = view->rootObject()->findChild<QQmlComponent*>();
133 QVERIFY(lvwph);
125 QVERIFY(lvwph);
134 QVERIFY(model);
126 QVERIFY(model);
@@ -1747,9 +1739,6 @@ private Q_SLOTS:
1747
1739
1748 void testMaximizeVisibleAreaMoveUpAndShowHeader()
1740 void testMaximizeVisibleAreaMoveUpAndShowHeader()
1749 {
1741 {
1750−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
1751− QSKIP("This test is extremely unstable in 5.0.x");
1752−#endif
1753 model->setProperty(0, "size", 800);
1742 model->setProperty(0, "size", 800);
1754 verifyItem(0, 50., 800., false);
1743 verifyItem(0, 50., 800., false);
1755
1744
@@ -1913,11 +1902,7 @@ private Q_SLOTS:
1913private:
1902private:
1914 QQuickView *view;
1903 QQuickView *view;
1915 ListViewWithPageHeader *lvwph;
1904 ListViewWithPageHeader *lvwph;
1916−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
1917− QQuickListModel *model;
1918−#else
1919 QQmlListModel *model;
1905 QQmlListModel *model;
1920−#endif
1921 QQmlComponent *otherDelegate;
1906 QQmlComponent *otherDelegate;
1922};
1907};
1923
1908
tests/plugins/DashViews/listviewwithpageheadertest.qml → tests/plugins/Dash/listviewwithpageheadertest.qmlrenamed+1−1
@@ -15,7 +15,7 @@
15 */
15 */
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18−import DashViews 0.1
18+import Dash 0.1
19
19
20Rectangle {
20Rectangle {
21 width: 300
21 width: 300
tests/plugins/DashViews/listviewwithpageheadertestsection.qml → tests/plugins/Dash/listviewwithpageheadertestsection.qmlrenamed+1−1
@@ -15,7 +15,7 @@
15 */
15 */
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18−import DashViews 0.1
18+import Dash 0.1
19
19
20Rectangle {
20Rectangle {
21 width: 300
21 width: 300
tests/plugins/DashViews/listviewwithpageheadertestsectionexternalmodel.qml → tests/plugins/Dash/listviewwithpageheadertestsectionexternalmodel.qmlrenamed+1−1
@@ -15,7 +15,7 @@
15 */
15 */
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18−import DashViews 0.1
18+import Dash 0.1
19
19
20Rectangle {
20Rectangle {
21 width: 300
21 width: 300
tests/plugins/DashViews/organicgridtest.cpp → tests/plugins/Dash/organicgridtest.cpprenamed

The content is the same.

tests/plugins/DashViews/organicgridtest.qml → tests/plugins/Dash/organicgridtest.qmlrenamed+1−1
@@ -15,7 +15,7 @@
15 */
15 */
16
16
17import QtQuick 2.1
17import QtQuick 2.1
18−import DashViews 0.1
18+import Dash 0.1
19
19
20Item {
20Item {
21
21
tests/plugins/DashViews/organicgridtry.cpp → tests/plugins/Dash/organicgridtry.cpprenamed

The content is the same.

tests/plugins/DashViews/organicgridtry.qml → tests/plugins/Dash/organicgridtry.qmlrenamed+1−1
@@ -15,7 +15,7 @@
15 */
15 */
16
16
17import QtQuick 2.1
17import QtQuick 2.1
18−import DashViews 0.1
18+import Dash 0.1
19
19
20Item {
20Item {
21 id: root
21 id: root
tests/plugins/DashViews/tst_ListViewWithPageHeaderQML.qml → tests/plugins/Dash/tst_ListViewWithPageHeaderQML.qmlrenamed+1−1
@@ -16,7 +16,7 @@
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18import QtTest 1.0
18import QtTest 1.0
19−import DashViews 0.1
19+import Dash 0.1
20
20
21Rectangle {
21Rectangle {
22 width: 300
22 width: 300
tests/plugins/DashViews/verticaljournaltest.cpp → tests/plugins/Dash/verticaljournaltest.cpprenamed

The content is the same.

tests/plugins/DashViews/verticaljournaltest.qml → tests/plugins/Dash/verticaljournaltest.qmlrenamed+1−1
@@ -15,7 +15,7 @@
15 */
15 */
16
16
17import QtQuick 2.1
17import QtQuick 2.1
18−import DashViews 0.1
18+import Dash 0.1
19
19
20Item {
20Item {
21
21
tests/plugins/DashViews/verticaljournaltry.cpp → tests/plugins/Dash/verticaljournaltry.cpprenamed

The content is the same.

tests/plugins/DashViews/verticaljournaltry.qml → tests/plugins/Dash/verticaljournaltry.qmlrenamed+1−1
@@ -15,7 +15,7 @@
15 */
15 */
16
16
17import QtQuick 2.1
17import QtQuick 2.1
18−import DashViews 0.1
18+import Dash 0.1
19
19
20Item {
20Item {
21 id: root
21 id: root
tests/plugins/Unity/Launcher/CMakeLists.txt+3−3
@@ -15,9 +15,9 @@ add_definitions(-DSRCDIR="${CMAKE_CURRENT_SOURCE_DIR}")
15add_definitions(-DLAUNCHER_TESTING)
15add_definitions(-DLAUNCHER_TESTING)
16
16
17### LauncherBackendTest
17### LauncherBackendTest
18−set(testBackendCommand ${CMAKE_CURRENT_BINARY_DIR}/launcherbackendtestExec
18+set(testBackendCommand dbus-test-runner --task ${CMAKE_CURRENT_BINARY_DIR}/launcherbackendtestExec
19− -o ${CMAKE_BINARY_DIR}/launcherbackendtest.xml,xunitxml
19+ --parameter -o --parameter ${CMAKE_BINARY_DIR}/launcherbackendtest.xml,xunitxml
20− -o -,txt)
20+ --parameter -o --parameter -,txt)
21add_test(NAME launcherbackendtest COMMAND ${testBackendCommand})
21add_test(NAME launcherbackendtest COMMAND ${testBackendCommand})
22add_custom_target(launcherbackendtest ${testBackendCommand})
22add_custom_target(launcherbackendtest ${testBackendCommand})
23add_executable(launcherbackendtestExec
23add_executable(launcherbackendtestExec
tests/plugins/Unity/Launcher/launcherbackendtest.cpp+167
@@ -20,6 +20,10 @@
20#include "launcherbackend.h"
20#include "launcherbackend.h"
21
21
22#include <QtTest>
22#include <QtTest>
23+#include <QDBusConnection>
24+#include <QDBusMessage>
25+#include <QDBusVariant>
26+
23
27
24class LauncherBackendTest : public QObject
28class LauncherBackendTest : public QObject
25{
29{
@@ -66,6 +70,169 @@ private Q_SLOTS:
66
70
67 QCOMPARE(backend.icon(appId), expectedIcon);
71 QCOMPARE(backend.icon(appId), expectedIcon);
68 }
72 }
73+
74+ void testGetItem_data() {
75+ QTest::addColumn<QString>("appId");
76+ QTest::addColumn<bool>("exists");
77+
78+ QTest::newRow("Exists") << "rel-icon" << true;
79+ QTest::newRow("Doesn't Exist") << "does-not-exist" << false;
80+ }
81+
82+ void testGetItem() {
83+ QFETCH(QString, appId);
84+ QFETCH(bool, exists);
85+
86+ LauncherBackend backend;
87+ auto item = backend.getItem(appId);
88+
89+ if (exists) {
90+ QVERIFY(item != nullptr);
91+ } else {
92+ QVERIFY(item == nullptr);
93+ }
94+ }
95+
96+ void testCount_data() {
97+ QTest::addColumn<QString>("appId");
98+ QTest::addColumn<bool>("setCount");
99+ QTest::addColumn<int>("inCount");
100+ QTest::addColumn<bool>("countVisible");
101+ QTest::addColumn<int>("expectedCount");
102+
103+ /* Get baseline data on things working */
104+ QTest::newRow("Baseline") << "rel-icon" << false << 0 << false << -1;
105+
106+ /* Valid count, but not visible */
107+ QTest::newRow("Not visible") << "rel-icon" << true << 42 << false << -1;
108+
109+ /* Turn it on */
110+ QTest::newRow("Visible Count") << "rel-icon" << true << 42 << true << 42;
111+
112+ /* Invalide app to load */
113+ QTest::newRow("Invalid App ID") << "this-app-doesnt-exist" << true << 42 << true << -1;
114+ }
115+
116+ void testCount() {
117+ QFETCH(QString, appId);
118+ QFETCH(bool, setCount);
119+ QFETCH(int, inCount);
120+ QFETCH(bool, countVisible);
121+ QFETCH(int, expectedCount);
122+
123+ LauncherBackend backend;
124+
125+ if (setCount)
126+ backend.setCount(appId, inCount);
127+ backend.setCountVisible(appId, countVisible);
128+
129+ QCOMPARE(backend.count(appId), expectedCount);
130+ }
131+
132+ void testDbusName_data() {
133+ QTest::addColumn<QString>("decoded");
134+ QTest::addColumn<QString>("encoded");
135+
136+ /* Passthrough test */
137+ QTest::newRow("Passthrough") << "fine" << "fine";
138+
139+ /* Number as first characeter */
140+ QTest::newRow("Number first") << "31337" << "_331337";
141+
142+ /* Underscore test */
143+ QTest::newRow("Underscore test") << "this_is_c_style_namespacing" << "this_5Fis_5Fc_5Fstyle_5Fnamespacing";
144+
145+ /* Hyphen test */
146+ QTest::newRow("Hyphen test") << "typical-application" << "typical_2Dapplication";
147+
148+ /* Japanese test */
149+ QTest::newRow("日本語 test") << "日本語" << "_E6_97_A5_E6_9C_AC_E8_AA_9E";
150+ }
151+
152+ void testDbusName() {
153+ QFETCH(QString, decoded);
154+ QFETCH(QString, encoded);
155+
156+ QString encodeOut = LauncherBackend::encodeAppId(decoded);
157+ QCOMPARE(encoded, encodeOut);
158+
159+ QString decodeOut = LauncherBackend::decodeAppId(encoded);
160+ QCOMPARE(decoded, decodeOut);
161+ }
162+
163+ void testDbusIface_data() {
164+ QTest::addColumn<QString>("appId");
165+ QTest::addColumn<bool>("setCount");
166+ QTest::addColumn<int>("inCount");
167+ QTest::addColumn<bool>("countVisible");
168+ QTest::addColumn<int>("expectedCount");
169+
170+ /* Get baseline data on things working */
171+ QTest::newRow("Baseline") << "rel-icon" << false << 0 << false << -1;
172+
173+ /* Turn it on */
174+ QTest::newRow("Visible Count") << "rel-icon" << true << 42 << true << 42;
175+
176+ /* Invalide app to load */
177+ QTest::newRow("Invalid App ID") << "this-app-doesnt-exist" << true << 42 << true << -1;
178+ }
179+
180+ void testDbusIface() {
181+ QFETCH(QString, appId);
182+ QFETCH(bool, setCount);
183+ QFETCH(int, inCount);
184+ QFETCH(bool, countVisible);
185+ QFETCH(int, expectedCount);
186+
187+ QDBusConnection con = QDBusConnection::sessionBus();
188+ QDBusMessage message;
189+ QDBusMessage reply;
190+
191+ LauncherBackend backend;
192+
193+ if (setCount) {
194+ message = QDBusMessage::createMethodCall("com.canonical.Unity.Launcher",
195+ "/com/canonical/Unity/Launcher/" + LauncherBackend::encodeAppId(appId),
196+ "org.freedesktop.DBus.Properties",
197+ "Set");
198+ QVariantList cargs;
199+ cargs.append(QString("com.canonical.Unity.Launcher.Item"));
200+ cargs.append(QString("count"));
201+ cargs.append(QVariant::fromValue(QDBusVariant(inCount)));
202+
203+ message.setArguments(cargs);
204+ reply = con.call(message);
205+ QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);
206+ }
207+
208+ /* Set countVisible */
209+ message = QDBusMessage::createMethodCall("com.canonical.Unity.Launcher",
210+ "/com/canonical/Unity/Launcher/" + LauncherBackend::encodeAppId(appId),
211+ "org.freedesktop.DBus.Properties",
212+ "Set");
213+ QVariantList cvargs;
214+ cvargs.append(QString("com.canonical.Unity.Launcher.Item"));
215+ cvargs.append(QString("countVisible"));
216+ cvargs.append(QVariant::fromValue(QDBusVariant(countVisible)));
217+
218+ message.setArguments(cvargs);
219+ reply = con.call(message);
220+ QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);
221+
222+ /* Get value */
223+ message = QDBusMessage::createMethodCall("com.canonical.Unity.Launcher",
224+ "/com/canonical/Unity/Launcher/" + LauncherBackend::encodeAppId(appId),
225+ "org.freedesktop.DBus.Properties",
226+ "Get");
227+ QVariantList getargs;
228+ getargs.append(QString("com.canonical.Unity.Launcher.Item"));
229+ getargs.append(QString("count"));
230+
231+ message.setArguments(getargs);
232+ reply = con.call(message);
233+ QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);
234+ QCOMPARE(reply.arguments()[0].value<QDBusVariant>().variant().toInt(), expectedCount);
235+ }
69};
236};
70
237
71QTEST_GUILESS_MAIN(LauncherBackendTest)
238QTEST_GUILESS_MAIN(LauncherBackendTest)
tests/qmltests/CMakeLists.txt+4−3
@@ -32,12 +32,13 @@ add_qml_test(Components Revealer)
32add_qml_test(Components SeeMore)
32add_qml_test(Components SeeMore)
33add_qml_test(Components Showable)
33add_qml_test(Components Showable)
34add_qml_test(Components PageHeaderLabel)
34add_qml_test(Components PageHeaderLabel)
35+add_qml_test(Components ZoomableImage)
35add_qml_test(Dash Dash IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
36add_qml_test(Dash Dash IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
36add_qml_test(Dash DashContent IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
37add_qml_test(Dash DashContent IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
37−add_qml_test(Dash Card)
38+add_qml_test(Dash Card IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
38−add_qml_benchmark(Dash CardBenchmark 1000)
39+add_qml_benchmark(Dash CardBenchmark 1000 IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
39add_qml_test(Dash CardHeader)
40add_qml_test(Dash CardHeader)
40−add_qml_test(Dash CardTool)
41+add_qml_test(Dash CardTool IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
41add_qml_test(Dash GenericScopeView IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
42add_qml_test(Dash GenericScopeView IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
42add_qml_test(Dash/Apps RunningApplicationsGrid IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS}
43add_qml_test(Dash/Apps RunningApplicationsGrid IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS}
43 ${CMAKE_BINARY_DIR}/tests/mocks
44 ${CMAKE_BINARY_DIR}/tests/mocks
tests/qmltests/Components/tst_ZoomableImage.qmlnew file+192
@@ -0,0 +1,192 @@
1+/*
2+ * Copyright 2014 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 "../../../qml/Components"
20+import Unity.Test 0.1 as UT
21+
22+Rectangle {
23+ id: root
24+ width: units.gu(30)
25+ height: units.gu(60)
26+ color: "lightgrey"
27+
28+ property var widgetData0: {
29+ "source": "",
30+ "zoomable": false
31+ }
32+
33+ property var widgetData1: {
34+ "source": "../../../qml/graphics/phone_background.jpg",
35+ "zoomable": false
36+ }
37+
38+ property var widgetData2: {
39+ "source": "../../../qml/Dash/graphics/phone/screenshots/gallery@12.png",
40+ "zoomable": true
41+ }
42+
43+ ZoomableImage {
44+ id: zoomableImage
45+ width: parent.width
46+ anchors.fill: parent
47+ asynchronous: false
48+ }
49+
50+ SignalSpy {
51+ id: signalSpy
52+ }
53+
54+ UT.UnityTestCase {
55+ name: "ZoomableImageTest"
56+ when: windowShown
57+
58+ function test_loadImage() {
59+ var lazyImage = findChild(zoomableImage, "lazyImage");
60+
61+ zoomableImage.source = widgetData0["source"];
62+ zoomableImage.zoomable = widgetData0["zoomable"];
63+ waitForRendering(zoomableImage);
64+ tryCompare(zoomableImage, "imageState", "default");
65+
66+ signalSpy.signalName = "onStateChanged";
67+ signalSpy.target = lazyImage;
68+ signalSpy.clear();
69+
70+ zoomableImage.source = widgetData1["source"];
71+ zoomableImage.zoomable = widgetData1["zoomable"];
72+ waitForRendering(lazyImage);
73+ tryCompareFunction(function() { return get_filename(lazyImage.source.toString()) === get_filename(widgetData1["source"]); }, true);
74+ waitForRendering(zoomableImage);
75+ tryCompare(zoomableImage, "imageState", "ready");
76+ compare (signalSpy.count, 1);
77+ }
78+
79+ function get_filename(a) {
80+ var wordsA = a.split("/");
81+ var filenameA = wordsA[wordsA.length-1];
82+ return filenameA;
83+ }
84+
85+ function test_mousewheel() {
86+ var image = findChild(zoomableImage, "image");
87+ var lazyImage = findChild(zoomableImage, "lazyImage");
88+ var flickable = findChild(zoomableImage, "flickable");
89+
90+ zoomableImage.source = widgetData2["source"];
91+ zoomableImage.zoomable = true;
92+ waitForRendering(zoomableImage);
93+
94+ tryCompare(zoomableImage, "imageState", "ready");
95+ tryCompareFunction(function() { return get_filename(lazyImage.source.toString()) === get_filename(widgetData2["source"]); }, true);
96+ waitForRendering(image);
97+
98+ // move mouse to center
99+ mouseMove(zoomableImage, zoomableImage.width / 2, zoomableImage.height / 2);
100+
101+ // Test Zoom-in Zoom-out twice.
102+ for (var c=0; c<2; c++) {
103+ // zoom in
104+ for (var i=0; i<10; i++) {
105+ mouseWheel(zoomableImage, zoomableImage.width / 2, zoomableImage.height / 2, 0, 10);
106+ tryCompare(image, "scale", 1.0 + (i + 1) * 0.1);
107+ compare(flickable.contentWidth, lazyImage.width * image.scale);
108+ compare(flickable.contentHeight, lazyImage.height * image.scale);
109+ }
110+
111+ // zoom out
112+ for (var i=0; i<10; i++) {
113+ mouseWheel(zoomableImage, zoomableImage.width / 2, zoomableImage.height / 2, 0, -10);
114+ tryCompare(image, "scale", 2.0 - (i + 1) * 0.1);
115+ compare(flickable.contentWidth, lazyImage.width * image.scale);
116+ compare(flickable.contentHeight, lazyImage.height * image.scale);
117+ }
118+ }
119+ }
120+
121+ function test_pinch_data() {
122+ return [ { source:widgetData2["source"],
123+ zoomable:false,
124+ answer1: true,
125+ answer2: false,
126+ answer3: true,
127+ answer4: 1.0,
128+ answer5: 1.0 },
129+ { source:widgetData2["source"],
130+ zoomable:true,
131+ answer1: false,
132+ answer2: true,
133+ answer3: false,
134+ answer4: 1.7740461882048026,
135+ answer5: 1.0 }
136+ ]
137+ }
138+
139+ function test_pinch(data) {
140+ var image = findChild(zoomableImage, "image");
141+ var lazyImage = findChild(zoomableImage, "lazyImage");
142+ var flickable = findChild(zoomableImage, "flickable");
143+
144+ signalSpy.signalName = "onScaleChanged";
145+ signalSpy.target = image;
146+ signalSpy.clear();
147+
148+ zoomableImage.source = data.source;
149+ zoomableImage.zoomable = data.zoomable;
150+ waitForRendering(zoomableImage);
151+
152+ tryCompare(zoomableImage, "imageState", "ready");
153+ tryCompareFunction(function() { return get_filename(lazyImage.source.toString()) === get_filename(data.source); }, true);
154+ waitForRendering(image);
155+
156+ var x1Start = zoomableImage.width * 2 / 6;
157+ var y1Start = zoomableImage.height * 2 / 6;
158+ var x1End = zoomableImage.width * 1 / 6;
159+ var y1End = zoomableImage.height * 1 / 6;
160+ var x2Start = zoomableImage.width * 4 / 6;
161+ var y2Start = zoomableImage.height * 4 / 6;
162+ var x2End = zoomableImage.width * 5 / 6;
163+ var y2End = zoomableImage.height * 5 / 6;
164+
165+ var oldScale = image.scale;
166+
167+ // move mouse to center
168+ mouseMove(zoomableImage, zoomableImage.width / 2, zoomableImage.height / 2);
169+
170+ // Test Zoom-in Zoom-out twice.
171+ for (var c=0; c<2; c++) {
172+ wait(3000); // have to delay between two consequent pinch event.
173+ // pinch zoom-in
174+ touchPinch(zoomableImage, x1Start, y1Start, x1End, y1End, x2Start, y2Start, x2End, y2End);
175+
176+ tryCompare(image, "scale", data.answer4);
177+ var newScale = image.scale;
178+ compare(newScale == oldScale, data.answer1, "scale factor not equal: "+ oldScale + "=?" + newScale);
179+ compare(newScale > oldScale, data.answer2, "scale factor didn't changed");
180+ compare(signalSpy.count == 0, data.answer3, "scale signal count error");
181+ compare(newScale, data.answer4, "scale factor error");
182+ compare(flickable.contentWidth, lazyImage.width * image.scale);
183+ compare(flickable.contentHeight, lazyImage.height * image.scale);
184+
185+ wait(3000); // have to delay between two consequent pinch event.
186+ // pinch zoom-out
187+ touchPinch(zoomableImage, x1End, y1End, x1Start, y1Start, x2End, y2End, x2Start, y2Start);
188+ tryCompare(image, "scale", data.answer5);
189+ }
190+ }
191+ }
192+}
tests/qmltests/Dash/Previews/tst_Preview.qml+1−1
@@ -23,7 +23,7 @@ import Unity 0.2 as Unity
23Rectangle {
23Rectangle {
24 id: root
24 id: root
25 width: units.gu(60)
25 width: units.gu(60)
26− height: units.gu(80)
26+ height: units.gu(60)
27 color: Theme.palette.selected.background
27 color: Theme.palette.selected.background
28
28
29 Item {
29 Item {
tests/qmltests/Dash/Previews/tst_PreviewHeader.qml+66−4
@@ -24,6 +24,12 @@ Rectangle {
24 width: units.gu(60)
24 width: units.gu(60)
25 height: units.gu(80)
25 height: units.gu(80)
26
26
27+ property var origHeaderjson: {
28+ "title": "THE TITLE",
29+ "subtitle": "Something catchy",
30+ "mascot": "../graphics/play_button.png"
31+ }
32+
27 property var headerjson: {
33 property var headerjson: {
28 "title": "THE TITLE",
34 "title": "THE TITLE",
29 "subtitle": "Something catchy",
35 "subtitle": "Something catchy",
@@ -43,14 +49,70 @@ Rectangle {
43 }
49 }
44
50
45 UT.UnityTestCase {
51 UT.UnityTestCase {
52+ id: testCase
46 name: "PreviewHeaderTest"
53 name: "PreviewHeaderTest"
47 when: windowShown
54 when: windowShown
48
55
56+ property Item mascot: findChild(previewHeader, "mascotShape")
57+ property Item outerRow: findChild(previewHeader, "outerRow")
58+ property Item column: findChild(previewHeader, "column")
59+
60+ function initTestCase() {
61+ verify(typeof testCase.mascot === "object", "Couldn't find mascot object.");
62+ verify(typeof testCase.outerRow === "object", "Couldn't find outerRow object.");
63+ verify(typeof testCase.column === "object", "Couldn't find column object.");
64+
65+ headerjson.mascot = "";
66+ headerjson.title = "";
67+ headerjson.subtitle = "";
68+ previewHeader.widgetData = headerjson;
69+ }
70+
71+ function test_mascot_data() {
72+ return [
73+ { tag: "Empty", source: "", visible: false },
74+ { tag: "Invalid", source: "bad_path", visible: false },
75+ { tag: "Valid", source: "../graphics/play_button.png", visible: true },
76+ ]
77+ }
78+
79+ function test_mascot(data) {
80+ headerjson.mascot = data.source;
81+ previewHeader.widgetData = headerjson;
82+
83+ tryCompare(testCase.mascot, "visible", data.visible);
84+ }
85+
86+ function test_dimensions_data() {
87+ return [
88+ { tag: "Column width with mascot", object: column, width: previewHeader.width - mascot.width - outerRow.margins * 3, mascot: "artwork/avatar.png" },
89+ { tag: "Header height", object: previewHeader, height: function() { return outerRow.height + outerRow.margins * 2 } },
90+ ]
91+ }
92+
93+ function test_dimensions(data) {
94+ if (data.hasOwnProperty("mascot")) {
95+ headerjson.mascot = data.mascot;
96+ }
97+ previewHeader.widgetData = headerjson;
98+
99+ if (data.hasOwnProperty("width")) {
100+ tryCompare(data.object, "width", data.width);
101+ }
102+
103+ if (data.hasOwnProperty("height")) {
104+ tryCompareFunction(function() { return data.object.height === data.height() }, true);
105+ }
106+ }
107+
49 function test_json() {
108 function test_json() {
109+ headerjson = origHeaderjson;
110+ previewHeader.widgetData = headerjson;
111+
50− var cardHeader = findChild(previewHeader, "cardHeader");
112+ var innerPreviewHeader = findChild(previewHeader, "innerPreviewHeader");
51− compare(cardHeader.title, "THE TITLE");
113+ compare(innerPreviewHeader.title, "THE TITLE");
52− compare(cardHeader.subtitle, "Something catchy");
114+ compare(innerPreviewHeader.subtitle, "Something catchy");
53− compare(cardHeader.mascot.toString().slice(-24), "graphics/play_button.png");
115+ compare(innerPreviewHeader.mascot.toString().slice(-24), "graphics/play_button.png");
54 }
116 }
55 }
117 }
56}
118}
tests/qmltests/Dash/Previews/tst_PreviewTextSummary.qml+5−5
@@ -42,7 +42,7 @@ Rectangle {
42
42
43 PreviewTextSummary {
43 PreviewTextSummary {
44 id: previewTextSummary
44 id: previewTextSummary
45− anchors.fill: parent
45+ anchors { left: parent.left; right: parent.right }
46 widgetData: widgetDataComplete
46 widgetData: widgetDataComplete
47 }
47 }
48
48
@@ -51,6 +51,7 @@ Rectangle {
51 when: windowShown
51 when: windowShown
52
52
53 property var textLabel: findChild(previewTextSummary, "textLabel")
53 property var textLabel: findChild(previewTextSummary, "textLabel")
54+ property var titleLabel: findChild(previewTextSummary, "titleLabel")
54
55
55 function init() {
56 function init() {
56 verify(typeof textLabel === "object", "TextLabel object could not be found.")
57 verify(typeof textLabel === "object", "TextLabel object could not be found.")
@@ -61,16 +62,14 @@ Rectangle {
61 }
62 }
62
63
63 function test_optional_title() {
64 function test_optional_title() {
64− var titleLabel = findChild(previewTextSummary, "titleLabel")
65−
66 // verify titleLabel is visible and textLabel is anchored below it
65 // verify titleLabel is visible and textLabel is anchored below it
67 compare(titleLabel.visible, true)
66 compare(titleLabel.visible, true)
68− compare(textLabel.y, titleLabel.height)
67+ tryCompare(textLabel, "y", titleLabel.height)
69
68
70 // verify titleLabel disappears and textLabel moves up
69 // verify titleLabel disappears and textLabel moves up
71 previewTextSummary.widgetData = widgetDataNoTitle
70 previewTextSummary.widgetData = widgetDataNoTitle
72 compare(titleLabel.visible, false)
71 compare(titleLabel.visible, false)
73− compare(textLabel.y, 0)
72+ tryCompare(textLabel, "y", 0)
74 }
73 }
75
74
76 function test_see_more() {
75 function test_see_more() {
@@ -96,6 +95,7 @@ Rectangle {
96 verify(textLabel.lineCount <= textLabel.maximumCollapsedLineCount)
95 verify(textLabel.lineCount <= textLabel.maximumCollapsedLineCount)
97 compare(seeMore.visible, false)
96 compare(seeMore.visible, false)
98 tryCompare(textLabel, "height", textLabel.contentHeight)
97 tryCompare(textLabel, "height", textLabel.contentHeight)
98+ tryCompare(previewTextSummary, "height", titleLabel.height + textLabel.height)
99 }
99 }
100 }
100 }
101}
101}
tests/qmltests/Dash/Previews/tst_PreviewZoomableImage.qml+6−3
@@ -36,7 +36,8 @@ Rectangle {
36
36
37 PreviewZoomableImage {
37 PreviewZoomableImage {
38 id: zoomableImage
38 id: zoomableImage
39− width: parent.width
39+ anchors.fill: parent
40+ widgetData: widgetData1
40 }
41 }
41
42
42 UT.UnityTestCase {
43 UT.UnityTestCase {
@@ -47,10 +48,12 @@ Rectangle {
47 var image = findChild(zoomableImage, "image");
48 var image = findChild(zoomableImage, "image");
48
49
49 zoomableImage.widgetData = widgetData0;
50 zoomableImage.widgetData = widgetData0;
51+ waitForRendering(zoomableImage);
50− tryCompare(image, "state", "default");
52+ tryCompare(image, "imageState", "default");
51
53
52 zoomableImage.widgetData = widgetData1;
54 zoomableImage.widgetData = widgetData1;
55+ waitForRendering(zoomableImage);
53− tryCompare(image, "state", "ready");
56+ tryCompare(image, "imageState", "ready");
54 }
57 }
55 }
58 }
56}
59}
tests/qmltests/Dash/tst_Card.qml+78−92
@@ -29,8 +29,8 @@ Rectangle {
29
29
30 property string cardData: '
30 property string cardData: '
31 {
31 {
32− "art": "../../tests/qmltests/Dash/artwork/music-player-design.png",
32+ "art": "../../../tests/qmltests/Dash/artwork/music-player-design.png",
33− "mascot": "../../tests/qmltests/Dash/artwork/avatar.png",
33+ "mascot": "../../../tests/qmltests/Dash/artwork/avatar.png",
34 "title": "foo",
34 "title": "foo",
35 "subtitle": "bar",
35 "subtitle": "bar",
36 "summary": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
36 "summary": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
@@ -98,21 +98,26 @@ Rectangle {
98
98
99 CardTool {
99 CardTool {
100 id: cardTool
100 id: cardTool
101− template: card.template
101+ template: Helpers.update(JSON.parse(Helpers.defaultLayout), Helpers.tryParse(layoutArea.text, layoutError))['template'];
102− components: card.components
102+ components: Helpers.update(JSON.parse(Helpers.defaultLayout), Helpers.tryParse(layoutArea.text, layoutError))['components'];
103 viewWidth: units.gu(48)
103 viewWidth: units.gu(48)
104 }
104 }
105
105
106− Card {
106+ readonly property var card: loader.item
107− id: card
108− anchors { top: parent.top; left: parent.left; margins: units.gu(1) }
109
107
110− width: cardTool.cardWidth || implicitWidth
108+ Loader {
111− height: cardTool.cardHeight || implicitHeight
109+ id: loader
110+ anchors { top: parent.top; left: parent.left; margins: units.gu(1) }
112
111
113− template: Helpers.update(JSON.parse(Helpers.defaultLayout), Helpers.tryParse(layoutArea.text, layoutError))['template'];
112+ sourceComponent: cardTool.cardComponent
114− components: Helpers.update(JSON.parse(Helpers.defaultLayout), Helpers.tryParse(layoutArea.text, layoutError))['components'];
113+ onLoaded: {
114+ item.template = Qt.binding(function() { return cardTool.template; });
115+ item.components = Qt.binding(function() { return cardTool.components; });
115− cardData: Helpers.mapData(dataArea.text, components, dataError)
116+ item.cardData = Qt.binding(function() { return Helpers.mapData(dataArea.text, cardTool.components, dataError); });
117+ item.width = Qt.binding(function() { return cardTool.cardWidth || item.implicitWidth; });
118+ item.height = Qt.binding(function() { return cardTool.cardHeight || item.implicitHeight; });
119+ item.fixedHeaderHeight = Qt.binding(function() { return cardTool.headerHeight; });
120+ }
116 }
121 }
117
122
118 Rectangle {
123 Rectangle {
@@ -181,60 +186,45 @@ Rectangle {
181
186
182 when: windowShown
187 when: windowShown
183
188
184− property Item header: findChild(card, "cardHeader")
185− property Item headerLoader: findChild(card, "cardHeaderLoader")
186− property Item title: findChild(header, "titleLabel")
189+ property Item title: findChild(card, "titleLabel")
190+ property Item subtitle: findChild(card, "subtitleLabel")
191+ property var headerRow: findChild(card, "outerRow")
187− property Item art: findChild(card, "artShape")
192+ property var art: findChild(card, "artShape")
188 property Item artImage: findChild(card, "artImage")
193 property Item artImage: findChild(card, "artImage")
189 property Item summary: findChild(card, "summaryLabel")
194 property Item summary: findChild(card, "summaryLabel")
190 property Item background: findChild(card, "background")
195 property Item background: findChild(card, "background")
191 property Item backgroundLoader: findChild(card, "backgroundLoader")
196 property Item backgroundLoader: findChild(card, "backgroundLoader")
192 property Item backgroundImage: findChild(card, "backgroundImage")
197 property Item backgroundImage: findChild(card, "backgroundImage")
193−
198+ property Item mascotImage: findChild(card, "mascotImage");
194− function initTestCase() {
195− verify(typeof testCase.header === "object", "Couldn't find header object.");
196− verify(typeof testCase.art === "object", "Couldn't find art object.");
197− verify(typeof testCase.artImage === "object", "Couldn't find artImage object.");
198− verify(typeof testCase.summary === "object", "Couldn't find summary object.");
199− verify(typeof testCase.artImage === "object", "Couldn't find background object.");
200− verify(typeof testCase.summary === "object", "Couldn't find backgroundImage object.");
201− }
202
199
203 function cleanup() {
200 function cleanup() {
204 selector.selectedIndex = -1;
201 selector.selectedIndex = -1;
205 }
202 }
206
203
207−
208− function test_header_binding_data() {
209− return [
210− { tag: "Mascot", property: "mascot", value: Qt.resolvedUrl("artwork/avatar.png"), index: 0 },
211− { tag: "Title", property: "title", value: "foo", index: 0 },
212− { tag: "Subtitle", property: "subtitle", value: "bar", index: 0 },
213− ];
214− }
215−
216− function test_header_binding(data) {
217− selector.selectedIndex = data.index;
218− tryCompare(testCase.header, data.property, data.value);
219− }
220−
221 function test_card_binding_data() {
204 function test_card_binding_data() {
222 return [
205 return [
223− { tag: "Art", object: artImage, property: "source", value: Qt.resolvedUrl("artwork/music-player-design.png"), index: 0 },
206+ { tag: "Art", object: "artImage", property: "source", value: Qt.resolvedUrl("artwork/music-player-design.png"), index: 0 },
224− { tag: "Summary", object: summary, property: "text", field: "summary", index: 0 },
207+ { tag: "Summary", object: "summary", property: "text", field: "summary", index: 0 },
225− { tag: "Fit", object: art, fill: Image.PreserveAspectFit, index: 4 },
208+ { tag: "Fit", object: "art", fill: Image.PreserveAspectFit, index: 4 },
209+ { tag: "Mascot", object: "mascotImage", property: "source", value: Qt.resolvedUrl("artwork/avatar.png"), index: 0 },
210+ { tag: "Title", object: "title", property: "text", value: "foo", index: 0 },
211+ { tag: "Subtitle", object: "subtitle", property: "text", value: "bar", index: 0 },
226 ];
212 ];
227 }
213 }
228
214
229 function test_card_binding(data) {
215 function test_card_binding(data) {
230 selector.selectedIndex = data.index;
216 selector.selectedIndex = data.index;
217+ waitForRendering(card);
218+
219+ tryCompareFunction(function() { return testCase[data.object] !== null }, true);
220+ var object = testCase[data.object];
231
221
232 if (data.hasOwnProperty('value')) {
222 if (data.hasOwnProperty('value')) {
233− tryCompare(data.object, data.property, data.value);
223+ tryCompare(object, data.property, data.value);
234 }
224 }
235
225
236 if (data.hasOwnProperty('field')) {
226 if (data.hasOwnProperty('field')) {
237− tryCompare(data.object, data.property, card.cardData[data.field]);
227+ tryCompare(object, data.property, card.cardData[data.field]);
238 }
228 }
239 }
229 }
240
230
@@ -243,31 +233,21 @@ Rectangle {
243 { tag: "Medium", width: units.gu(18.5), index: 0 },
233 { tag: "Medium", width: units.gu(18.5), index: 0 },
244 { tag: "Small", width: units.gu(12), index: 1 },
234 { tag: "Small", width: units.gu(12), index: 1 },
245 { tag: "Large", width: units.gu(38), index: 2 },
235 { tag: "Large", width: units.gu(38), index: 2 },
246− { tag: "Wide", width: units.gu(18.5), aspect: 0.5, index: 0 },
236+ { tag: "Wide", width: units.gu(18.5), index: 0 },
247 { tag: "Horizontal", width: units.gu(38), index: 5 },
237 { tag: "Horizontal", width: units.gu(38), index: 5 },
248 // Make sure card ends with header when there's no summary
238 // Make sure card ends with header when there's no summary
249− { tag: "NoSummary", height: function() { return headerLoader.y + headerLoader.height }, index: 6 },
239+ { tag: "NoSummary", height: function() { var cardToolRow = findChild(cardTool, "outerRow");
240+ return cardToolRow.y + cardToolRow.height + units.gu(1) }, index: 6 },
250− { tag: "HorizontalNoSummary", height: function() { return headerLoader.height }, card_layout: "horizontal", index: 6 },
241+ { tag: "HorizontalNoSummary", height: function() { return headerRow.height + units.gu(2) }, card_layout: "horizontal", index: 6 },
251 ]
242 ]
252 }
243 }
253
244
254 function test_card_size(data) {
245 function test_card_size(data) {
255− waitForRendering(card);
256 selector.selectedIndex = data.index;
246 selector.selectedIndex = data.index;
257
247
258− if (data.hasOwnProperty("size")) {
259− card.template['card-size'] = data.size;
260− card.templateChanged();
261− }
262−
263 if (data.hasOwnProperty("card_layout")) {
248 if (data.hasOwnProperty("card_layout")) {
264− card.template['card-layout'] = data.card_layout;
249+ cardTool.template['card-layout'] = data.card_layout;
265− card.templateChanged();
250+ cardTool.templateChanged();
266− }
267−
268− if (data.hasOwnProperty("aspect")) {
269− card.components['art']['aspect-ratio'] = data.aspect;
270− card.componentsChanged();
271 }
251 }
272
252
273 if (data.hasOwnProperty("width")) {
253 if (data.hasOwnProperty("width")) {
@@ -288,25 +268,26 @@ Rectangle {
288 { tag: "Large", width: units.gu(38), index: 2 },
268 { tag: "Large", width: units.gu(38), index: 2 },
289 { tag: "Wide", height: units.gu(19), size: "large", index: 3 },
269 { tag: "Wide", height: units.gu(19), size: "large", index: 3 },
290 { tag: "Fit", height: units.gu(38), size: "large", width: units.gu(19), index: 4 },
270 { tag: "Fit", height: units.gu(38), size: "large", width: units.gu(19), index: 4 },
291− { tag: "VerticalWidth", width: function() { return header.width }, index: 0 },
271+ { tag: "VerticalWidth", width: function() { return headerRow.width + units.gu(1) * 2 }, index: 0 },
292− { tag: "HorizontalHeight", height: function() { return header.height }, index: 5 },
272+ { tag: "HorizontalHeight", height: function() { return headerRow.height + units.gu(1) * 2 }, index: 5 },
293− { tag: "HorizontalWidth", width: function() { return headerLoader.x }, index: 5 },
273+ { tag: "HorizontalWidth", width: function() { return headerRow.x - units.gu(1) }, index: 5 },
294 ]
274 ]
295 }
275 }
296
276
297 function test_art_size(data) {
277 function test_art_size(data) {
298 selector.selectedIndex = data.index;
278 selector.selectedIndex = data.index;
299−
300 if (data.hasOwnProperty("size")) {
279 if (data.hasOwnProperty("size")) {
301− card.template['card-size'] = data.size;
280+ cardTool.template['card-size'] = data.size;
302− card.templateChanged();
281+ cardTool.templateChanged();
303 }
282 }
304
283
305 if (data.hasOwnProperty("aspect")) {
284 if (data.hasOwnProperty("aspect")) {
306− card.components['art']['aspect-ratio'] = data.aspect;
285+ cardTool.components['art']['aspect-ratio'] = data.aspect;
307− card.componentsChanged();
286+ cardTool.componentsChanged();
308 }
287 }
309
288
289+ waitForRendering(card);
290+
310 if (data.hasOwnProperty("width")) {
291 if (data.hasOwnProperty("width")) {
311 if (typeof data.width === "function") {
292 if (typeof data.width === "function") {
312 tryCompareFunction(function() { return art.width === data.width() }, true);
293 tryCompareFunction(function() { return art.width === data.width() }, true);
@@ -326,38 +307,40 @@ Rectangle {
326
307
327 function test_art_layout_data() {
308 function test_art_layout_data() {
328 return [
309 return [
329− { tag: "Vertical", left: function() { return 0 }, index: 0},
310+ { tag: "Vertical", left: function() { return units.gu(1); }, index: 0},
330− { tag: "Horizontal", left: function() { return art.width }, index: 5 },
311+ { tag: "Horizontal", left: function() { return art.width + units.gu(1); }, index: 5 },
331 ];
312 ];
332 }
313 }
333
314
334 function test_art_layout(data) {
315 function test_art_layout(data) {
335 selector.selectedIndex = data.index;
316 selector.selectedIndex = data.index;
317+ waitForRendering(card);
336
318
337− tryCompare(testCase.headerLoader, "x", data.left());
319+ tryCompare(headerRow, "x", data.left());
338 }
320 }
339
321
340 function test_header_layout_data() {
322 function test_header_layout_data() {
341 return [
323 return [
342− { tag: "Vertical", top: function() { return art.y + art.height },
324+ { tag: "Vertical", top: function() { return art.y + art.height + units.gu(1) },
343− left: function() { return art.x }, index: 0 },
325+ left: function() { return art.x + units.gu(1) }, index: 0 },
344− { tag: "Horizontal", top: function() { return art.y },
326+ { tag: "Horizontal", top: function() { return art.y + units.gu(1) },
345− left: function() { return art.x + art.width }, index: 5 },
327+ left: function() { return art.x + art.width + units.gu(1) }, index: 5 },
346− { tag: "Overlay", top: function() { return art.y + art.height - header.height },
328+ { tag: "Overlay", top: function() { return art.y + art.height - headerRow.height - units.gu(1) },
347− left: function() { return art.x }, index: 9 },
329+ left: function() { return art.x + units.gu(1) }, index: 9 },
348 ]
330 ]
349 }
331 }
350
332
351 function test_header_layout(data) {
333 function test_header_layout(data) {
352 selector.selectedIndex = data.index;
334 selector.selectedIndex = data.index;
335+ waitForRendering(card);
353
336
354− tryCompareFunction(function() { return testCase.headerLoader.y === data.top() }, true);
337+ tryCompareFunction(function() { return testCase.headerRow.y === data.top() }, true);
355− tryCompareFunction(function() { return testCase.headerLoader.x === data.left() }, true);
338+ tryCompareFunction(function() { return testCase.headerRow.x === data.left() }, true);
356 }
339 }
357
340
358 function test_summary_layout_data() {
341 function test_summary_layout_data() {
359 return [
342 return [
360− { tag: "With header", top: function() { return headerLoader.y + headerLoader.height }, index: 0 },
343+ { tag: "With header", top: function() { return headerRow.y + headerRow.height + units.gu(1); }, index: 0 },
361 { tag: "Without header", top: function() { return art.y + art.height }, index: 7 },
344 { tag: "Without header", top: function() { return art.y + art.height }, index: 7 },
362 ]
345 ]
363 }
346 }
@@ -365,16 +348,16 @@ Rectangle {
365 function test_summary_layout(data) {
348 function test_summary_layout(data) {
366 selector.selectedIndex = data.index;
349 selector.selectedIndex = data.index;
367
350
351+ waitForRendering(card);
352+
368 tryCompareFunction(function() { return testCase.summary.y === data.top() }, true);
353 tryCompareFunction(function() { return testCase.summary.y === data.top() }, true);
369 }
354 }
370
355
371 function test_art_visibility() {
356 function test_art_visibility() {
372 selector.selectedIndex = 8;
357 selector.selectedIndex = 8;
373
358
374− tryCompare(testCase.artImage, "source", "");
359+ compare(testCase.artImage, null);
375− compare(testCase.art.visible, false);
360+ compare(testCase.art, null);
376− compare(testCase.art.height, 0);
377− compare(testCase.art.width, 0);
378 }
361 }
379
362
380 function test_background_data() {
363 function test_background_data() {
@@ -402,7 +385,11 @@ Rectangle {
402
385
403 waitForRendering(card);
386 waitForRendering(card);
404
387
405− tryCompare(backgroundLoader, "active", data.visible);
388+ if (data.visible) {
389+ tryCompare(backgroundLoader, "active", true);
390+ } else {
391+ compare(backgroundLoader, null);
392+ }
406
393
407 if (data.hasOwnProperty("color")) {
394 if (data.hasOwnProperty("color")) {
408 tryCompare(background, "color", data.color);
395 tryCompare(background, "color", data.color);
@@ -449,13 +436,15 @@ Rectangle {
449
436
450 function test_fontColor(data) {
437 function test_fontColor(data) {
451 selector.selectedIndex = 10;
438 selector.selectedIndex = 10;
439+ waitForRendering(card);
452
440
453 background.color = data.tag;
441 background.color = data.tag;
454
442
455 var fontColor = data.dark ? "grey" : "white";
443 var fontColor = data.dark ? "grey" : "white";
456
444
457 tryCompareFunction(function() { return Qt.colorEqual(summary.color, fontColor); }, true);
445 tryCompareFunction(function() { return Qt.colorEqual(summary.color, fontColor); }, true);
458− tryCompareFunction(function() { return Qt.colorEqual(header.fontColor, fontColor); }, true);
446+ tryCompareFunction(function() { return Qt.colorEqual(title.color, fontColor); }, true);
447+ tryCompareFunction(function() { return Qt.colorEqual(subtitle.color, fontColor); }, true);
459 }
448 }
460
449
461 function test_mascotShape_data() {
450 function test_mascotShape_data() {
@@ -468,15 +457,12 @@ Rectangle {
468
457
469 function test_mascotShape(data) {
458 function test_mascotShape(data) {
470 selector.selectedIndex = data.index;
459 selector.selectedIndex = data.index;
460+ waitForRendering(card);
471
461
472 var shape = findChild(card, "mascotShapeLoader");
462 var shape = findChild(card, "mascotShapeLoader");
473− var image = findChild(card, "mascotImage");
474−
475− verify(shape, "Could not find shape.");
476− verify(image, "Could not find image.");
477
463
478− tryCompare(shape, "active", data.shape);
464+ compare(shape !== null, data.shape);
479− tryCompare(image, "visible", !data.shape);
465+ tryCompare(mascotImage, "visible", !data.shape);
480 }
466 }
481 }
467 }
482}
468}
tests/qmltests/Dash/tst_CardBenchmark.qml+10−7
@@ -54,13 +54,16 @@ Rectangle {
54 Repeater {
54 Repeater {
55 id: cardRepeater
55 id: cardRepeater
56 model: 0
56 model: 0
57− Card {
57+ Loader {
58+ sourceComponent: cardTool.cardComponent
59+ onLoaded: {
60+ item.objectName = "delegate" + index;
58− width: cardTool.cardWidth || implicitWidth
61+ item.width = Qt.binding(function() { return cardTool.cardWidth || implicitWidth; });
59− height: cardTool.cardHeight || implicitHeight
62+ item.height = Qt.binding(function() { return cardTool.cardHeight || implicitHeight; });
60−
61− template: cardTool.template
62− components: cardTool.components
63− cardData: Helpers.mapData(root.cardData, components)
63+ item.cardData = Qt.binding(function() { return Helpers.mapData(root.cardData, cardTool.components); });
64+ item.template = Qt.binding(function() { return cardTool.template; });
65+ item.components = Qt.binding(function() { return cardTool.components; });
66+ }
64 }
67 }
65 }
68 }
66
69
tests/qmltests/Dash/tst_CardHeader.qmldeleted−116
@@ -1,116 +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 QtTest 1.0
19−import Ubuntu.Components 0.1
20−import Unity.Test 0.1 as UT
21−import "../../../qml/Dash"
22−
23−
24−Rectangle {
25− width: units.gu(40)
26− height: units.gu(72)
27− color: "lightgrey"
28−
29− CardHeader {
30− id: cardHeader
31− anchors { left: parent.left; right: parent.right }
32− }
33−
34− Rectangle {
35− anchors.fill: cardHeader
36− color: "lightblue"
37− opacity: 0.5
38− }
39−
40− UT.UnityTestCase {
41− id: testCase
42− name: "CardHeader"
43−
44− when: windowShown
45−
46− property Item mascot: findChild(cardHeader, "mascotShapeLoader")
47− property Item titleLabel: findChild(cardHeader, "titleLabel")
48− property Item subtitleLabel: findChild(cardHeader, "subtitleLabel")
49− property Item oldPriceLabel: findChild(cardHeader, "oldPriceLabel")
50− property Item outerRow: findChild(cardHeader, "outerRow")
51− property Item column: findChild(cardHeader, "column")
52−
53− function initTestCase() {
54− verify(typeof testCase.mascot === "object", "Couldn't find mascot object.");
55− verify(typeof testCase.titleLabel === "object", "Couldn't find titleLabel object.");
56− verify(typeof testCase.subtitleLabel === "object", "Couldn't find subtitleLabel object.");
57− verify(typeof testCase.oldPriceLabel === "object", "Couldn't find oldPriceLabel object.");
58− }
59−
60− function cleanup() {
61− cardHeader.mascot = "";
62− cardHeader.title = "";
63− cardHeader.subtitle = "";
64− }
65−
66− function test_mascot_data() {
67− return [
68− { tag: "Empty", source: "", visible: false },
69− { tag: "Invalid", source: "bad_path", visible: false },
70− { tag: "Valid", source: Qt.resolvedUrl("artwork/avatar.png"), visible: true },
71− ]
72− }
73−
74− function test_mascot(data) {
75− cardHeader.mascot = data.source;
76− tryCompare(testCase.mascot, "visible", data.visible);
77− }
78−
79− function test_labels_data() {
80− return [
81− { tag: "Empty", visible: false },
82− { tag: "Title only", title: "Foo", visible: true },
83− { tag: "Subtitle only", subtitle: "Bar", visible: false },
84− { tag: "Both", title: "Foo", subtitle: "Bar", visible: true },
85− ]
86− }
87−
88− function test_labels(data) {
89− cardHeader.title = data.title !== undefined ? data.title : "";
90− cardHeader.subtitle = data.subtitle !== undefined ? data.subtitle : "";
91− tryCompare(cardHeader, "visible", data.visible);
92− }
93−
94− function test_dimensions_data() {
95− return [
96− { tag: "Column width", object: column, width: cardHeader.width },
97− { tag: "Column width with mascot", object: column, width: cardHeader.width - mascot.width - outerRow.margins * 3, mascot: "artwork/avatar.png" },
98− { tag: "Header height", object: cardHeader, height: function() { return outerRow.height + outerRow.margins * 2 } },
99− ]
100− }
101−
102− function test_dimensions(data) {
103− if (data.hasOwnProperty("mascot")) {
104− cardHeader.mascot = data.mascot;
105− }
106−
107− if (data.hasOwnProperty("width")) {
108− tryCompare(data.object, "width", data.width);
109− }
110−
111− if (data.hasOwnProperty("height")) {
112− tryCompareFunction(function() { return data.object.height === data.height() }, true);
113− }
114− }
115− }
116−}
tests/qmltests/Dash/tst_CardTool.qml+11−31
@@ -127,26 +127,6 @@ Rectangle {
127 }
127 }
128 }
128 }
129 }
129 }
130−
131− Card {
132− id: card
133− template: cardTool.template;
134− components: cardTool.components;
135− cardData: Helpers.mapData(dataArea.text, components, dataError)
136−
137− width: cardTool.cardWidth || implicitWidth
138− height: cardTool.cardHeight || implicitHeight
139−
140− clip: true
141− headerAlignment: cardTool.headerAlignment
142−
143− Rectangle {
144− anchors.fill: parent
145− color: "transparent"
146− border.width: 1
147− border.color: "green"
148− }
149− }
150 }
130 }
151
131
152 Rectangle {
132 Rectangle {
@@ -257,7 +237,7 @@ Rectangle {
257 id: testCase
237 id: testCase
258 name: "Card"
238 name: "Card"
259
239
260− property Card internalCard: findChild(cardTool, "cardToolCard")
240+ property var internalCard: findChild(cardTool, "cardToolCard")
261
241
262 when: windowShown
242 when: windowShown
263
243
@@ -272,16 +252,16 @@ Rectangle {
272
252
273 function test_card_size_data() {
253 function test_card_size_data() {
274 return [
254 return [
275− { tag: "Medium", width: units.gu(18.5), height: function() { return card.height }, index: 0 },
255+ { tag: "Medium", width: units.gu(18.5), height: function() { return internalCard ? internalCard.height : 0 }, index: 0 },
276− { tag: "No art", width: units.gu(18.5), height: function() { return card.height }, index: 1 },
256+ { tag: "No art", width: units.gu(18.5), height: function() { return internalCard ? internalCard.height : 0 }, index: 1 },
277− { tag: "No summary", width: units.gu(18.5), height: function() { return card.height }, index: 2 },
257+ { tag: "No summary", width: units.gu(18.5), height: function() { return internalCard ? internalCard.height : 0 }, index: 2 },
278− { tag: "Just header", width: units.gu(18.5), height: function() { return card.height }, index: 3 },
258+ { tag: "Just header", width: units.gu(18.5), height: function() { return internalCard ? internalCard.height : 0 }, index: 3 },
279− { tag: "Just title", width: units.gu(18.5), height: function() { return card.height }, index: 4 },
259+ { tag: "Just title", width: units.gu(18.5), height: function() { return internalCard ? internalCard.height : 0 }, index: 4 },
280− { tag: "Title and subtitle", width: units.gu(18.5), height: function() { return card.height }, index: 5 },
260+ { tag: "Title and subtitle", width: units.gu(18.5), height: function() { return internalCard ? internalCard.height : 0 }, index: 5 },
281− { tag: "Title and mascot", width: units.gu(18.5), height: function() { return card.height }, index: 6 },
261+ { tag: "Title and mascot", width: units.gu(18.5), height: function() { return internalCard ? internalCard.height : 0 }, index: 6 },
282− { tag: "Small", width: units.gu(12), height: function() { return card.height }, index: 7 },
262+ { tag: "Small", width: units.gu(12), height: function() { return internalCard ? internalCard.height : 0 }, index: 7 },
283− { tag: "Large", width: units.gu(38), height: function() { return card.height }, index: 8 },
263+ { tag: "Large", width: units.gu(38), height: function() { return internalCard ? internalCard.height : 0 }, index: 8 },
284− { tag: "Horizontal", width: units.gu(38), height: function() { return card.height }, index: 9 },
264+ { tag: "Horizontal", width: units.gu(38), height: function() { return internalCard ? internalCard.height : 0 }, index: 9 },
285 { tag: "OrganicGrid", width: undefined, height: undefined, index: 0, layout_index: 1},
265 { tag: "OrganicGrid", width: undefined, height: undefined, index: 0, layout_index: 1},
286 { tag: "Journal", width: undefined, height: units.gu(20), size: 20, index: 0, layout_index: 2 },
266 { tag: "Journal", width: undefined, height: units.gu(20), size: 20, index: 0, layout_index: 2 },
287 { tag: "OversizedJournal", width: undefined, height: units.gu(18.5), size: 40, index: 0, layout_index: 2 },
267 { tag: "OversizedJournal", width: undefined, height: units.gu(18.5), size: 40, index: 0, layout_index: 2 },
tests/utils/modules/Unity/Test/UnityTestCase.qml+26
@@ -260,6 +260,32 @@ TestCase {
260 }
260 }
261 }
261 }
262
262
263+ function touchPinch(item, x1Start, y1Start, x1End, y1End, x2Start, y2Start, x2End, y2End) {
264+ // Make sure the item is rendered
265+ waitForRendering(item);
266+
267+ var event1 = touchEvent();
268+ // first finger
269+ event1.press(0, x1Start, y1Start);
270+ event1.commit();
271+ // second finger
272+ event1.stationary(0);
273+ event1.press(1, x2Start, y2Start);
274+ event1.commit();
275+
276+ // pinch
277+ for (var i = 0.0; i < 1.0; i += 0.02) {
278+ event1.move(0, x1Start + (x1End - x1Start) * i, y1Start + (y1End - y1Start) * i);
279+ event1.move(1, x2Start + (x2End - x2Start) * i, y2Start + (y2End - y2Start) * i);
280+ event1.commit();
281+ }
282+
283+ // release
284+ event1.release(0, x1End, y1End);
285+ event1.release(1, x2End, y2End);
286+ event1.commit();
287+ }
288+
263 function fetchRootItem(item) {
289 function fetchRootItem(item) {
264 if (item.parent)
290 if (item.parent)
265 return fetchRootItem(item.parent)
291 return fetchRootItem(item.parent)