on xenial help sign in
Merge upstream
712f254Ying-Chun Liu
CMakeLists.txt+1
@@ -96,6 +96,7 @@ include(autopilot)
96declare_autopilot_test(shell unity8.shell ${CMAKE_SOURCE_DIR}/tests/autopilot/)
96declare_autopilot_test(shell unity8.shell ${CMAKE_SOURCE_DIR}/tests/autopilot/)
97
97
98set(SHELL_APP unity8)
98set(SHELL_APP unity8)
99+set(DASH_APP unity8-dash)
99set(SCOPE_TOOL unity-scope-tool)
100set(SCOPE_TOOL unity-scope-tool)
100
101
101include_directories(
102include_directories(
cmake/modules/QmlTest.cmake+2−2
@@ -135,7 +135,7 @@ macro(add_binary_qml_test CLASS_NAME LD_PATH DEPS)
135 set(testCommand
135 set(testCommand
136 LD_LIBRARY_PATH=${LD_PATH}
136 LD_LIBRARY_PATH=${LD_PATH}
137 ${CMAKE_CURRENT_BINARY_DIR}/${CLASS_NAME}TestExec
137 ${CMAKE_CURRENT_BINARY_DIR}/${CLASS_NAME}TestExec
138− -o ${CMAKE_BINARY_DIR}/${CLASS_NAME}Test.xml,xunitxml
138+ -o ${CMAKE_BINARY_DIR}/test${CLASS_NAME}.xml,xunitxml
139 -o -,txt)
139 -o -,txt)
140
140
141 add_qmltest_target(test${CLASS_NAME} "${testCommand}" FALSE TRUE)
141 add_qmltest_target(test${CLASS_NAME} "${testCommand}" FALSE TRUE)
@@ -151,7 +151,7 @@ macro(add_binary_qml_test CLASS_NAME LD_PATH DEPS)
151 LD_LIBRARY_PATH=${LD_PATH}
151 LD_LIBRARY_PATH=${LD_PATH}
152 xvfb-run --server-args "-screen 0 1024x768x24" --auto-servernum
152 xvfb-run --server-args "-screen 0 1024x768x24" --auto-servernum
153 ${CMAKE_CURRENT_BINARY_DIR}/${CLASS_NAME}TestExec
153 ${CMAKE_CURRENT_BINARY_DIR}/${CLASS_NAME}TestExec
154− -o ${CMAKE_BINARY_DIR}/${CLASS_NAME}Test.xml,xunitxml
154+ -o ${CMAKE_BINARY_DIR}/test${CLASS_NAME}.xml,xunitxml
155 -o -,txt)
155 -o -,txt)
156
156
157 add_qmltest_target(xvfbtest${CLASS_NAME} "${xvfbtestCommand}" FALSE TRUE)
157 add_qmltest_target(xvfbtest${CLASS_NAME} "${xvfbtestCommand}" FALSE TRUE)
data/CMakeLists.txt+5−2
@@ -1,7 +1,10 @@
1−# generate desktop file
1+# generate desktop files
2configure_file(${SHELL_APP}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop @ONLY)
2configure_file(${SHELL_APP}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop @ONLY)
3+configure_file(${DASH_APP}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${DASH_APP}.desktop @ONLY)
3
4
4# install desktop files
5# install desktop files
6+install(FILES
5−install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop
7+ ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop
8+ ${CMAKE_CURRENT_BINARY_DIR}/${DASH_APP}.desktop
6 DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
9 DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
7 )
10 )
data/unity8-dash.confnew file+22
@@ -0,0 +1,22 @@
1+description "Unity Shell v8 Dash"
2+author "Michael Zanetti <michael.zanetti@canonical.com>"
3+
4+emits scope-ui-starting
5+
6+start on started unity8
7+stop on stopping unity8
8+
9+kill timeout 120
10+
11+respawn
12+
13+pre-start script
14+ if [ -z "$UNITY_SCOPES_LIST" ]; then
15+ # FIXME: remove once we have this in dconf
16+ initctl set-env UNITY_SCOPES_LIST="scopes;clickscope;musicaggregator;videoaggregator"
17+ fi
18+
19+ initctl emit scope-ui-starting
20+end script
21+
22+exec ${BINARY:-unity8-dash} $ARGS --desktop_file_hint=/usr/share/applications/unity8-dash.desktop
data/unity8-dash.desktop.innew file+9
@@ -0,0 +1,9 @@
1+[Desktop Entry]
2+Type=Application
3+Name=Unity 8 Dash
4+Comment=The converged Unity shell dash
5+Exec=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_BINDIR@/unity8-dash
6+Terminal=false
7+Icon=unity8
8+NoDisplay=true
9+X-Ubuntu-Touch=true
data/unity8.conf+1−7
@@ -1,7 +1,7 @@
1description "Unity Shell v8"
1description "Unity Shell v8"
2author "Ricardo Mendoza <ricmm@ubuntu.com>"
2author "Ricardo Mendoza <ricmm@ubuntu.com>"
3
3
4−emits scope-ui-starting indicator-services-start
4+emits indicator-services-start
5
5
6start on ((xsession SESSION=ubuntu-touch) or (xsession SESSION=ubuntu-touch-surfaceflinger)) and started dbus
6start on ((xsession SESSION=ubuntu-touch) or (xsession SESSION=ubuntu-touch-surfaceflinger)) and started dbus
7stop on desktop-end
7stop on desktop-end
@@ -34,11 +34,6 @@ pre-start script
34 gdbus call --session --dest org.freedesktop.DBus --object-path /org/freedesktop/DBus --method org.freedesktop.DBus.UpdateActivationEnvironment "@a{ss} {'MIR_SOCKET': '$MIR_SERVER_FILE'}"
34 gdbus call --session --dest org.freedesktop.DBus --object-path /org/freedesktop/DBus --method org.freedesktop.DBus.UpdateActivationEnvironment "@a{ss} {'MIR_SOCKET': '$MIR_SERVER_FILE'}"
35 fi
35 fi
36
36
37− if [ -z "$UNITY_SCOPES_LIST" ]; then
38− # FIXME: remove once we have this in dconf
39− initctl set-env UNITY_SCOPES_LIST="scopes;clickscope;musicaggregator;videoaggregator"
40− fi
41−
42 # Remove the socket if still there
37 # Remove the socket if still there
43 if [ -S "$MIR_SERVER_FILE" ]; then
38 if [ -S "$MIR_SERVER_FILE" ]; then
44 rm "$MIR_SERVER_FILE"
39 rm "$MIR_SERVER_FILE"
@@ -46,7 +41,6 @@ pre-start script
46
41
47 initctl set-env --global MIR_SERVER_PROMPT_FILE=1
42 initctl set-env --global MIR_SERVER_PROMPT_FILE=1
48
43
49− initctl emit scope-ui-starting
50 initctl emit --no-wait indicator-services-start
44 initctl emit --no-wait indicator-services-start
51end script
45end script
52
46
debian/changelog+82
@@ -1,3 +1,85 @@
1+unity8 (8.00+14.10.20140808-0ubuntu1) utopic; urgency=low
2+
3+ [ CI bot ]
4+ * Resync trunk
5+
6+ [ Nick Dedekind ]
7+ * Added application prompt surfaces to allow prompting application
8+ which have not yet created a surface.
9+
10+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Fri, 08 Aug 2014 12:15:05 +0000
11+
12+unity8 (8.00+14.10.20140806.1-0ubuntu1) utopic; urgency=low
13+
14+ [ Michal Hruby ]
15+ * Work with the scopes-v4 branch + departments->navigation renaming
16+
17+ [ Michał Sawicz ]
18+ * Hardcode art shape size for click scope local and predefined
19+ categories While at it, drop the fillmode of cards
20+ * Use the correct API in PageHeader. (LP: #1353048)
21+ * Refactor dash activity indicator. (LP: #1351539)
22+
23+ [ Albert Astals ]
24+ * Dash Departments fixes Update maxHeight manually since it depends on
25+ the position of the item and its parents and it can't know when the
26+ binding has to be updated Make parent stuff non interactive when the
27+ department list is shown
28+ * PageHeader: when on search clip y-coordinates otherwise the
29+ background spills out when on search (LP: #1350398)
30+ * Dash: Implement OverlayColor support in Cards
31+ * Hardcode art shape size for click scope local and predefined
32+ categories While at it, drop the fillmode of cards
33+ * Make test_departments test more stable There's various
34+ DashDepartments on the dash, make sure we're working over the one
35+ that is on screen, otherwise clicks don't end up where they should
36+ * Work with the scopes-v4 branch + departments->navigation renaming
37+ * Fixes for dash as app Load i18n catalog Process command line options
38+ Add the posibility to have a mouse touch adaptor (LP: #1353351)
39+ * Implement the Expandable Preview Widget Now TextSummary is not
40+ expandable by itself anymore, you have to use it inside an
41+ Expandable to get the behaviour
42+ * Add test prefix to xml output, seems CI needs it
43+
44+ [ Antti Kaijanmäki ]
45+ * Indicators: Adds new ModemInfoItem to be used with indicator-network
46+ (LP: #1329204)
47+
48+ [ Michael Terry ]
49+ * When the edge demo is running, don't show the greeter if the screen
50+ is turned off. This avoids an odd interaction where parts of the
51+ greeter are disabled but the edge demo isn't visible until you slide
52+ the greeter away. (LP: #1283425)
53+ * Don't hardcode the phablet password in our testing script.
54+
55+ [ Ying-Chun Liu ]
56+ * Add divider dots.
57+
58+ [ Mirco Müller ]
59+ * Make sure the TextField of a snap-decision notification has the
60+ active focus upon creation, thus the osk shows up right away. (LP:
61+ #1346867)
62+
63+ [ Andrea Cimitan ]
64+ * Add touchdown effect to dash cards.
65+ * Import Ubuntu.Components for preview image gallery to pick up
66+ default flicking speeds.
67+
68+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 06 Aug 2014 19:40:05 +0000
69+
70+unity8 (8.00+14.10.20140805-0ubuntu1) utopic; urgency=low
71+
72+ [ Michael Zanetti ]
73+ * Split the dash from the shell into a separate app (LP: #1232687)
74+
75+ [ Leo Arias ]
76+ * Update the autopilot tests to work with the new dash app.
77+
78+ [ Daniel d'Andrada ]
79+ * Split the dash from the shell into a separate app (LP: #1232687)
80+
81+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 05 Aug 2014 12:06:31 +0000
82+
1unity8 (8.00+14.10.20140731.1-0ubuntu1) utopic; urgency=low
83unity8 (8.00+14.10.20140731.1-0ubuntu1) utopic; urgency=low
2
84
3 [ Gerry Boland ]
85 [ Gerry Boland ]
debian/control+3−3
@@ -24,7 +24,7 @@ Build-Depends: cmake,
24 libpulse-dev,
24 libpulse-dev,
25 libqmenumodel-dev (>= 0.2.8),
25 libqmenumodel-dev (>= 0.2.8),
26 libqt5xmlpatterns5-dev,
26 libqt5xmlpatterns5-dev,
27− libunity-api-dev (>= 7.87),
27+ libunity-api-dev (>= 7.88),
28 libusermetricsoutput1-dev,
28 libusermetricsoutput1-dev,
29 libxcb1-dev,
29 libxcb1-dev,
30 pkg-config,
30 pkg-config,
@@ -83,7 +83,7 @@ Depends: gsettings-desktop-schemas,
83 qmenumodel-qml (>= 0.2.8),
83 qmenumodel-qml (>= 0.2.8),
84 qml-module-qtquick-xmllistmodel,
84 qml-module-qtquick-xmllistmodel,
85 qtdeclarative5-gsettings1.0,
85 qtdeclarative5-gsettings1.0,
86− qtdeclarative5-qtmir-plugin (>= 0.4),
86+ qtdeclarative5-qtmir-plugin (>= 0.4.1),
87 qtdeclarative5-ubuntu-settings-components (>= 0.3),
87 qtdeclarative5-ubuntu-settings-components (>= 0.3),
88 qtdeclarative5-ubuntu-telephony0.1,
88 qtdeclarative5-ubuntu-telephony0.1,
89 unity-launcher-impl-3,
89 unity-launcher-impl-3,
@@ -112,7 +112,7 @@ Depends: qtdeclarative5-ubuntu-thumbnailer0.1 | ubuntu-thumbnailer-impl,
112 unity-application-impl-2,
112 unity-application-impl-2,
113 unity-notifications-impl-3,
113 unity-notifications-impl-3,
114 unity-plugin-scopes | unity-scopes-impl,
114 unity-plugin-scopes | unity-scopes-impl,
115− unity-scopes-impl-2,
115+ unity-scopes-impl-4,
116 unity8-fake-env | unity-application-impl,
116 unity8-fake-env | unity-application-impl,
117 ${misc:Depends},
117 ${misc:Depends},
118Breaks: unity8 (<< 7.86),
118Breaks: unity8 (<< 7.86),
debian/unity8.install+3
@@ -1,6 +1,9 @@
1data/unity8.conf usr/share/upstart/sessions/
1data/unity8.conf usr/share/upstart/sessions/
2+data/unity8-dash.conf usr/share/upstart/sessions/
2usr/bin/unity8
3usr/bin/unity8
4+usr/bin/unity8-dash
3usr/share/applications/unity8.desktop
5usr/share/applications/unity8.desktop
6+usr/share/applications/unity8-dash.desktop
4usr/share/unity8/Greeter
7usr/share/unity8/Greeter
5usr/share/unity8/Hud
8usr/share/unity8/Hud
6usr/share/unity8/Launcher
9usr/share/unity8/Launcher
plugins/Dash/CardCreator.js+26−12
@@ -71,19 +71,14 @@ var kArtShapeHolderCode = 'Item { \n\
71 visible: image.status == Image.Ready; \n\
71 visible: image.status == Image.Ready; \n\
72 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1; \n\
72 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1; \n\
73 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1; \n\
73 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1; \n\
74− readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect; \n\
75 Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; } \n\
74 Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; } \n\
76− onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings(); \n\
77 Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); } \n\
75 Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); } \n\
78 function updateWidthHeightBindings() { \n\
76 function updateWidthHeightBindings() { \n\
79 if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) { \n\
77 if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) { \n\
80 width = root.fixedArtShapeSize.width; \n\
78 width = root.fixedArtShapeSize.width; \n\
81 height = root.fixedArtShapeSize.height; \n\
79 height = root.fixedArtShapeSize.height; \n\
82− } else if (aspectSmallerThanImageAspect) { \n\
83− width = Qt.binding(function() { return !visible ? 0 : image.width }); \n\
84− height = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.height : width / image.aspect }); \n\
85 } else { \n\
80 } else { \n\
86− width = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.width : height * image.aspect }); \n\
81+ width = Qt.binding(function() { return !visible ? 0 : image.width }); \n\
87 height = Qt.binding(function() { return !visible ? 0 : image.height }); \n\
82 height = Qt.binding(function() { return !visible ? 0 : image.height }); \n\
88 } \n\
83 } \n\
89 } \n\
84 } \n\
@@ -92,8 +87,7 @@ var kArtShapeHolderCode = 'Item { \n\
92 source: cardData && cardData["art"] || ""; \n\
87 source: cardData && cardData["art"] || ""; \n\
93 cache: true; \n\
88 cache: true; \n\
94 asynchronous: root.asynchronous; \n\
89 asynchronous: root.asynchronous; \n\
95− fillMode: components && components["art"]["fill-mode"] === "fit" ? Image.PreserveAspectFit: Image.PreserveAspectCrop; \n\
90+ fillMode: Image.PreserveAspectCrop; \n\
96− readonly property real aspect: implicitWidth / implicitHeight; \n\
97 width: %2; \n\
91 width: %2; \n\
98 height: %3; \n\
92 height: %3; \n\
99 } \n\
93 } \n\
@@ -114,7 +108,7 @@ var kOverlayLoaderCode = 'Loader { \n\
114 sourceComponent: ShaderEffect { \n\
108 sourceComponent: ShaderEffect { \n\
115 id: overlay; \n\
109 id: overlay; \n\
116 height: (fixedHeaderHeight > 0 ? fixedHeaderHeight : headerHeight) + units.gu(2); \n\
110 height: (fixedHeaderHeight > 0 ? fixedHeaderHeight : headerHeight) + units.gu(2); \n\
117− opacity: 0.6; \n\
111+ property color overlayColor: cardData && cardData["overlayColor"] || "#99000000"; \n\
118 property var source: ShaderEffectSource { \n\
112 property var source: ShaderEffectSource { \n\
119 id: shaderSource; \n\
113 id: shaderSource; \n\
120 sourceItem: artShapeLoader.item; \n\
114 sourceItem: artShapeLoader.item; \n\
@@ -135,9 +129,10 @@ var kOverlayLoaderCode = 'Loader { \n\
135 varying highp vec2 coord; \n\
129 varying highp vec2 coord; \n\
136 uniform sampler2D source; \n\
130 uniform sampler2D source; \n\
137 uniform lowp float qt_Opacity; \n\
131 uniform lowp float qt_Opacity; \n\
132+ uniform highp vec4 overlayColor; \n\
138 void main() { \n\
133 void main() { \n\
139 lowp vec4 tex = texture2D(source, coord); \n\
134 lowp vec4 tex = texture2D(source, coord); \n\
140− gl_FragColor = vec4(0, 0, 0, tex.a) * qt_Opacity; \n\
135+ gl_FragColor = vec4(overlayColor.r, overlayColor.g, overlayColor.b, 1) * qt_Opacity * overlayColor.a * tex.a; \n\
141 }"; \n\
136 }"; \n\
142 } \n\
137 } \n\
143 }\n';
138 }\n';
@@ -257,6 +252,16 @@ var kTitleLabelCode = 'Label { \n\
257 horizontalAlignment: root.headerAlignment; \n\
252 horizontalAlignment: root.headerAlignment; \n\
258 }\n';
253 }\n';
259
254
255+// %1 is used as anchors of touchdown effect
256+var kTouchdownCode = 'UbuntuShape { \n\
257+ id: touchdown; \n\
258+ objectName: "touchdown"; \n\
259+ anchors { %1 } \n\
260+ visible: root.pressed; \n\
261+ radius: "medium"; \n\
262+ borderSource: "radius_pressed.sci" \n\
263+ }\n';
264+
260// %1 is used as anchors of subtitleLabel
265// %1 is used as anchors of subtitleLabel
261// %2 is used as color of subtitleLabel
266// %2 is used as color of subtitleLabel
262var kSubtitleLabelCode = 'Label { \n\
267var kSubtitleLabelCode = 'Label { \n\
@@ -279,7 +284,7 @@ var kAttributesRowCode = 'CardAttributes { \n\
279 objectName: "attributesRow"; \n\
284 objectName: "attributesRow"; \n\
280 anchors { %1 } \n\
285 anchors { %1 } \n\
281 color: %2; \n\
286 color: %2; \n\
282− model: cardData && cardData["attributes"] || undefined; \n\
287+ model: cardData["attributes"]; \n\
283 }\n';
288 }\n';
284
289
285// %1 is used as top anchor of summary
290// %1 is used as top anchor of summary
@@ -569,6 +574,16 @@ function cardString(template, components) {
569 code += kSummaryLabelCode.arg(summaryTopAnchor).arg(summaryTopMargin).arg(color);
574 code += kSummaryLabelCode.arg(summaryTopAnchor).arg(summaryTopMargin).arg(color);
570 }
575 }
571
576
577+ var touchdownAnchors;
578+ if (hasBackground) {
579+ touchdownAnchors = 'fill: backgroundLoader';
580+ } else if (hasArt && !hasMascot && !hasSummary) {
581+ touchdownAnchors = 'fill: artShapeHolder';
582+ } else {
583+ touchdownAnchors = 'fill: root'
584+ }
585+ code += kTouchdownCode.arg(touchdownAnchors);
586+
572 if (hasSummary) {
587 if (hasSummary) {
573 code += 'implicitHeight: summary.y + summary.height + (summary.text ? units.gu(1) : 0);\n';
588 code += 'implicitHeight: summary.y + summary.height + (summary.text ? units.gu(1) : 0);\n';
574 } else if (hasHeaderRow) {
589 } else if (hasHeaderRow) {
@@ -593,7 +608,6 @@ function cardString(template, components) {
593function createCardComponent(parent, template, components) {
608function createCardComponent(parent, template, components) {
594 var imports = 'import QtQuick 2.2; \n\
609 var imports = 'import QtQuick 2.2; \n\
595 import Ubuntu.Components 0.1; \n\
610 import Ubuntu.Components 0.1; \n\
596− import Ubuntu.Thumbnailer 0.1;\n\
597 import Dash 0.1;\n';
611 import Dash 0.1;\n';
598 var card = cardString(template, components);
612 var card = cardString(template, components);
599 var code = imports + 'Component {\n' + card + '}\n';
613 var code = imports + 'Component {\n' + card + '}\n';
plugins/Dash/ScopeStyle.qml+11−8
@@ -38,14 +38,20 @@ QtObject {
38 /// Color used for text and symbolic icons
38 /// Color used for text and symbolic icons
39 readonly property color foreground: "foreground-color" in style ? style["foreground-color"] : d.defaultDark
39 readonly property color foreground: "foreground-color" in style ? style["foreground-color"] : d.defaultDark
40
40
41+ /// Luminance of the foreground color
42+ readonly property real foregroundLuminance: foreground ? luminance(foreground) : d.defaultForegroundLuminance
43+
41 /// Color used for the overall background
44 /// Color used for the overall background
42 readonly property color background: "background-color" in style ? style["background-color"] : "transparent"
45 readonly property color background: "background-color" in style ? style["background-color"] : "transparent"
43
46
47+ /// Luminance of the foreground color
48+ readonly property real backgroundLuminance: background ? luminance(background) : d.defaultBackgroundLuminance
49+
44 /*! \brief Luminance threshold for switching between fore and background color
50 /*! \brief Luminance threshold for switching between fore and background color
45
51
46 \note If background colour is not fully opaque, it's not taken into account.
52 \note If background colour is not fully opaque, it's not taken into account.
47 */
53 */
48− readonly property real threshold: background.a !== 1.0 ? d.foregroundLuminance : (d.foregroundLuminance + d.backgroundLuminance) / 2
54+ readonly property real threshold: background.a !== 1.0 ? foregroundLuminance : (foregroundLuminance + backgroundLuminance) / 2
49
55
50 /*! \brief The lighter of foreground and background colors
56 /*! \brief The lighter of foreground and background colors
51
57
@@ -53,8 +59,8 @@ QtObject {
53 and defaults to the theme-provided light color.
59 and defaults to the theme-provided light color.
54 */
60 */
55 readonly property color light: {
61 readonly property color light: {
56− if (background.a !== 1.0) return d.foregroundLuminance > d.defaultLightLuminance ? foreground : d.defaultLight;
62+ if (background.a !== 1.0) return foregroundLuminance > d.defaultLightLuminance ? foreground : d.defaultLight;
57− return d.foregroundLuminance > d.backgroundLuminance ? foreground : background;
63+ return foregroundLuminance > backgroundLuminance ? foreground : background;
58 }
64 }
59
65
60 /*! \brief The darker of foreground and background colors
66 /*! \brief The darker of foreground and background colors
@@ -63,8 +69,8 @@ QtObject {
63 and defaults to the theme-provided dark color.
69 and defaults to the theme-provided dark color.
64 */
70 */
65 readonly property color dark: {
71 readonly property color dark: {
66− if (background.a !== 1.0) return d.foregroundLuminance < d.defaultDarkLuminance ? foreground : d.defaultDark;
72+ if (background.a !== 1.0) return foregroundLuminance < d.defaultDarkLuminance ? foreground : d.defaultDark;
67− return d.foregroundLuminance < d.backgroundLuminance ? foreground : background;
73+ return foregroundLuminance < backgroundLuminance ? foreground : background;
68 }
74 }
69
75
70 /// Source of the logo image for the header
76 /// Source of the logo image for the header
@@ -78,9 +84,6 @@ QtObject {
78
84
79 //! @cond
85 //! @cond
80 property var d: QtObject {
86 property var d: QtObject {
81− readonly property real foregroundLuminance: luminance(foreground)
82− readonly property real backgroundLuminance: luminance(background)
83−
84 // FIXME: should be taken from the theme
87 // FIXME: should be taken from the theme
85 readonly property color defaultLight: "white"
88 readonly property color defaultLight: "white"
86 readonly property color defaultDark: "grey"
89 readonly property color defaultDark: "grey"
plugins/Unity/CMakeLists.txt+1
@@ -1,3 +1,4 @@
1add_subdirectory(Indicators)
1add_subdirectory(Indicators)
2add_subdirectory(Launcher)
2add_subdirectory(Launcher)
3add_subdirectory(Session)
3add_subdirectory(Session)
4+add_subdirectory(DashCommunicator)
plugins/Unity/DashCommunicator/CMakeLists.txtnew file+19
@@ -0,0 +1,19 @@
1+include_directories(
2+ ${CMAKE_CURRENT_SOURCE_DIR}
3+)
4+
5+set(QMLDASHCOMMUNICATORPLUGIN_SRC
6+ plugin.cpp
7+ dbusdashcommunicatorservice.cpp
8+ dashcommunicatorservice.cpp
9+ dashcommunicator.cpp
10+ )
11+
12+add_library(DashCommunicator-qml MODULE
13+ ${QMLDASHCOMMUNICATORPLUGIN_SRC}
14+ )
15+
16+qt5_use_modules(DashCommunicator-qml DBus Qml)
17+
18+# export the qmldir and qmltypes files
19+add_unity8_plugin(Unity.DashCommunicator 0.1 Unity/DashCommunicator TARGETS DashCommunicator-qml)
plugins/Unity/DashCommunicator/dashcommunicator.cppnew file+43
@@ -0,0 +1,43 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "dashcommunicator.h"
18+
19+#include <QObject>
20+#include <QDBusConnection>
21+#include <QDBusInterface>
22+#include <QDebug>
23+
24+DashCommunicator::DashCommunicator(QObject *parent):
25+ QObject(parent)
26+{
27+}
28+
29+DashCommunicator::~DashCommunicator()
30+{
31+}
32+
33+
34+void DashCommunicator::setCurrentScope(const QString &scopeId, bool animate, bool reset)
35+{
36+ QDBusConnection connection = QDBusConnection::sessionBus();
37+ QDBusInterface dashIface ("com.canonical.UnityDash",
38+ "/com/canonical/UnityDash",
39+ "",
40+ connection);
41+
42+ dashIface.call("SetCurrentScope", scopeId, animate, reset);
43+}
plugins/Unity/DashCommunicator/dashcommunicator.hnew file+35
@@ -0,0 +1,35 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef DASHCOMMUNICATOR_H
18+#define DASHCOMMUNICATOR_H
19+
20+#include <QObject>
21+
22+class DashCommunicator: public QObject
23+{
24+ Q_OBJECT
25+ Q_CLASSINFO("D-Bus Interface", "com.canonical.Unity.DashCommunicator")
26+
27+public:
28+ DashCommunicator(QObject *parent = 0);
29+ ~DashCommunicator();
30+
31+public Q_SLOTS:
32+ void setCurrentScope(const QString &scopeId, bool animate, bool reset);
33+};
34+
35+#endif
plugins/Unity/DashCommunicator/dashcommunicatorservice.cppnew file+30
@@ -0,0 +1,30 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "dashcommunicatorservice.h"
18+
19+DashCommunicatorService::DashCommunicatorService(QObject *parent):
20+ QObject(parent),
21+ m_dbusService(new DBusDashCommunicatorService(this))
22+{
23+ connect(m_dbusService, &DBusDashCommunicatorService::setCurrentScopeRequested, this, &DashCommunicatorService::setCurrentScopeRequested);
24+}
25+
26+
27+DashCommunicatorService::~DashCommunicatorService()
28+{
29+
30+}
plugins/Unity/DashCommunicator/dashcommunicatorservice.hnew file+38
@@ -0,0 +1,38 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef DASHCOMMUNICATORSERVICE_H
18+#define DASHCOMMUNICATORSERVICE_H
19+
20+#include "dbusdashcommunicatorservice.h"
21+
22+#include <QObject>
23+
24+class DashCommunicatorService: public QObject
25+{
26+ Q_OBJECT
27+public:
28+ DashCommunicatorService(QObject *parent = 0);
29+ ~DashCommunicatorService();
30+
31+Q_SIGNALS:
32+ void setCurrentScopeRequested(const QString &scopeId, bool animate, bool reset);
33+
34+private:
35+ DBusDashCommunicatorService *m_dbusService;
36+};
37+
38+#endif // DBUSUNITYSESSIONSERVICE_H
plugins/Unity/DashCommunicator/dbusdashcommunicatorservice.cppnew file+39
@@ -0,0 +1,39 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "dbusdashcommunicatorservice.h"
18+
19+#include <QDBusConnection>
20+#include <QDBusInterface>
21+#include <QDebug>
22+
23+DBusDashCommunicatorService::DBusDashCommunicatorService(QObject *parent):
24+ QObject(parent)
25+{
26+ QDBusConnection connection = QDBusConnection::sessionBus();
27+
28+ connection.registerService("com.canonical.UnityDash");
29+ connection.registerObject("/com/canonical/UnityDash", this, QDBusConnection::ExportScriptableSlots);
30+}
31+
32+DBusDashCommunicatorService::~DBusDashCommunicatorService()
33+{
34+}
35+
36+void DBusDashCommunicatorService::SetCurrentScope(const QString &scopeId, bool animate, bool reset)
37+{
38+ Q_EMIT setCurrentScopeRequested(scopeId, animate, reset);
39+}
plugins/Unity/DashCommunicator/dbusdashcommunicatorservice.hnew file+39
@@ -0,0 +1,39 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef DBUSDASHCOMMUNICATORSERVICE_H
18+#define DBUSDASHCOMMUNICATORSERVICE_H
19+
20+#include <QObject>
21+
22+class DBusDashCommunicatorService: public QObject
23+{
24+ Q_OBJECT
25+ Q_CLASSINFO("D-Bus Interface", "com.canonical.Unity.DashCommunicator")
26+
27+public:
28+ DBusDashCommunicatorService(QObject *parent = 0);
29+ ~DBusDashCommunicatorService();
30+
31+Q_SIGNALS:
32+ void setCurrentScopeRequested(const QString &scopeId, bool animate, bool reset);
33+
34+public Q_SLOTS:
35+ Q_SCRIPTABLE void SetCurrentScope(const QString &scopeId, bool animate, bool reset);
36+
37+};
38+
39+#endif // DBUSUNITYSESSIONSERVICE_H
plugins/Unity/DashCommunicator/plugin.cppnew file+31
@@ -0,0 +1,31 @@
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+ * Authors: Michael Zanetti <michael.zanetti@canonical.com>
17+ */
18+
19+#include "plugin.h"
20+#include "dashcommunicator.h"
21+#include "dashcommunicatorservice.h"
22+
23+#include <QDBusConnection>
24+#include <QtQml/qqml.h>
25+
26+void DashCommunicatorPlugin::registerTypes(const char *uri)
27+{
28+ Q_ASSERT(uri == QStringLiteral("Unity.DashCommunicator"));
29+ qmlRegisterType<DashCommunicatorService>(uri, 0, 1, "DashCommunicatorService");
30+ qmlRegisterType<DashCommunicator>(uri, 0, 1, "DashCommunicator");
31+}
plugins/Unity/DashCommunicator/plugin.hnew file+34
@@ -0,0 +1,34 @@
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+ * Authors: Michael Zanetti <michael.zanetti@canonical.com>
17+ */
18+
19+#ifndef DASHCOMMUNICATOR_PLUGIN_H
20+#define DASHCOMMUNICATOR_PLUGIN_H
21+
22+#include <QtQml/QQmlEngine>
23+#include <QtQml/QQmlExtensionPlugin>
24+
25+class DashCommunicatorPlugin : public QQmlExtensionPlugin
26+{
27+ Q_OBJECT
28+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
29+
30+public:
31+ void registerTypes(const char *uri);
32+};
33+
34+#endif
plugins/Unity/DashCommunicator/qmldirnew file+3
@@ -0,0 +1,3 @@
1+module Unity.DashCommunicator
2+plugin DashCommunicator-qml
3+typeinfo DashCommunicator.qmltypes
plugins/Unity/Launcher/launchermodel.cpp+5
@@ -317,6 +317,11 @@ void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
317 return;
317 return;
318 }
318 }
319
319
320+ if (app->appId() == "unity8-dash") {
321+ // Not adding the dash app
322+ return;
323+ }
324+
320 bool found = false;
325 bool found = false;
321 Q_FOREACH(LauncherItem *item, m_list) {
326 Q_FOREACH(LauncherItem *item, m_list) {
322 if (app->appId() == item->appId()) {
327 if (app->appId() == item->appId()) {
po/am.po+10−10
@@ -8,14 +8,14 @@ msgstr ""
8"Project-Id-Version: unity8\n"
8"Project-Id-Version: unity8\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-07-11 14:59+0200\n"
10"POT-Creation-Date: 2014-07-11 14:59+0200\n"
11−"PO-Revision-Date: 2014-07-27 01:25+0000\n"
11+"PO-Revision-Date: 2014-08-04 16:30+0000\n"
12"Last-Translator: samson <Unknown>\n"
12"Last-Translator: samson <Unknown>\n"
13"Language-Team: Amharic <am@li.org>\n"
13"Language-Team: Amharic <am@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-07-28 06:44+0000\n"
17+"X-Launchpad-Export-Date: 2014-08-05 06:45+0000\n"
18−"X-Generator: Launchpad (build 17131)\n"
18+"X-Generator: Launchpad (build 17147)\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
@@ -36,7 +36,7 @@ msgstr "የቀኝ ጠርዝ"
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 "ስልኩን ለመክፈት ከ ቀኝ ጠርዝ በኩል ወደ ግራ ይጥረጉ"
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 "የላይ ጠርዝ"
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 "ጠቋሚዎች ጋር ለመድረስ ከ ላይ ጠርዝ በኩል ወደ ታች ይጥረጉ"
48
48
49#: qml/Components/EdgeDemo.qml:171
49#: qml/Components/EdgeDemo.qml:171
50msgid "Close"
50msgid "Close"
@@ -52,7 +52,7 @@ msgstr "መዝጊያ"
52
52
53#: qml/Components/EdgeDemo.qml:172
53#: qml/Components/EdgeDemo.qml:172
54msgid "Swipe up again to close the settings screen"
54msgid "Swipe up again to close the settings screen"
55−msgstr ""
55+msgstr "የማሰናጃውን መመልከቻ ለመዝጋት እንደገና ወደ ላይ ይጥረጉ"
56
56
57#: qml/Components/EdgeDemo.qml:199
57#: qml/Components/EdgeDemo.qml:199
58msgid "Left edge"
58msgid "Left edge"
@@ -60,11 +60,11 @@ msgstr "የግራ ጠርዝ"
60
60
61#: qml/Components/EdgeDemo.qml:200
61#: qml/Components/EdgeDemo.qml:200
62msgid "Swipe from the left to reveal the launcher for quick access to apps"
62msgid "Swipe from the left to reveal the launcher for quick access to apps"
63−msgstr ""
63+msgstr "ከ ግራ በኩል ወደ ቀኝ ይጥረጉ በፍጥነት መተግበሪያዎች ጋር ለመድረስ እና ለማስጀመር"
64
64
65#: qml/Components/EdgeDemo.qml:227
65#: qml/Components/EdgeDemo.qml:227
66msgid "Well done"
66msgid "Well done"
67−msgstr ""
67+msgstr "ጥሩ አድረገዋል"
68
68
69#: qml/Components/EdgeDemo.qml:228
69#: qml/Components/EdgeDemo.qml:228
70msgid ""
70msgid ""
@@ -123,7 +123,7 @@ msgstr "አነስተኛ..."
123
123
124#: qml/Dash/Previews/PreviewRatingInput.qml:81
124#: qml/Dash/Previews/PreviewRatingInput.qml:81
125msgid "Rate this"
125msgid "Rate this"
126−msgstr ""
126+msgstr "ለዚህ ደረጃ ይስጡ"
127
127
128#: qml/Dash/Previews/PreviewRatingInput.qml:126
128#: qml/Dash/Previews/PreviewRatingInput.qml:126
129msgid "Add a review"
129msgid "Add a review"
@@ -135,7 +135,7 @@ msgstr "መላኪያ"
135
135
136#: qml/Greeter/Greeter.qml:157
136#: qml/Greeter/Greeter.qml:157
137msgid "Swipe to unlock"
137msgid "Swipe to unlock"
138−msgstr ""
138+msgstr "ለመክፈት ይጥረጉ"
139
139
140#: qml/Hud/HudParametrizedActionsPage.qml:132
140#: qml/Hud/HudParametrizedActionsPage.qml:132
141msgid "Confirm"
141msgid "Confirm"
po/de.po+7−7
@@ -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-07-11 14:59+0200\n"
10"POT-Creation-Date: 2014-07-11 14:59+0200\n"
11−"PO-Revision-Date: 2014-07-15 13:20+0000\n"
11+"PO-Revision-Date: 2014-08-08 08:58+0000\n"
12−"Last-Translator: Phillip Sz <Unknown>\n"
12+"Last-Translator: Martin Pitt <martin.pitt@ubuntu.com>\n"
13"Language-Team: German <de@li.org>\n"
13"Language-Team: German <de@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-07-26 07:16+0000\n"
17+"X-Launchpad-Export-Date: 2014-08-09 05:48+0000\n"
18−"X-Generator: Launchpad (build 17131)\n"
18+"X-Generator: Launchpad (build 17156)\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
@@ -116,7 +116,7 @@ msgstr "Kürzlich"
116
116
117#: qml/Dash/GenericScopeView.qml:330
117#: qml/Dash/GenericScopeView.qml:330
118msgid "See all"
118msgid "See all"
119−msgstr ""
119+msgstr "Alle anzeigen"
120
120
121#: qml/Dash/Previews/PreviewActionCombo.qml:34
121#: qml/Dash/Previews/PreviewActionCombo.qml:34
122msgid "More..."
122msgid "More..."
@@ -172,11 +172,11 @@ msgstr "Bitte die PIN der SIM eingeben"
172
172
173#: qml/Panel/ActiveCallHint.qml:77
173#: qml/Panel/ActiveCallHint.qml:77
174msgid "Tap to return to call..."
174msgid "Tap to return to call..."
175−msgstr ""
175+msgstr "Tippen um zum Anruf zurückzugehen"
176
176
177#: qml/Panel/ActiveCallHint.qml:90
177#: qml/Panel/ActiveCallHint.qml:90
178msgid "Conference"
178msgid "Conference"
179−msgstr ""
179+msgstr "Konferenz"
180
180
181#: qml/Panel/Indicators/MenuItemFactory.qml:583
181#: qml/Panel/Indicators/MenuItemFactory.qml:583
182msgid "In queue…"
182msgid "In queue…"
po/el.po+7−7
@@ -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-07-11 14:59+0200\n"
10"POT-Creation-Date: 2014-07-11 14:59+0200\n"
11−"PO-Revision-Date: 2014-07-28 16:06+0000\n"
11+"PO-Revision-Date: 2014-08-08 13:03+0000\n"
12−"Last-Translator: Chris Taklis (aka Kailor) <ctaklis@gmail.com>\n"
12+"Last-Translator: Simos Xenitellis <Unknown>\n"
13"Language-Team: Greek <el@li.org>\n"
13"Language-Team: Greek <el@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-07-29 06:54+0000\n"
17+"X-Launchpad-Export-Date: 2014-08-09 05:48+0000\n"
18−"X-Generator: Launchpad (build 17131)\n"
18+"X-Generator: Launchpad (build 17156)\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
@@ -171,7 +171,7 @@ msgstr "Παρακαλώ εισάγετε το PIN της κάρτας SIM"
171
171
172#: qml/Panel/ActiveCallHint.qml:77
172#: qml/Panel/ActiveCallHint.qml:77
173msgid "Tap to return to call..."
173msgid "Tap to return to call..."
174−msgstr ""
174+msgstr "Πατήστε για να γυρίσετε στην κλήση..."
175
175
176#: qml/Panel/ActiveCallHint.qml:90
176#: qml/Panel/ActiveCallHint.qml:90
177msgid "Conference"
177msgid "Conference"
@@ -179,7 +179,7 @@ msgstr "Συνδιάσκεψη"
179
179
180#: qml/Panel/Indicators/MenuItemFactory.qml:583
180#: qml/Panel/Indicators/MenuItemFactory.qml:583
181msgid "In queue…"
181msgid "In queue…"
182−msgstr ""
182+msgstr "Στην ουρά..."
183
183
184#: qml/Panel/Indicators/MenuItemFactory.qml:587
184#: qml/Panel/Indicators/MenuItemFactory.qml:587
185msgid "Downloading"
185msgid "Downloading"
@@ -199,7 +199,7 @@ msgstr "Ολοκληρώθηκε"
199
199
200#: qml/Panel/Indicators/MenuItemFactory.qml:595
200#: qml/Panel/Indicators/MenuItemFactory.qml:595
201msgid "Failed, tap to retry"
201msgid "Failed, tap to retry"
202−msgstr ""
202+msgstr "Αποτυχία, πατήστε για να ξαναπροσπαθήσετε"
203
203
204#: qml/Panel/SearchIndicator.qml:27
204#: qml/Panel/SearchIndicator.qml:27
205msgid "Search"
205msgid "Search"
po/es.po+5−5
@@ -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-07-11 14:59+0200\n"
10"POT-Creation-Date: 2014-07-11 14:59+0200\n"
11−"PO-Revision-Date: 2014-07-26 06:22+0000\n"
11+"PO-Revision-Date: 2014-08-06 15:24+0000\n"
12−"Last-Translator: Paco Molinero <paco@byasl.com>\n"
12+"Last-Translator: Leo Arias <leo.arias@canonical.com>\n"
13"Language-Team: Spanish <es@li.org>\n"
13"Language-Team: Spanish <es@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-07-27 06:35+0000\n"
17+"X-Launchpad-Export-Date: 2014-08-08 07:07+0000\n"
18−"X-Generator: Launchpad (build 17131)\n"
18+"X-Generator: Launchpad (build 17156)\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
@@ -116,7 +116,7 @@ msgstr "Recientes"
116
116
117#: qml/Dash/GenericScopeView.qml:330
117#: qml/Dash/GenericScopeView.qml:330
118msgid "See all"
118msgid "See all"
119−msgstr "Ver todo"
119+msgstr "Ver todas"
120
120
121#: qml/Dash/Previews/PreviewActionCombo.qml:34
121#: qml/Dash/Previews/PreviewActionCombo.qml:34
122msgid "More..."
122msgid "More..."
po/eu.po+7−6
@@ -8,14 +8,14 @@ msgstr ""
8"Project-Id-Version: unity8\n"
8"Project-Id-Version: unity8\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-07-11 14:59+0200\n"
10"POT-Creation-Date: 2014-07-11 14:59+0200\n"
11−"PO-Revision-Date: 2014-07-25 12:38+0000\n"
11+"PO-Revision-Date: 2014-08-06 22:51+0000\n"
12"Last-Translator: Ibai Oihanguren Sala <Unknown>\n"
12"Last-Translator: Ibai Oihanguren Sala <Unknown>\n"
13"Language-Team: Basque <eu@li.org>\n"
13"Language-Team: Basque <eu@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-07-26 07:16+0000\n"
17+"X-Launchpad-Export-Date: 2014-08-08 07:07+0000\n"
18−"X-Generator: Launchpad (build 17131)\n"
18+"X-Generator: Launchpad (build 17156)\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
@@ -36,7 +36,8 @@ msgstr "Eskuineko ertza"
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 "Probatu eskuineko ertzetik arrastatzen telefonoa desblokeatzeko"
40+"Pasatu hatza eskuineko ertzetik ezkerrerantz telefonoa desblokeatzeko"
40
41
41#: qml/Components/EdgeDemo.qml:145
42#: qml/Components/EdgeDemo.qml:145
42msgid "Top edge"
43msgid "Top edge"
@@ -44,7 +45,7 @@ msgstr "Goiko ertza"
44
45
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"
47−msgstr "Probatu goiko ertzetik arrastatzen adierazleak ikusteko"
48+msgstr "Pasatu hatza goiko ertzetik beherantz adierazleak ikusteko"
48
49
49#: qml/Components/EdgeDemo.qml:171
50#: qml/Components/EdgeDemo.qml:171
50msgid "Close"
51msgid "Close"
@@ -52,7 +53,7 @@ msgstr "Itxi"
52
53
53#: qml/Components/EdgeDemo.qml:172
54#: qml/Components/EdgeDemo.qml:172
54msgid "Swipe up again to close the settings screen"
55msgid "Swipe up again to close the settings screen"
55−msgstr "Pasatu hatza gora berriro ezarpenen leihoa ixteko"
56+msgstr "Pasatu hatza berriro gora ezarpenen leihoa ixteko"
56
57
57#: qml/Components/EdgeDemo.qml:199
58#: qml/Components/EdgeDemo.qml:199
58msgid "Left edge"
59msgid "Left edge"
po/fa.po+51−49
@@ -8,200 +8,202 @@ msgstr ""
8"Project-Id-Version: unity8\n"
8"Project-Id-Version: unity8\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-07-11 14:59+0200\n"
10"POT-Creation-Date: 2014-07-11 14:59+0200\n"
11−"PO-Revision-Date: 2013-10-31 19:02+0000\n"
11+"PO-Revision-Date: 2014-08-03 13:00+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
12+"Last-Translator: Arash Badie Modiri <arashbm@gmail.com>\n"
13"Language-Team: Persian <fa@li.org>\n"
13"Language-Team: Persian <fa@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-07-26 07:17+0000\n"
17+"X-Launchpad-Export-Date: 2014-08-04 06:32+0000\n"
18−"X-Generator: Launchpad (build 17131)\n"
18+"X-Generator: Launchpad (build 17147)\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 "Pin shortcut"
22msgid "Pin shortcut"
23−msgstr ""
23+msgstr "سنجاق کردن میانبر"
24
24
25#: plugins/Unity/Launcher/launcheritem.cpp:73
25#: plugins/Unity/Launcher/launcheritem.cpp:73
26msgid "Unpin shortcut"
26msgid "Unpin shortcut"
27−msgstr ""
27+msgstr "برداشتن سنجاق میانبر"
28
28
29#: qml/Components/EdgeDemoOverlay.qml:151
29#: qml/Components/EdgeDemoOverlay.qml:151
30msgid "Skip intro"
30msgid "Skip intro"
31−msgstr ""
31+msgstr "پرش از مقدّمه"
32
32
33#: qml/Components/EdgeDemo.qml:113
33#: qml/Components/EdgeDemo.qml:113
34msgid "Right edge"
34msgid "Right edge"
35−msgstr ""
35+msgstr "لبه‌ی راست"
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 "برای باز کردن قفل تلفن، از لبه‌ی راست بکشید"
40
40
41#: qml/Components/EdgeDemo.qml:145
41#: qml/Components/EdgeDemo.qml:145
42msgid "Top edge"
42msgid "Top edge"
43−msgstr ""
43+msgstr "لبه‌ی بالا"
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 "برای دست‌رسی به نشانگرها، از لبه‌ی بالا بکشید"
48
48
49#: qml/Components/EdgeDemo.qml:171
49#: qml/Components/EdgeDemo.qml:171
50msgid "Close"
50msgid "Close"
51−msgstr ""
51+msgstr "بستن"
52
52
53#: qml/Components/EdgeDemo.qml:172
53#: qml/Components/EdgeDemo.qml:172
54msgid "Swipe up again to close the settings screen"
54msgid "Swipe up again to close the settings screen"
55−msgstr ""
55+msgstr "برای بستن صفحه‌ی تنظیمات، دوباره به بالا بکشپد"
56
56
57#: qml/Components/EdgeDemo.qml:199
57#: qml/Components/EdgeDemo.qml:199
58msgid "Left edge"
58msgid "Left edge"
59−msgstr ""
59+msgstr "لبه‌ی چپ"
60
60
61#: qml/Components/EdgeDemo.qml:200
61#: qml/Components/EdgeDemo.qml:200
62msgid "Swipe from the left to reveal the launcher for quick access to apps"
62msgid "Swipe from the left to reveal the launcher for quick access to apps"
63−msgstr ""
63+msgstr "برای آشکار شدن اجراگر به منظور دست‌رسی سریع به اپ‌ها از سمت چپ بکشید"
64
64
65#: qml/Components/EdgeDemo.qml:227
65#: qml/Components/EdgeDemo.qml:227
66msgid "Well done"
66msgid "Well done"
67−msgstr ""
67+msgstr "عالی بود"
68
68
69#: qml/Components/EdgeDemo.qml:228
69#: qml/Components/EdgeDemo.qml:228
70msgid ""
70msgid ""
71"You have now mastered the edge gestures and can start using the "
71"You have now mastered the edge gestures and can start using the "
72"phone<br><br>Tap on the screen to start"
72"phone<br><br>Tap on the screen to start"
73msgstr ""
73msgstr ""
74+"هم اکنون در استفاده از ژست های حرکتی مهارت لازم را دارید و می‌توانید استفاده "
75+"از تلفن را آغاز کنید<br><br>برای شروع صفحه را لمس کنید"
74
76
75#: qml/Components/Lockscreen.qml:214
77#: qml/Components/Lockscreen.qml:214
76msgid "Emergency Call"
78msgid "Emergency Call"
77−msgstr ""
79+msgstr "تماس اضطراری"
78
80
79#: qml/Components/Lockscreen.qml:231
81#: qml/Components/Lockscreen.qml:231
80msgid "OK"
82msgid "OK"
81−msgstr ""
83+msgstr "قبول"
82
84
83#: qml/Components/PassphraseLockscreen.qml:60
85#: qml/Components/PassphraseLockscreen.qml:60
84#, qt-format
86#, qt-format
85msgid "Hello %1"
87msgid "Hello %1"
86−msgstr ""
88+msgstr "سلام %1"
87
89
88#: qml/Components/PassphraseLockscreen.qml:60
90#: qml/Components/PassphraseLockscreen.qml:60
89msgid "Hello"
91msgid "Hello"
90−msgstr ""
92+msgstr "سلام"
91
93
92#: qml/Components/PinLockscreen.qml:198
94#: qml/Components/PinLockscreen.qml:198
93msgid "CANCEL"
95msgid "CANCEL"
94−msgstr ""
96+msgstr "لغو"
95
97
96#: qml/Components/PinLockscreen.qml:216
98#: qml/Components/PinLockscreen.qml:216
97msgid "DONE"
99msgid "DONE"
98−msgstr ""
100+msgstr "انجام شد"
99
101
100#: qml/Components/SeeMore.qml:35
102#: qml/Components/SeeMore.qml:35
101msgid "See more"
103msgid "See more"
102−msgstr ""
104+msgstr "بیش‌تر ببینید"
103
105
104#: qml/Components/SeeMore.qml:58 qml/Dash/GenericScopeView.qml:330
106#: qml/Components/SeeMore.qml:58 qml/Dash/GenericScopeView.qml:330
105msgid "See less"
107msgid "See less"
106−msgstr ""
108+msgstr "کم‌تر ببینید"
107
109
108#: qml/Dash/DashApps.qml:37
110#: qml/Dash/DashApps.qml:37
109msgid "Recent"
111msgid "Recent"
110−msgstr ""
112+msgstr "موارد اخیر"
111
113
112#: qml/Dash/GenericScopeView.qml:330
114#: qml/Dash/GenericScopeView.qml:330
113msgid "See all"
115msgid "See all"
114−msgstr ""
116+msgstr "دیدن همه"
115
117
116#: qml/Dash/Previews/PreviewActionCombo.qml:34
118#: qml/Dash/Previews/PreviewActionCombo.qml:34
117msgid "More..."
119msgid "More..."
118−msgstr ""
120+msgstr "بیش‌تر…"
119
121
120#: qml/Dash/Previews/PreviewActionCombo.qml:34
122#: qml/Dash/Previews/PreviewActionCombo.qml:34
121msgid "Less..."
123msgid "Less..."
122−msgstr ""
124+msgstr "کم‌تر…"
123
125
124#: qml/Dash/Previews/PreviewRatingInput.qml:81
126#: qml/Dash/Previews/PreviewRatingInput.qml:81
125msgid "Rate this"
127msgid "Rate this"
126−msgstr ""
128+msgstr "امتیاز دادن"
127
129
128#: qml/Dash/Previews/PreviewRatingInput.qml:126
130#: qml/Dash/Previews/PreviewRatingInput.qml:126
129msgid "Add a review"
131msgid "Add a review"
130−msgstr ""
132+msgstr "افزودن یک بازبینی"
131
133
132#: qml/Dash/Previews/PreviewRatingInput.qml:166
134#: qml/Dash/Previews/PreviewRatingInput.qml:166
133msgid "Send"
135msgid "Send"
134−msgstr ""
136+msgstr "ارسال"
135
137
136#: qml/Greeter/Greeter.qml:157
138#: qml/Greeter/Greeter.qml:157
137msgid "Swipe to unlock"
139msgid "Swipe to unlock"
138−msgstr ""
140+msgstr "برای باز کردن قفل بکشد"
139
141
140#: qml/Hud/HudParametrizedActionsPage.qml:132
142#: qml/Hud/HudParametrizedActionsPage.qml:132
141msgid "Confirm"
143msgid "Confirm"
142−msgstr ""
144+msgstr "تأیید"
143
145
144#: qml/Hud/Hud.qml:61 qml/Hud/Hud.qml:99 qml/Hud/Hud.qml:372
146#: qml/Hud/Hud.qml:61 qml/Hud/Hud.qml:99 qml/Hud/Hud.qml:372
145msgid "Type or say a command"
147msgid "Type or say a command"
146−msgstr ""
148+msgstr "دستوری را بنویسید یا بگویید"
147
149
148#: qml/Hud/Hud.qml:84
150#: qml/Hud/Hud.qml:84
149msgid "Loading. Please Wait..."
151msgid "Loading. Please Wait..."
150−msgstr ""
152+msgstr "در حال بار کردن. لطفاً صبر کنید…"
151
153
152#: qml/Hud/Hud.qml:89
154#: qml/Hud/Hud.qml:89
153msgid "Speak Now..."
155msgid "Speak Now..."
154−msgstr ""
156+msgstr "اکنون صحبت کنید…"
155
157
156#: qml/Hud/Hud.qml:94
158#: qml/Hud/Hud.qml:94
157msgid "Speaking..."
159msgid "Speaking..."
158−msgstr ""
160+msgstr "در حال صحبت کردن…"
159
161
160#: qml/Notifications/NotificationMenuItemFactory.qml:91
162#: qml/Notifications/NotificationMenuItemFactory.qml:91
161msgid "Show password"
163msgid "Show password"
162−msgstr ""
164+msgstr "نمایش گذرواژه"
163
165
164#: qml/Notifications/NotificationMenuItemFactory.qml:103
166#: qml/Notifications/NotificationMenuItemFactory.qml:103
165msgid "Please enter SIM PIN"
167msgid "Please enter SIM PIN"
166−msgstr ""
168+msgstr "لطفاً PIN سیم‌کارت را وارد کنید"
167
169
168#: qml/Panel/ActiveCallHint.qml:77
170#: qml/Panel/ActiveCallHint.qml:77
169msgid "Tap to return to call..."
171msgid "Tap to return to call..."
170−msgstr ""
172+msgstr "برای بازگشت به تماس ضربه بزنید…"
171
173
172#: qml/Panel/ActiveCallHint.qml:90
174#: qml/Panel/ActiveCallHint.qml:90
173msgid "Conference"
175msgid "Conference"
174−msgstr ""
176+msgstr "کنفرانس"
175
177
176#: qml/Panel/Indicators/MenuItemFactory.qml:583
178#: qml/Panel/Indicators/MenuItemFactory.qml:583
177msgid "In queue…"
179msgid "In queue…"
178−msgstr ""
180+msgstr "در صف…"
179
181
180#: qml/Panel/Indicators/MenuItemFactory.qml:587
182#: qml/Panel/Indicators/MenuItemFactory.qml:587
181msgid "Downloading"
183msgid "Downloading"
182−msgstr ""
184+msgstr "در حال بارگیری"
183
185
184#: qml/Panel/Indicators/MenuItemFactory.qml:589
186#: qml/Panel/Indicators/MenuItemFactory.qml:589
185msgid "Paused, tap to resume"
187msgid "Paused, tap to resume"
186−msgstr ""
188+msgstr "مکث شد، برای از سر گیری ضربه بزنید"
187
189
188#: qml/Panel/Indicators/MenuItemFactory.qml:591
190#: qml/Panel/Indicators/MenuItemFactory.qml:591
189msgid "Canceled"
191msgid "Canceled"
190−msgstr ""
192+msgstr "لغو شد"
191
193
192#: qml/Panel/Indicators/MenuItemFactory.qml:593
194#: qml/Panel/Indicators/MenuItemFactory.qml:593
193msgid "Finished"
195msgid "Finished"
194−msgstr ""
196+msgstr "پایان یافت"
195
197
196#: qml/Panel/Indicators/MenuItemFactory.qml:595
198#: qml/Panel/Indicators/MenuItemFactory.qml:595
197msgid "Failed, tap to retry"
199msgid "Failed, tap to retry"
198−msgstr ""
200+msgstr "شکست خورد، برای تلاش دوباره ضربه بزنید"
199
201
200#: qml/Panel/SearchIndicator.qml:27
202#: qml/Panel/SearchIndicator.qml:27
201msgid "Search"
203msgid "Search"
202−msgstr ""
204+msgstr "جست‌وجو"
203
205
204#: qml/Shell.qml:359
206#: qml/Shell.qml:359
205#, qt-format
207#, qt-format
206msgid "Please enter %1"
208msgid "Please enter %1"
207−msgstr ""
209+msgstr "لطفا %1 را وارد کنید"
po/hu.po+7−7
@@ -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-07-11 14:59+0200\n"
10"POT-Creation-Date: 2014-07-11 14:59+0200\n"
11−"PO-Revision-Date: 2014-07-30 18:42+0000\n"
11+"PO-Revision-Date: 2014-08-06 07:41+0000\n"
12"Last-Translator: Richard Somlói <ricsipontaz@gmail.com>\n"
12"Last-Translator: Richard Somlói <ricsipontaz@gmail.com>\n"
13"Language-Team: Hungarian <hu@li.org>\n"
13"Language-Team: Hungarian <hu@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-07-31 07:15+0000\n"
17+"X-Launchpad-Export-Date: 2014-08-08 07:07+0000\n"
18−"X-Generator: Launchpad (build 17131)\n"
18+"X-Generator: Launchpad (build 17156)\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
@@ -44,7 +44,7 @@ msgstr "Felső szél"
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 "A jelzők eléréséhez csúsztassa ujját a felső szélről"
47+msgstr "Az állapotmenük eléréséhez csúsztassa ujját a felső szélről"
48
48
49#: qml/Components/EdgeDemo.qml:171
49#: qml/Components/EdgeDemo.qml:171
50msgid "Close"
50msgid "Close"
@@ -82,16 +82,16 @@ msgstr "Vészhívás"
82
82
83#: qml/Components/Lockscreen.qml:231
83#: qml/Components/Lockscreen.qml:231
84msgid "OK"
84msgid "OK"
85−msgstr "Oké"
85+msgstr "Ok"
86
86
87#: qml/Components/PassphraseLockscreen.qml:60
87#: qml/Components/PassphraseLockscreen.qml:60
88#, qt-format
88#, qt-format
89msgid "Hello %1"
89msgid "Hello %1"
90−msgstr "Szia %1"
90+msgstr "Üdv %1"
91
91
92#: qml/Components/PassphraseLockscreen.qml:60
92#: qml/Components/PassphraseLockscreen.qml:60
93msgid "Hello"
93msgid "Hello"
94−msgstr "Szia"
94+msgstr "Üdvözöljük"
95
95
96#: qml/Components/PinLockscreen.qml:198
96#: qml/Components/PinLockscreen.qml:198
97msgid "CANCEL"
97msgid "CANCEL"
po/ja.po+15−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-07-11 14:59+0200\n"
10"POT-Creation-Date: 2014-07-11 14:59+0200\n"
11−"PO-Revision-Date: 2014-01-18 07:01+0000\n"
11+"PO-Revision-Date: 2014-08-08 06:18+0000\n"
12−"Last-Translator: Shushi Kurose <md81bird@hitaki.net>\n"
12+"Last-Translator: Mitsuya Shibata <mty.shibata@gmail.com>\n"
13"Language-Team: Japanese <ja@li.org>\n"
13"Language-Team: Japanese <ja@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-07-26 07:16+0000\n"
17+"X-Launchpad-Export-Date: 2014-08-09 05:48+0000\n"
18−"X-Generator: Launchpad (build 17131)\n"
18+"X-Generator: Launchpad (build 17156)\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
@@ -28,7 +28,7 @@ msgstr ""
28
28
29#: qml/Components/EdgeDemoOverlay.qml:151
29#: qml/Components/EdgeDemoOverlay.qml:151
30msgid "Skip intro"
30msgid "Skip intro"
31−msgstr ""
31+msgstr "導入ガイドをスキップ"
32
32
33#: qml/Components/EdgeDemo.qml:113
33#: qml/Components/EdgeDemo.qml:113
34msgid "Right edge"
34msgid "Right edge"
@@ -44,7 +44,7 @@ msgstr "上端"
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 "インジケーターにアクセスするには上端からスワイプしてみてください"
48
48
49#: qml/Components/EdgeDemo.qml:171
49#: qml/Components/EdgeDemo.qml:171
50msgid "Close"
50msgid "Close"
@@ -52,7 +52,7 @@ msgstr "閉じる"
52
52
53#: qml/Components/EdgeDemo.qml:172
53#: qml/Components/EdgeDemo.qml:172
54msgid "Swipe up again to close the settings screen"
54msgid "Swipe up again to close the settings screen"
55−msgstr ""
55+msgstr "設定画面を閉じるにはもう一度上にスワイプしてください"
56
56
57#: qml/Components/EdgeDemo.qml:199
57#: qml/Components/EdgeDemo.qml:199
58msgid "Left edge"
58msgid "Left edge"
@@ -60,11 +60,11 @@ msgstr "左端"
60
60
61#: qml/Components/EdgeDemo.qml:200
61#: qml/Components/EdgeDemo.qml:200
62msgid "Swipe from the left to reveal the launcher for quick access to apps"
62msgid "Swipe from the left to reveal the launcher for quick access to apps"
63−msgstr ""
63+msgstr "アプリに素早くアクセスできるLauncherを表示するには左からスワイプしてください"
64
64
65#: qml/Components/EdgeDemo.qml:227
65#: qml/Components/EdgeDemo.qml:227
66msgid "Well done"
66msgid "Well done"
67−msgstr ""
67+msgstr "よくできました!"
68
68
69#: qml/Components/EdgeDemo.qml:228
69#: qml/Components/EdgeDemo.qml:228
70msgid ""
70msgid ""
@@ -74,16 +74,16 @@ msgstr ""
74
74
75#: qml/Components/Lockscreen.qml:214
75#: qml/Components/Lockscreen.qml:214
76msgid "Emergency Call"
76msgid "Emergency Call"
77−msgstr ""
77+msgstr "緊急通報"
78
78
79#: qml/Components/Lockscreen.qml:231
79#: qml/Components/Lockscreen.qml:231
80msgid "OK"
80msgid "OK"
81−msgstr ""
81+msgstr "OK"
82
82
83#: qml/Components/PassphraseLockscreen.qml:60
83#: qml/Components/PassphraseLockscreen.qml:60
84#, qt-format
84#, qt-format
85msgid "Hello %1"
85msgid "Hello %1"
86−msgstr ""
86+msgstr "こんにちは %1 さん"
87
87
88#: qml/Components/PassphraseLockscreen.qml:60
88#: qml/Components/PassphraseLockscreen.qml:60
89msgid "Hello"
89msgid "Hello"
@@ -99,7 +99,7 @@ msgstr ""
99
99
100#: qml/Components/SeeMore.qml:35
100#: qml/Components/SeeMore.qml:35
101msgid "See more"
101msgid "See more"
102−msgstr ""
102+msgstr "さらに表示する"
103
103
104#: qml/Components/SeeMore.qml:58 qml/Dash/GenericScopeView.qml:330
104#: qml/Components/SeeMore.qml:58 qml/Dash/GenericScopeView.qml:330
105msgid "See less"
105msgid "See less"
@@ -127,7 +127,7 @@ msgstr ""
127
127
128#: qml/Dash/Previews/PreviewRatingInput.qml:126
128#: qml/Dash/Previews/PreviewRatingInput.qml:126
129msgid "Add a review"
129msgid "Add a review"
130−msgstr ""
130+msgstr "レビューを追加"
131
131
132#: qml/Dash/Previews/PreviewRatingInput.qml:166
132#: qml/Dash/Previews/PreviewRatingInput.qml:166
133msgid "Send"
133msgid "Send"
@@ -155,7 +155,7 @@ msgstr "音声入力を開始..."
155
155
156#: qml/Hud/Hud.qml:94
156#: qml/Hud/Hud.qml:94
157msgid "Speaking..."
157msgid "Speaking..."
158−msgstr ""
158+msgstr "入力中..."
159
159
160#: qml/Notifications/NotificationMenuItemFactory.qml:91
160#: qml/Notifications/NotificationMenuItemFactory.qml:91
161msgid "Show password"
161msgid "Show password"
po/km.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
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-08-01 07:14+0000\n"
17+"X-Launchpad-Export-Date: 2014-08-02 06:39+0000\n"
18−"X-Generator: Launchpad (build 17141)\n"
18+"X-Generator: Launchpad (build 17147)\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
po/pt_BR.po+14−14
@@ -8,23 +8,23 @@ 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-07-11 14:59+0200\n"
10"POT-Creation-Date: 2014-07-11 14:59+0200\n"
11−"PO-Revision-Date: 2014-07-17 05:46+0000\n"
11+"PO-Revision-Date: 2014-08-07 12:34+0000\n"
12−"Last-Translator: Tiago Hillebrandt <tiagohillebrandt@gmail.com>\n"
12+"Last-Translator: Salomão Carneiro de Brito <salomaocar@gmail.com>\n"
13"Language-Team: Brazilian Portuguese <pt_BR@li.org>\n"
13"Language-Team: Brazilian Portuguese <pt_BR@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-07-26 07:17+0000\n"
17+"X-Launchpad-Export-Date: 2014-08-08 07:07+0000\n"
18−"X-Generator: Launchpad (build 17131)\n"
18+"X-Generator: Launchpad (build 17156)\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 "Pin shortcut"
22msgid "Pin shortcut"
23−msgstr ""
23+msgstr "Fixar atalho"
24
24
25#: plugins/Unity/Launcher/launcheritem.cpp:73
25#: plugins/Unity/Launcher/launcheritem.cpp:73
26msgid "Unpin shortcut"
26msgid "Unpin shortcut"
27−msgstr ""
27+msgstr "Desafixar atalho"
28
28
29#: qml/Components/EdgeDemoOverlay.qml:151
29#: qml/Components/EdgeDemoOverlay.qml:151
30msgid "Skip intro"
30msgid "Skip intro"
@@ -99,7 +99,7 @@ msgstr "CANCELAR"
99
99
100#: qml/Components/PinLockscreen.qml:216
100#: qml/Components/PinLockscreen.qml:216
101msgid "DONE"
101msgid "DONE"
102−msgstr ""
102+msgstr "FEITO"
103
103
104#: qml/Components/SeeMore.qml:35
104#: qml/Components/SeeMore.qml:35
105msgid "See more"
105msgid "See more"
@@ -115,7 +115,7 @@ msgstr "Recentes"
115
115
116#: qml/Dash/GenericScopeView.qml:330
116#: qml/Dash/GenericScopeView.qml:330
117msgid "See all"
117msgid "See all"
118−msgstr ""
118+msgstr "Ver todos"
119
119
120#: qml/Dash/Previews/PreviewActionCombo.qml:34
120#: qml/Dash/Previews/PreviewActionCombo.qml:34
121msgid "More..."
121msgid "More..."
@@ -171,15 +171,15 @@ msgstr "Por favor, digite o PIN do cartão SIM"
171
171
172#: qml/Panel/ActiveCallHint.qml:77
172#: qml/Panel/ActiveCallHint.qml:77
173msgid "Tap to return to call..."
173msgid "Tap to return to call..."
174−msgstr ""
174+msgstr "Toque para retornar para a chamada..."
175
175
176#: qml/Panel/ActiveCallHint.qml:90
176#: qml/Panel/ActiveCallHint.qml:90
177msgid "Conference"
177msgid "Conference"
178−msgstr ""
178+msgstr "Conferência"
179
179
180#: qml/Panel/Indicators/MenuItemFactory.qml:583
180#: qml/Panel/Indicators/MenuItemFactory.qml:583
181msgid "In queue…"
181msgid "In queue…"
182−msgstr ""
182+msgstr "Em fila..."
183
183
184#: qml/Panel/Indicators/MenuItemFactory.qml:587
184#: qml/Panel/Indicators/MenuItemFactory.qml:587
185msgid "Downloading"
185msgid "Downloading"
@@ -187,7 +187,7 @@ msgstr "Baixando"
187
187
188#: qml/Panel/Indicators/MenuItemFactory.qml:589
188#: qml/Panel/Indicators/MenuItemFactory.qml:589
189msgid "Paused, tap to resume"
189msgid "Paused, tap to resume"
190−msgstr ""
190+msgstr "Em pausa, toque para continuar"
191
191
192#: qml/Panel/Indicators/MenuItemFactory.qml:591
192#: qml/Panel/Indicators/MenuItemFactory.qml:591
193msgid "Canceled"
193msgid "Canceled"
@@ -195,11 +195,11 @@ msgstr "Cancelado"
195
195
196#: qml/Panel/Indicators/MenuItemFactory.qml:593
196#: qml/Panel/Indicators/MenuItemFactory.qml:593
197msgid "Finished"
197msgid "Finished"
198−msgstr ""
198+msgstr "Finalizado"
199
199
200#: qml/Panel/Indicators/MenuItemFactory.qml:595
200#: qml/Panel/Indicators/MenuItemFactory.qml:595
201msgid "Failed, tap to retry"
201msgid "Failed, tap to retry"
202−msgstr ""
202+msgstr "Falhou, toque para tentar novamente"
203
203
204#: qml/Panel/SearchIndicator.qml:27
204#: qml/Panel/SearchIndicator.qml:27
205msgid "Search"
205msgid "Search"
po/sl.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-07-11 14:59+0200\n"
10"POT-Creation-Date: 2014-07-11 14:59+0200\n"
11−"PO-Revision-Date: 2014-07-28 12:32+0000\n"
11+"PO-Revision-Date: 2014-08-06 06:11+0000\n"
12"Last-Translator: Damir Jerovšek <Unknown>\n"
12"Last-Translator: Damir Jerovšek <Unknown>\n"
13"Language-Team: Slovenian <sl@li.org>\n"
13"Language-Team: Slovenian <sl@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-07-29 06:54+0000\n"
17+"X-Launchpad-Export-Date: 2014-08-08 07:07+0000\n"
18−"X-Generator: Launchpad (build 17131)\n"
18+"X-Generator: Launchpad (build 17156)\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
@@ -115,7 +115,7 @@ msgstr "Nedavno"
115
115
116#: qml/Dash/GenericScopeView.qml:330
116#: qml/Dash/GenericScopeView.qml:330
117msgid "See all"
117msgid "See all"
118−msgstr ""
118+msgstr "Ogled vsega"
119
119
120#: qml/Dash/Previews/PreviewActionCombo.qml:34
120#: qml/Dash/Previews/PreviewActionCombo.qml:34
121msgid "More..."
121msgid "More..."
po/zh_HK.po+33−33
@@ -8,23 +8,23 @@ msgstr ""
8"Project-Id-Version: unity8\n"
8"Project-Id-Version: unity8\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-07-11 14:59+0200\n"
10"POT-Creation-Date: 2014-07-11 14:59+0200\n"
11−"PO-Revision-Date: 2014-01-25 13:32+0000\n"
11+"PO-Revision-Date: 2014-08-10 11:45+0000\n"
12"Last-Translator: Daniel Cheung <daniel.2345@hotmail.com>\n"
12"Last-Translator: Daniel Cheung <daniel.2345@hotmail.com>\n"
13"Language-Team: Chinese (Hong Kong) <zh_HK@li.org>\n"
13"Language-Team: Chinese (Hong Kong) <zh_HK@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-07-26 07:17+0000\n"
17+"X-Launchpad-Export-Date: 2014-08-11 06:34+0000\n"
18−"X-Generator: Launchpad (build 17131)\n"
18+"X-Generator: Launchpad (build 17156)\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 "Pin shortcut"
22msgid "Pin shortcut"
23−msgstr ""
23+msgstr "釘住捷徑"
24
24
25#: plugins/Unity/Launcher/launcheritem.cpp:73
25#: plugins/Unity/Launcher/launcheritem.cpp:73
26msgid "Unpin shortcut"
26msgid "Unpin shortcut"
27−msgstr ""
27+msgstr "取消捷徑釘選"
28
28
29#: qml/Components/EdgeDemoOverlay.qml:151
29#: qml/Components/EdgeDemoOverlay.qml:151
30msgid "Skip intro"
30msgid "Skip intro"
@@ -32,11 +32,11 @@ msgstr "跳過介紹"
32
32
33#: qml/Components/EdgeDemo.qml:113
33#: qml/Components/EdgeDemo.qml:113
34msgid "Right edge"
34msgid "Right edge"
35−msgstr "右邊緣"
35+msgstr "右側邊緣"
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 "試從右邊緣向左滑動解鎖手機"
40
40
41#: qml/Components/EdgeDemo.qml:145
41#: qml/Components/EdgeDemo.qml:145
42msgid "Top edge"
42msgid "Top edge"
@@ -52,15 +52,15 @@ msgstr "關閉"
52
52
53#: qml/Components/EdgeDemo.qml:172
53#: qml/Components/EdgeDemo.qml:172
54msgid "Swipe up again to close the settings screen"
54msgid "Swipe up again to close the settings screen"
55−msgstr "再向上掃一次以關閉設定畫面"
55+msgstr "再向上滑動一次以關閉設定畫面"
56
56
57#: qml/Components/EdgeDemo.qml:199
57#: qml/Components/EdgeDemo.qml:199
58msgid "Left edge"
58msgid "Left edge"
59−msgstr "左邊緣"
59+msgstr "左側邊緣"
60
60
61#: qml/Components/EdgeDemo.qml:200
61#: qml/Components/EdgeDemo.qml:200
62msgid "Swipe from the left to reveal the launcher for quick access to apps"
62msgid "Swipe from the left to reveal the launcher for quick access to apps"
63−msgstr "從左邊緣輕掃以顯示啟動器快速訪問應用"
63+msgstr "從左側邊緣滑動以顯示啟動器快速查看應用"
64
64
65#: qml/Components/EdgeDemo.qml:227
65#: qml/Components/EdgeDemo.qml:227
66msgid "Well done"
66msgid "Well done"
@@ -70,7 +70,7 @@ msgstr "做得好"
70msgid ""
70msgid ""
71"You have now mastered the edge gestures and can start using the "
71"You have now mastered the edge gestures and can start using the "
72"phone<br><br>Tap on the screen to start"
72"phone<br><br>Tap on the screen to start"
73−msgstr ""
73+msgstr "您現在已熟練邊緣手勢,可以開始使用手機了<br><br>輕觸螢幕開始使用"
74
74
75#: qml/Components/Lockscreen.qml:214
75#: qml/Components/Lockscreen.qml:214
76msgid "Emergency Call"
76msgid "Emergency Call"
@@ -78,7 +78,7 @@ msgstr "緊急電話"
78
78
79#: qml/Components/Lockscreen.qml:231
79#: qml/Components/Lockscreen.qml:231
80msgid "OK"
80msgid "OK"
81−msgstr ""
81+msgstr "確定"
82
82
83#: qml/Components/PassphraseLockscreen.qml:60
83#: qml/Components/PassphraseLockscreen.qml:60
84#, qt-format
84#, qt-format
@@ -91,39 +91,39 @@ msgstr "您好"
91
91
92#: qml/Components/PinLockscreen.qml:198
92#: qml/Components/PinLockscreen.qml:198
93msgid "CANCEL"
93msgid "CANCEL"
94−msgstr ""
94+msgstr "取消"
95
95
96#: qml/Components/PinLockscreen.qml:216
96#: qml/Components/PinLockscreen.qml:216
97msgid "DONE"
97msgid "DONE"
98−msgstr ""
98+msgstr "完成"
99
99
100#: qml/Components/SeeMore.qml:35
100#: qml/Components/SeeMore.qml:35
101msgid "See more"
101msgid "See more"
102−msgstr ""
102+msgstr "查看更多"
103
103
104#: qml/Components/SeeMore.qml:58 qml/Dash/GenericScopeView.qml:330
104#: qml/Components/SeeMore.qml:58 qml/Dash/GenericScopeView.qml:330
105msgid "See less"
105msgid "See less"
106−msgstr ""
106+msgstr "縮減查看"
107
107
108#: qml/Dash/DashApps.qml:37
108#: qml/Dash/DashApps.qml:37
109msgid "Recent"
109msgid "Recent"
110−msgstr ""
110+msgstr "最近"
111
111
112#: qml/Dash/GenericScopeView.qml:330
112#: qml/Dash/GenericScopeView.qml:330
113msgid "See all"
113msgid "See all"
114−msgstr ""
114+msgstr "查看全部"
115
115
116#: qml/Dash/Previews/PreviewActionCombo.qml:34
116#: qml/Dash/Previews/PreviewActionCombo.qml:34
117msgid "More..."
117msgid "More..."
118−msgstr ""
118+msgstr "更多..."
119
119
120#: qml/Dash/Previews/PreviewActionCombo.qml:34
120#: qml/Dash/Previews/PreviewActionCombo.qml:34
121msgid "Less..."
121msgid "Less..."
122−msgstr ""
122+msgstr "縮減…"
123
123
124#: qml/Dash/Previews/PreviewRatingInput.qml:81
124#: qml/Dash/Previews/PreviewRatingInput.qml:81
125msgid "Rate this"
125msgid "Rate this"
126−msgstr "評價"
126+msgstr "評分"
127
127
128#: qml/Dash/Previews/PreviewRatingInput.qml:126
128#: qml/Dash/Previews/PreviewRatingInput.qml:126
129msgid "Add a review"
129msgid "Add a review"
@@ -135,7 +135,7 @@ msgstr "傳送"
135
135
136#: qml/Greeter/Greeter.qml:157
136#: qml/Greeter/Greeter.qml:157
137msgid "Swipe to unlock"
137msgid "Swipe to unlock"
138−msgstr ""
138+msgstr "滑動解除鎖定"
139
139
140#: qml/Hud/HudParametrizedActionsPage.qml:132
140#: qml/Hud/HudParametrizedActionsPage.qml:132
141msgid "Confirm"
141msgid "Confirm"
@@ -147,11 +147,11 @@ msgstr "輸入或說出指令"
147
147
148#: qml/Hud/Hud.qml:84
148#: qml/Hud/Hud.qml:84
149msgid "Loading. Please Wait..."
149msgid "Loading. Please Wait..."
150−msgstr "正載入。請稍候..."
150+msgstr "載入中。請稍候..."
151
151
152#: qml/Hud/Hud.qml:89
152#: qml/Hud/Hud.qml:89
153msgid "Speak Now..."
153msgid "Speak Now..."
154−msgstr "馬上講..."
154+msgstr "請講..."
155
155
156#: qml/Hud/Hud.qml:94
156#: qml/Hud/Hud.qml:94
157msgid "Speaking..."
157msgid "Speaking..."
@@ -163,39 +163,39 @@ msgstr "顯示密碼"
163
163
164#: qml/Notifications/NotificationMenuItemFactory.qml:103
164#: qml/Notifications/NotificationMenuItemFactory.qml:103
165msgid "Please enter SIM PIN"
165msgid "Please enter SIM PIN"
166−msgstr ""
166+msgstr "請輸入 SIM 卡 PIN 碼"
167
167
168#: qml/Panel/ActiveCallHint.qml:77
168#: qml/Panel/ActiveCallHint.qml:77
169msgid "Tap to return to call..."
169msgid "Tap to return to call..."
170−msgstr ""
170+msgstr "輕觸可返回通話…"
171
171
172#: qml/Panel/ActiveCallHint.qml:90
172#: qml/Panel/ActiveCallHint.qml:90
173msgid "Conference"
173msgid "Conference"
174−msgstr ""
174+msgstr "會議"
175
175
176#: qml/Panel/Indicators/MenuItemFactory.qml:583
176#: qml/Panel/Indicators/MenuItemFactory.qml:583
177msgid "In queue…"
177msgid "In queue…"
178−msgstr ""
178+msgstr "佇列中…"
179
179
180#: qml/Panel/Indicators/MenuItemFactory.qml:587
180#: qml/Panel/Indicators/MenuItemFactory.qml:587
181msgid "Downloading"
181msgid "Downloading"
182−msgstr ""
182+msgstr "下載中"
183
183
184#: qml/Panel/Indicators/MenuItemFactory.qml:589
184#: qml/Panel/Indicators/MenuItemFactory.qml:589
185msgid "Paused, tap to resume"
185msgid "Paused, tap to resume"
186−msgstr ""
186+msgstr "已暫停,輕觸以繼續"
187
187
188#: qml/Panel/Indicators/MenuItemFactory.qml:591
188#: qml/Panel/Indicators/MenuItemFactory.qml:591
189msgid "Canceled"
189msgid "Canceled"
190−msgstr ""
190+msgstr "已取消"
191
191
192#: qml/Panel/Indicators/MenuItemFactory.qml:593
192#: qml/Panel/Indicators/MenuItemFactory.qml:593
193msgid "Finished"
193msgid "Finished"
194−msgstr ""
194+msgstr "已完成"
195
195
196#: qml/Panel/Indicators/MenuItemFactory.qml:595
196#: qml/Panel/Indicators/MenuItemFactory.qml:595
197msgid "Failed, tap to retry"
197msgid "Failed, tap to retry"
198−msgstr ""
198+msgstr "失敗,輕觸以重試"
199
199
200#: qml/Panel/SearchIndicator.qml:27
200#: qml/Panel/SearchIndicator.qml:27
201msgid "Search"
201msgid "Search"
qml/Components/EdgeDemo.qml+15−16
@@ -22,16 +22,15 @@ Item {
22 id: demo
22 id: demo
23
23
24 property Item greeter
24 property Item greeter
25− property Item dash
26 property Item launcher
25 property Item launcher
27 property Item indicators
26 property Item indicators
28− property Item underlay
27+ property Item stages
29
28
30 property bool launcherEnabled: true
29 property bool launcherEnabled: true
31− property bool dashEnabled: true
30+ property bool stagesEnabled: true
32 property bool panelEnabled: true
31 property bool panelEnabled: true
33 property bool panelContentEnabled: true
32 property bool panelContentEnabled: true
34− property bool running: !launcherEnabled || !dashEnabled || !panelEnabled || !panelContentEnabled
33+ property bool running: !launcherEnabled || !stagesEnabled || !panelEnabled || !panelContentEnabled
35
34
36 property bool paused: false
35 property bool paused: false
37
36
@@ -59,7 +58,7 @@ Item {
59
58
60 function stopDemo() {
59 function stopDemo() {
61 launcherEnabled = true
60 launcherEnabled = true
62− dashEnabled = true
61+ stagesEnabled = true
63 panelEnabled = true
62 panelEnabled = true
64 panelContentEnabled = true
63 panelContentEnabled = true
65 if (d.rightEdgeDemo) d.rightEdgeDemo.destroy()
64 if (d.rightEdgeDemo) d.rightEdgeDemo.destroy()
@@ -75,11 +74,11 @@ Item {
75 }
74 }
76
75
77 launcherEnabled = false;
76 launcherEnabled = false;
78− dashEnabled = false;
77+ stagesEnabled = false;
79 panelEnabled = false;
78 panelEnabled = false;
80 panelContentEnabled = false;
79 panelContentEnabled = false;
81
80
82− // Begin with either greeter or dash, depending on which is visible
81+ // Begin with either greeter or top, depending on which is visible
83 if (greeter && greeter.shown) {
82 if (greeter && greeter.shown) {
84 startRightEdgeDemo()
83 startRightEdgeDemo()
85 } else {
84 } else {
@@ -139,12 +138,12 @@ Item {
139
138
140 function startTopEdgeDemo() {
139 function startTopEdgeDemo() {
141 demo.panelEnabled = true;
140 demo.panelEnabled = true;
142− if (demo.dash && demo.underlay) {
141+ if (demo.stages) {
143− d.topEdgeDemo = d.overlay.createObject(demo.underlay, {
142+ d.topEdgeDemo = d.overlay.createObject(demo.stages, {
144 "edge": "top",
143 "edge": "top",
145 "title": i18n.tr("Top edge"),
144 "title": i18n.tr("Top edge"),
146 "text": i18n.tr("Try swiping from the top edge to access the indicators"),
145 "text": i18n.tr("Try swiping from the top edge to access the indicators"),
147− "anchors.fill": demo.dash,
146+ "anchors.fill": demo.stages,
148 });
147 });
149 }
148 }
150 if (d.topEdgeDemo) {
149 if (d.topEdgeDemo) {
@@ -193,12 +192,12 @@ Item {
193 function startLeftEdgeDemo() {
192 function startLeftEdgeDemo() {
194 demo.panelEnabled = false;
193 demo.panelEnabled = false;
195 demo.launcherEnabled = true;
194 demo.launcherEnabled = true;
196− if (demo.dash && demo.underlay) {
195+ if (demo.stages) {
197− d.leftEdgeDemo = d.overlay.createObject(demo.underlay, {
196+ d.leftEdgeDemo = d.overlay.createObject(demo.stages, {
198 "edge": "left",
197 "edge": "left",
199 "title": i18n.tr("Left edge"),
198 "title": i18n.tr("Left edge"),
200 "text": i18n.tr("Swipe from the left to reveal the launcher for quick access to apps"),
199 "text": i18n.tr("Swipe from the left to reveal the launcher for quick access to apps"),
201− "anchors.fill": demo.dash,
200+ "anchors.fill": demo.stages,
202 });
201 });
203 }
202 }
204 if (d.leftEdgeDemo) {
203 if (d.leftEdgeDemo) {
@@ -221,12 +220,12 @@ Item {
221
220
222 function startFinalEdgeDemo() {
221 function startFinalEdgeDemo() {
223 demo.launcherEnabled = false;
222 demo.launcherEnabled = false;
224− if (demo.dash && demo.underlay) {
223+ if (demo.stages) {
225− d.finalEdgeDemo = d.overlay.createObject(demo.underlay, {
224+ d.finalEdgeDemo = d.overlay.createObject(demo.stages, {
226 "edge": "none",
225 "edge": "none",
227 "title": i18n.tr("Well done"),
226 "title": i18n.tr("Well done"),
228 "text": i18n.tr("You have now mastered the edge gestures and can start using the phone<br><br>Tap on the screen to start"),
227 "text": i18n.tr("You have now mastered the edge gestures and can start using the phone<br><br>Tap on the screen to start"),
229− "anchors.fill": demo.dash,
228+ "anchors.fill": demo.stages,
230 "showSkip": false,
229 "showSkip": false,
231 });
230 });
232 }
231 }
qml/Components/PageHeader.qml+25−16
@@ -32,9 +32,10 @@ Item {
32 property bool searchEntryEnabled: false
32 property bool searchEntryEnabled: false
33 property ListModel searchHistory: SearchHistoryModel
33 property ListModel searchHistory: SearchHistoryModel
34 property alias searchQuery: searchTextField.text
34 property alias searchQuery: searchTextField.text
35− property bool searchInProgress: false
36
35
37 property alias bottomItem: bottomContainer.children
36 property alias bottomItem: bottomContainer.children
37+ property int paginationCount: 0
38+ property int paginationIndex: -1
38
39
39 // TODO We should use foreground for the icons
40 // TODO We should use foreground for the icons
40 // of the toolbar but unfortunately Action does not have
41 // of the toolbar but unfortunately Action does not have
@@ -125,7 +126,7 @@ Item {
125 Flickable {
126 Flickable {
126 id: headerContainer
127 id: headerContainer
127 objectName: "headerContainer"
128 objectName: "headerContainer"
128− clip: openSearchAnimation.running
129+ clip: contentY < height
129 anchors { left: parent.left; top: parent.top; right: parent.right }
130 anchors { left: parent.left; top: parent.top; right: parent.right }
130 height: units.gu(6.5)
131 height: units.gu(6.5)
131 contentHeight: headersColumn.height
132 contentHeight: headersColumn.height
@@ -169,6 +170,7 @@ Item {
169 property var styledItem: searchHeader
170 property var styledItem: searchHeader
170 property string title
171 property string title
171 property var config: PageHeadConfiguration {
172 property var config: PageHeadConfiguration {
173+ foregroundColor: root.scopeStyle ? root.scopeStyle.headerForeground : "grey"
172 backAction: Action {
174 backAction: Action {
173 iconName: "back"
175 iconName: "back"
174 onTriggered: {
176 onTriggered: {
@@ -200,25 +202,13 @@ Item {
200 anchors.fill: parent
202 anchors.fill: parent
201 anchors.margins: units.gu(.75)
203 anchors.margins: units.gu(.75)
202 source: "image://theme/clear"
204 source: "image://theme/clear"
203− opacity: searchTextField.text.length > 0 && !searchActivityIndicator.running
205+ opacity: searchTextField.text.length > 0
204 visible: opacity > 0
206 visible: opacity > 0
205 Behavior on opacity {
207 Behavior on opacity {
206 UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration }
208 UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration }
207 }
209 }
208 }
210 }
209
211
210− ActivityIndicator {
211− id: searchActivityIndicator
212− objectName: "searchIndicator"
213− anchors.fill: parent
214− anchors.margins: units.gu(.75)
215− running: root.searchInProgress
216− opacity: running ? 1 : 0
217− Behavior on opacity {
218− UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration }
219− }
220− }
221−
222 onClicked: {
212 onClicked: {
223 root.resetSearch(true);
213 root.resetSearch(true);
224 root.openSearchHistory();
214 root.openSearchHistory();
@@ -247,10 +237,10 @@ Item {
247 contentHeight: height
237 contentHeight: height
248 opacity: headerContainer.clip || !headerContainer.showSearch ? 1 : 0 // setting visible false cause column to relayout
238 opacity: headerContainer.clip || !headerContainer.showSearch ? 1 : 0 // setting visible false cause column to relayout
249 separatorSource: ""
239 separatorSource: ""
250− textColor: root.scopeStyle ? root.scopeStyle.headerForeground : "grey"
251 property var styledItem: header
240 property var styledItem: header
252 property string title: root.title
241 property string title: root.title
253 property var config: PageHeadConfiguration {
242 property var config: PageHeadConfiguration {
243+ foregroundColor: root.scopeStyle ? root.scopeStyle.headerForeground : "grey"
254 backAction: Action {
244 backAction: Action {
255 iconName: "back"
245 iconName: "back"
256 visible: root.showBackButton
246 visible: root.showBackButton
@@ -294,6 +284,25 @@ Item {
294 }
284 }
295 }
285 }
296
286
287+ Row {
288+ spacing: units.gu(.5)
289+ Repeater {
290+ objectName: "paginationRepeater"
291+ model: root.paginationCount
292+ Image {
293+ objectName: "paginationDots_" + index
294+ height: units.gu(1)
295+ width: height
296+ source: (index == root.paginationIndex) ? "graphics/pagination_dot_on.png" : "graphics/pagination_dot_off.png"
297+ }
298+ }
299+ anchors {
300+ top: headerContainer.bottom
301+ horizontalCenter: headerContainer.horizontalCenter
302+ topMargin: units.gu(.5)
303+ }
304+ }
305+
297 Component {
306 Component {
298 id: popoverComponent
307 id: popoverComponent
299 Popover {
308 Popover {
qml/Components/SeeMore.qmldeleted−70
@@ -1,70 +0,0 @@
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−
20−/*! Widget that can be used in combination with a text area to allow easy 'expand/collapse' functionality. */
21−
22−Item {
23− //! Boolean set to true when it suggests expanded functionality
24− property bool more: false
25−
26− implicitHeight: seeMoreLabel.height + units.gu(2)
27−
28− Row {
29− anchors.centerIn: parent
30− spacing: units.gu(2)
31−
32− Label {
33− id: seeMoreLabel
34− objectName: "seeMoreLabel"
35− text: i18n.tr("See more")
36− opacity: !more ? 0.8 : 0.4
37− // TODO: Fix requiring Palette update
38− color: "grey" //Theme.palette.selected.backgroundText
39− font.weight: Font.Bold
40−
41− MouseArea {
42− anchors.fill: parent
43− onClicked: more = true
44− }
45− }
46−
47− Image {
48− anchors {
49− top: parent.top
50− bottom: parent.bottom
51− }
52− width: units.dp(2)
53− source: "ListItems/graphics/ListItemDividerVertical.png"
54− }
55−
56− Label {
57− objectName: "seeLessLabel"
58− text: i18n.tr("See less")
59− opacity: more ? 0.8 : 0.4
60− // TODO: Fix requiring Palette update
61− color: "grey" //Theme.palette.selected.backgroundText
62− font.weight: Font.Bold
63−
64− MouseArea {
65− anchors.fill: parent
66− onClicked: more = false
67− }
68− }
69− }
70−}
qml/Components/graphics/pagination_dot_off@30.pngnew file

Binary file not shown.

qml/Components/graphics/pagination_dot_on@30.pngnew file

Binary file not shown.

qml/Dash/CardTool.qml+1−1
@@ -126,7 +126,7 @@ Item {
126 type:real \brief Height of the card's header.
126 type:real \brief Height of the card's header.
127 */
127 */
128 readonly property int headerHeight: cardLoader.item ? cardLoader.item.headerHeight : 0
128 readonly property int headerHeight: cardLoader.item ? cardLoader.item.headerHeight : 0
129− readonly property size artShapeSize: cardLoader.item ? cardLoader.item.artShapeSize : 0
129+ property size artShapeSize: cardLoader.item ? cardLoader.item.artShapeSize : 0
130
130
131 /*!
131 /*!
132 \brief Desired alignment of header components.
132 \brief Desired alignment of header components.
qml/Dash/Dash.qml+92−11
@@ -14,10 +14,11 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
15 */
16
16
17−import QtQuick 2.0
17+import QtQuick 2.2
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19import Unity 0.2
19import Unity 0.2
20import Utils 0.1
20import Utils 0.1
21+import Unity.DashCommunicator 0.1
21import "../Components"
22import "../Components"
22
23
23Showable {
24Showable {
@@ -29,8 +30,21 @@ Showable {
29 property string showScopeOnLoaded: "clickscope"
30 property string showScopeOnLoaded: "clickscope"
30 property real contentScale: 1.0
31 property real contentScale: 1.0
31
32
33+ DashCommunicatorService {
34+ objectName: "dashCommunicatorService"
35+ onSetCurrentScopeRequested: {
36+ dash.setCurrentScope(scopeId, animate, reset)
37+ }
38+ }
39+
32 function setCurrentScope(scopeId, animate, reset) {
40 function setCurrentScope(scopeId, animate, reset) {
33− var scopeIndex = filteredScopes.findFirst(Scopes.RoleId, scopeId)
41+ var scopeIndex = -1;
42+ for (var i = 0; i < scopes.count; ++i) {
43+ if (scopes.getScope(i).id == scopeId) {
44+ scopeIndex = i;
45+ break;
46+ }
47+ }
34
48
35 if (scopeIndex == -1) {
49 if (scopeIndex == -1) {
36 console.warn("No match for scope with id: %1".arg(scopeId))
50 console.warn("No match for scope with id: %1".arg(scopeId))
@@ -55,15 +69,16 @@ Showable {
55 }
69 }
56 }
70 }
57
71
58− SortFilterProxyModel {
59− id: filteredScopes
60− model: Scopes {
72+ Scopes {
61− id: scopes
73+ id: scopes
62− }
74+ }
63− dynamicSortFilter: true
64
75
65− filterRole: Scopes.RoleVisible
76+ Image {
66− filterRegExp: RegExp("^true$")
77+ anchors.fill: parent
78+ source: parent.width > parent.height ? "graphics/paper_landscape.png" : "graphics/paper_portrait.png"
79+ fillMode: Image.PreserveAspectCrop
80+ horizontalAlignment: Image.AlignRight
81+ verticalAlignment: Image.AlignTop
67 }
82 }
68
83
69 DashContent {
84 DashContent {
@@ -71,7 +86,6 @@ Showable {
71 objectName: "dashContent"
86 objectName: "dashContent"
72 width: parent.width
87 width: parent.width
73 height: parent.height
88 height: parent.height
74− model: filteredScopes
75 scopes: scopes
89 scopes: scopes
76 visible: x != -width
90 visible: x != -width
77 onGotoScope: {
91 onGotoScope: {
@@ -126,4 +140,71 @@ Showable {
126 }
140 }
127 }
141 }
128 }
142 }
143+
144+ Rectangle {
145+ id: indicator
146+ objectName: "processingIndicator"
147+ anchors {
148+ left: parent.left
149+ right: parent.right
150+ bottom: parent.bottom
151+ }
152+ height: units.dp(3)
153+ color: scopeStyle.backgroundLuminance > 0.7 ? "#50000000" : "#50ffffff"
154+ opacity: 0
155+ visible: opacity > 0
156+
157+ readonly property bool processing: dashContent.processing || scopeItem.processing
158+
159+ Behavior on opacity {
160+ UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration }
161+ }
162+
163+ onProcessingChanged: {
164+ if (processing) delay.start();
165+ else if (!persist.running) indicator.opacity = 0;
166+ }
167+
168+ Timer {
169+ id: delay
170+ interval: 200
171+ onTriggered: if (indicator.processing) {
172+ persist.restart();
173+ indicator.opacity = 1;
174+ }
175+ }
176+
177+ Timer {
178+ id: persist
179+ interval: 2 * UbuntuAnimation.SleepyDuration - UbuntuAnimation.FastDuration
180+ onTriggered: if (!indicator.processing) indicator.opacity = 0
181+ }
182+
183+ Rectangle {
184+ id: orange
185+ anchors { top: parent.top; bottom: parent.bottom }
186+ width: parent.width / 4
187+ color: Theme.palette.selected.foreground
188+
189+ SequentialAnimation {
190+ running: indicator.visible
191+ loops: Animation.Infinite
192+ XAnimator {
193+ from: -orange.width / 2
194+ to: indicator.width - orange.width / 2
195+ duration: UbuntuAnimation.SleepyDuration
196+ easing.type: Easing.InOutSine
197+ target: orange
198+ }
199+ XAnimator {
200+ from: indicator.width - orange.width / 2
201+ to: -orange.width / 2
202+ duration: UbuntuAnimation.SleepyDuration
203+ easing.type: Easing.InOutSine
204+ target: orange
205+ }
206+ }
207+ }
208+ }
209+
129}
210}
qml/Dash/DashApplication.qmlnew file+36
@@ -0,0 +1,36 @@
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 Ubuntu.Components 1.0
19+import Ubuntu.Thumbnailer 0.1 // Register support for image://thumbnailer/ and image://albumart/
20+
21+MainView {
22+ width: units.gu(40)
23+ height: units.gu(71)
24+
25+ useDeprecatedToolbar: false
26+
27+ Binding {
28+ target: i18n
29+ property: "domain"
30+ value: "unity8"
31+ }
32+
33+ Dash {
34+ anchors.fill: parent
35+ }
36+}
qml/Dash/DashContent.qml+7−4
@@ -23,9 +23,10 @@ import "../Components"
23Item {
23Item {
24 id: dashContent
24 id: dashContent
25
25
26− property var model: null
26+ property alias scopes: dashContentList.model
27− property var scopes: null
28 readonly property alias currentIndex: dashContentList.currentIndex
27 readonly property alias currentIndex: dashContentList.currentIndex
28+ readonly property bool processing: dashContentList.currentItem && dashContentList.currentItem.item
29+ && dashContentList.currentItem.item.processing || false
29
30
30 signal scopeLoaded(string scopeId)
31 signal scopeLoaded(string scopeId)
31 signal gotoScope(string scopeId)
32 signal gotoScope(string scopeId)
@@ -89,10 +90,9 @@ Item {
89 id: dashContentList
90 id: dashContentList
90 objectName: "dashContentList"
91 objectName: "dashContentList"
91
92
92− interactive: dashContent.scopes.loaded && currentItem && !currentItem.moving
93+ interactive: dashContent.scopes.loaded && currentItem && !currentItem.moving && !currentItem.navigationShown
93
94
94 anchors.fill: parent
95 anchors.fill: parent
95− model: dashContent.model
96 orientation: ListView.Horizontal
96 orientation: ListView.Horizontal
97 boundsBehavior: Flickable.DragAndOvershootBounds
97 boundsBehavior: Flickable.DragAndOvershootBounds
98 flickDeceleration: units.gu(625)
98 flickDeceleration: units.gu(625)
@@ -130,6 +130,7 @@ Item {
130 objectName: scope.id + " loader"
130 objectName: scope.id + " loader"
131
131
132 readonly property bool moving: item ? item.moving : false
132 readonly property bool moving: item ? item.moving : false
133+ readonly property bool navigationShown: item ? item.navigationShown : false
133 readonly property var categoryView: item ? item.categoryView : null
134 readonly property var categoryView: item ? item.categoryView : null
134 readonly property var theScope: scope
135 readonly property var theScope: scope
135
136
@@ -143,6 +144,8 @@ Item {
143 item.scope = Qt.binding(function() { return scope })
144 item.scope = Qt.binding(function() { return scope })
144 item.isCurrent = Qt.binding(function() { return visible && ListView.isCurrentItem })
145 item.isCurrent = Qt.binding(function() { return visible && ListView.isCurrentItem })
145 dashContent.scopeLoaded(item.scope.id)
146 dashContent.scopeLoaded(item.scope.id)
147+ item.paginationCount = Qt.binding(function() { return dashContentList.count } )
148+ item.paginationIndex = Qt.binding(function() { return dashContentList.currentIndex } )
146 }
149 }
147 Connections {
150 Connections {
148 target: isCurrent ? scope : null
151 target: isCurrent ? scope : null
qml/Dash/DashDepartments.qml → qml/Dash/DashNavigation.qmlrenamed+50−43
@@ -15,17 +15,17 @@
15 */
15 */
16
16
17import QtQuick 2.2
17import QtQuick 2.2
18−import Ubuntu.Components 0.1
18+import Ubuntu.Components 1.1
19
19
20AbstractButton {
20AbstractButton {
21 id: root
21 id: root
22− objectName: "dashDepartments"
22+ objectName: "dashNavigation"
23
23
24 property var scope: null
24 property var scope: null
25
25
26 property bool showList: false
26 property bool showList: false
27
27
28− readonly property var currentDepartment: scope && scope.hasDepartments ? scope.getDepartment(scope.currentDepartmentId) : null
28+ readonly property var currentNavigation: scope && scope.hasNavigation ? scope.getNavigation(scope.currentNavigationId) : null
29
29
30 property alias windowWidth: blackRect.width
30 property alias windowWidth: blackRect.width
31 property alias windowHeight: blackRect.height
31 property alias windowHeight: blackRect.height
@@ -34,20 +34,21 @@ AbstractButton {
34 // Are we drilling down the tree or up?
34 // Are we drilling down the tree or up?
35 property bool isGoingBack: false
35 property bool isGoingBack: false
36
36
37− visible: root.currentDepartment != null
37+ visible: root.currentNavigation != null
38
38
39 height: visible ? units.gu(5) : 0
39 height: visible ? units.gu(5) : 0
40
40
41 onClicked: {
41 onClicked: {
42+ navigationListView.updateMaxHeight();
42 root.showList = !root.showList;
43 root.showList = !root.showList;
43 }
44 }
44
45
45 Rectangle {
46 Rectangle {
46 id: blackRect
47 id: blackRect
47 color: "black"
48 color: "black"
48− opacity: departmentListView.currentItem && departmentListView.currentItem.visible ? 0.3 : 0
49+ opacity: navigationListView.currentItem && navigationListView.currentItem.visible ? 0.3 : 0
49 Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
50 Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
50− anchors.top: departmentListView.top
51+ anchors.top: navigationListView.top
51 anchors.right: parent.right
52 anchors.right: parent.right
52 visible: opacity != 0
53 visible: opacity != 0
53 }
54 }
@@ -78,7 +79,7 @@ AbstractButton {
78 anchors.fill: parent
79 anchors.fill: parent
79 anchors.margins: units.gu(2)
80 anchors.margins: units.gu(2)
80 verticalAlignment: Text.AlignVCenter
81 verticalAlignment: Text.AlignVCenter
81− text: root.currentDepartment ? root.currentDepartment.label : ""
82+ text: root.currentNavigation ? root.currentNavigation.label : ""
82 color: root.scopeStyle ? root.scopeStyle.foreground : "grey"
83 color: root.scopeStyle ? root.scopeStyle.foreground : "grey"
83 }
84 }
84
85
@@ -92,18 +93,18 @@ AbstractButton {
92 color: root.scopeStyle ? root.scopeStyle.foreground : "grey"
93 color: root.scopeStyle ? root.scopeStyle.foreground : "grey"
93 }
94 }
94
95
95− // departmentListView is outside root
96+ // navigationListView is outside root
96 ListView {
97 ListView {
97− id: departmentListView
98+ id: navigationListView
98− objectName: "departmentListView"
99+ objectName: "navigationListView"
99 orientation: ListView.Horizontal
100 orientation: ListView.Horizontal
100 interactive: false
101 interactive: false
101 clip: root.width != windowWidth
102 clip: root.width != windowWidth
102 model: ListModel {
103 model: ListModel {
103− id: departmentModel
104+ id: navigationModel
104 // We have two roles
105 // We have two roles
105− // departmentId: the department id of the department the list represents
106+ // navigationId: the navigation id of the navigation the list represents
106− // nullifyDepartment: overrides departmentId to be null
107+ // nullifyNavigation: overrides navigationId to be null
107 // This is used to "clear" the delegate when going "right" on the tree
108 // This is used to "clear" the delegate when going "right" on the tree
108 }
109 }
109 anchors {
110 anchors {
@@ -111,7 +112,12 @@ AbstractButton {
111 right: parent.right
112 right: parent.right
112 top: root.bottom
113 top: root.bottom
113 }
114 }
115+ property int maxHeight: -1
116+ Component.onCompleted: updateMaxHeight();
117+ function updateMaxHeight()
118+ {
114− readonly property int maxHeight: (windowHeight - mapToItem(null, root.x, root.y).y) - units.gu(8)
119+ maxHeight = (windowHeight - mapToItem(null, 0, 0).y) - units.gu(8);
120+ }
115 property int prevHeight: maxHeight
121 property int prevHeight: maxHeight
116 height: currentItem ? currentItem.height : maxHeight
122 height: currentItem ? currentItem.height : maxHeight
117 onHeightChanged: {
123 onHeightChanged: {
@@ -120,83 +126,84 @@ AbstractButton {
120 }
126 }
121 }
127 }
122 highlightMoveDuration: UbuntuAnimation.FastDuration
128 highlightMoveDuration: UbuntuAnimation.FastDuration
123− delegate: DashDepartmentsList {
129+ delegate: DashNavigationList {
124− objectName: "department" + index
130+ objectName: "navigation" + index
125 visible: height != 0
131 visible: height != 0
126− width: departmentListView.width
132+ width: navigationListView.width
127 scopeStyle: root.scopeStyle
133 scopeStyle: root.scopeStyle
128 property real desiredHeight: {
134 property real desiredHeight: {
129 if (root.showList) {
135 if (root.showList) {
130− if (department && department.loaded && x == departmentListView.contentX)
136+ if (navigation && navigation.loaded && x == navigationListView.contentX)
131 {
137 {
138+ navigationListView.updateMaxHeight();
132− return Math.min(implicitHeight, departmentListView.maxHeight);
139+ return Math.min(implicitHeight, navigationListView.maxHeight);
133 } else {
140 } else {
134− return departmentListView.prevHeight;
141+ return navigationListView.prevHeight;
135 }
142 }
136 } else {
143 } else {
137 return 0;
144 return 0;
138 }
145 }
139 }
146 }
140 height: desiredHeight
147 height: desiredHeight
141− department: (nullifyDepartment || !scope) ? null : scope.getDepartment(departmentId)
148+ navigation: (nullifyNavigation || !scope) ? null : scope.getNavigation(navigationId)
142− currentDepartment: root.currentDepartment
149+ currentNavigation: root.currentNavigation
143− onEnterDepartment: {
150+ onEnterNavigation: {
144− scope.loadDepartment(newDepartmentId);
151+ scope.setNavigationState(newNavigationId, false);
145 // We only need to add a new item to the model
152 // We only need to add a new item to the model
146 // if we have children, otherwise just load it
153 // if we have children, otherwise just load it
147 if (hasChildren) {
154 if (hasChildren) {
148 isGoingBack = false;
155 isGoingBack = false;
149− departmentModel.append({"departmentId": newDepartmentId, "nullifyDepartment": false});
156+ navigationModel.append({"navigationId": newNavigationId, "nullifyNavigation": false});
150− departmentListView.currentIndex++;
157+ navigationListView.currentIndex++;
151 } else {
158 } else {
152 showList = false;
159 showList = false;
153 }
160 }
154 }
161 }
155 onGoBackToParentClicked: {
162 onGoBackToParentClicked: {
156− scope.loadDepartment(department.parentDepartmentId);
163+ scope.setNavigationState(navigation.parentNavigationId, false);
157 isGoingBack = true;
164 isGoingBack = true;
158− departmentModel.setProperty(departmentListView.currentIndex - 1, "nullifyDepartment", false);
165+ navigationModel.setProperty(navigationListView.currentIndex - 1, "nullifyNavigation", false);
159− departmentListView.currentIndex--;
166+ navigationListView.currentIndex--;
160 }
167 }
161− onAllDepartmentClicked: {
168+ onAllNavigationClicked: {
162 showList = false;
169 showList = false;
163− if (root.currentDepartment.parentDepartmentId == department.departmentId) {
170+ if (root.currentNavigation.parentNavigationId == navigation.navigationId) {
164 // For leaves we have to go to the parent too
171 // For leaves we have to go to the parent too
165− scope.loadDepartment(root.currentDepartment.parentDepartmentId);
172+ scope.setNavigationState(root.currentNavigation.parentNavigationId, false);
166 }
173 }
167 }
174 }
168 }
175 }
169 onContentXChanged: {
176 onContentXChanged: {
170− if (contentX == width * departmentListView.currentIndex) {
177+ if (contentX == width * navigationListView.currentIndex) {
171 if (isGoingBack) {
178 if (isGoingBack) {
172− departmentModel.remove(departmentListView.currentIndex + 1);
179+ navigationModel.remove(navigationListView.currentIndex + 1);
173 } else {
180 } else {
174− departmentModel.setProperty(departmentListView.currentIndex - 1, "nullifyDepartment", true);
181+ navigationModel.setProperty(navigationListView.currentIndex - 1, "nullifyNavigation", true);
175 }
182 }
176 }
183 }
177 }
184 }
178 }
185 }
179
186
180 InverseMouseArea {
187 InverseMouseArea {
181− anchors.fill: departmentListView
188+ anchors.fill: navigationListView
182 enabled: root.showList
189 enabled: root.showList
183 onClicked: root.showList = false
190 onClicked: root.showList = false
184 }
191 }
185
192
186 onScopeChanged: {
193 onScopeChanged: {
187− departmentModel.clear();
194+ navigationModel.clear();
188− if (scope && scope.hasDepartments) {
195+ if (scope && scope.hasNavigation) {
189− departmentModel.append({"departmentId": scope.currentDepartmentId, "nullifyDepartment": false});
196+ navigationModel.append({"navigationId": scope.currentNavigationId, "nullifyNavigation": false});
190 }
197 }
191 }
198 }
192
199
193 Connections {
200 Connections {
194 target: scope
201 target: scope
195− onHasDepartmentsChanged: {
202+ onHasNavigationChanged: {
196− if (scope.hasDepartments) {
203+ if (scope.hasNavigation) {
197− departmentModel.append({"departmentId": scope.currentDepartmentId, "nullifyDepartment": false});
204+ navigationModel.append({"navigationId": scope.currentNavigationId, "nullifyNavigation": false});
198 } else {
205 } else {
199− departmentModel.clear();
206+ navigationModel.clear();
200 }
207 }
201 }
208 }
202 }
209 }
qml/Dash/DashDepartmentsList.qml → qml/Dash/DashNavigationList.qmlrenamed+14−18
@@ -15,16 +15,16 @@
15 */
15 */
16
16
17import QtQuick 2.2
17import QtQuick 2.2
18−import Ubuntu.Components 0.1
18+import Ubuntu.Components 1.1
19
19
20Item {
20Item {
21 id: root
21 id: root
22− property var department: null
22+ property var navigation: null
23− property var currentDepartment: null
23+ property var currentNavigation: null
24 property var scopeStyle: null
24 property var scopeStyle: null
25− signal enterDepartment(var newDepartmentId, bool hasChildren)
25+ signal enterNavigation(var newNavigationId, bool hasChildren)
26 signal goBackToParentClicked()
26 signal goBackToParentClicked()
27− signal allDepartmentClicked()
27+ signal allNavigationClicked()
28
28
29 readonly property int itemHeight: units.gu(5)
29 readonly property int itemHeight: units.gu(5)
30 readonly property color foregroundColor: root.scopeStyle ? root.scopeStyle.foreground : "grey"
30 readonly property color foregroundColor: root.scopeStyle ? root.scopeStyle.foreground : "grey"
@@ -35,11 +35,6 @@ Item {
35 anchors.fill: parent
35 anchors.fill: parent
36 }
36 }
37
37
38− ActivityIndicator {
39− id: loadingIndicator
40− anchors.centerIn: parent
41− running: !(department && department.loaded)
42− }
43 clip: true
38 clip: true
44
39
45 Behavior on height {
40 Behavior on height {
@@ -54,6 +49,7 @@ Item {
54
49
55 anchors.fill: parent
50 anchors.fill: parent
56
51
52+ flickableDirection: Flickable.VerticalFlick
57 contentHeight: column.height
53 contentHeight: column.height
58 contentWidth: width
54 contentWidth: width
59
55
@@ -68,7 +64,7 @@ Item {
68 id: backButton
64 id: backButton
69 objectName: "backButton"
65 objectName: "backButton"
70 width: parent.width
66 width: parent.width
71− visible: department && !department.isRoot || false
67+ visible: navigation && !navigation.isRoot || false
72 height: itemHeight
68 height: itemHeight
73
69
74 onClicked: root.goBackToParentClicked();
70 onClicked: root.goBackToParentClicked();
@@ -92,7 +88,7 @@ Item {
92 left: backImage.right
88 left: backImage.right
93 leftMargin: units.gu(0.5)
89 leftMargin: units.gu(0.5)
94 }
90 }
95− text: department ? department.parentLabel : ""
91+ text: navigation ? navigation.parentLabel : ""
96 color: root.foregroundColor
92 color: root.foregroundColor
97 }
93 }
98
94
@@ -114,7 +110,7 @@ Item {
114 id: allButton
110 id: allButton
115 objectName: "allButton"
111 objectName: "allButton"
116 width: parent.width
112 width: parent.width
117− visible: department && (!department.isRoot || (root.currentDepartment && !root.currentDepartment.isRoot && root.currentDepartment.parentDepartmentId == department.departmentId)) || false
113+ visible: navigation && (!navigation.isRoot || (root.currentNavigation && !root.currentNavigation.isRoot && root.currentNavigation.parentNavigationId == navigation.navigationId)) || false
118 height: itemHeight
114 height: itemHeight
119
115
120 Label {
116 Label {
@@ -123,7 +119,7 @@ Item {
123 left: parent.left
119 left: parent.left
124 leftMargin: units.gu(2)
120 leftMargin: units.gu(2)
125 }
121 }
126− text: department ? (department.allLabel != "" ? department.allLabel : department.label) : ""
122+ text: navigation ? (navigation.allLabel != "" ? navigation.allLabel : navigation.label) : ""
127 font.bold: true
123 font.bold: true
128 color: root.foregroundColor
124 color: root.foregroundColor
129 }
125 }
@@ -141,18 +137,18 @@ Item {
141 height: units.dp(1)
137 height: units.dp(1)
142 }
138 }
143
139
144− onClicked: root.allDepartmentClicked();
140+ onClicked: root.allNavigationClicked();
145 }
141 }
146
142
147 Repeater {
143 Repeater {
148− model: department && department.loaded ? department : null
144+ model: navigation && navigation.loaded ? navigation : null
149 clip: true
145 clip: true
150 delegate: AbstractButton {
146 delegate: AbstractButton {
151 objectName: root.objectName + "child" + index
147 objectName: root.objectName + "child" + index
152 height: root.itemHeight
148 height: root.itemHeight
153 width: root.width
149 width: root.width
154
150
155− onClicked: root.enterDepartment(departmentId, hasChildren)
151+ onClicked: root.enterNavigation(navigationId, hasChildren)
156
152
157 Label {
153 Label {
158 anchors {
154 anchors {
@@ -188,7 +184,7 @@ Item {
188 color: root.foregroundColor
184 color: root.foregroundColor
189 opacity: 0.1
185 opacity: 0.1
190 height: units.dp(1)
186 height: units.dp(1)
191− visible: index != department.count - 1
187+ visible: index != navigation.count - 1
192 }
188 }
193 }
189 }
194 }
190 }
qml/Dash/GenericScopeView.qml+12−12
@@ -25,6 +25,7 @@ import "../Components/ListItems" as ListItems
25FocusScope {
25FocusScope {
26 id: scopeView
26 id: scopeView
27
27
28+ readonly property alias navigationShown: dashNavigation.showList
28 property var scope: null
29 property var scope: null
29 property SortFilterProxyModel categories: categoryFilter
30 property SortFilterProxyModel categories: categoryFilter
30 property bool isCurrent: false
31 property bool isCurrent: false
@@ -32,22 +33,16 @@ FocusScope {
32 property bool hasBackAction: false
33 property bool hasBackAction: false
33 property bool enableHeightBehaviorOnNextCreation: false
34 property bool enableHeightBehaviorOnNextCreation: false
34 property var categoryView: categoryView
35 property var categoryView: categoryView
36+ property alias paginationCount: pageHeader.paginationCount
37+ property alias paginationIndex: pageHeader.paginationIndex
35
38
36 property var scopeStyle: ScopeStyle {
39 property var scopeStyle: ScopeStyle {
37 style: scope ? scope.customizations : {}
40 style: scope ? scope.customizations : {}
38 }
41 }
39
42
40− signal backClicked()
43+ readonly property bool processing: scope ? scope.searchInProgress || previewListView.processing : false
41−
42− onScopeChanged: {
43− if (scope) {
44− scope.activateApplication.connect(activateApp);
45− }
46− }
47
44
48− function activateApp(appId) {
45+ signal backClicked()
49− shell.activateApplication(appId);
50− }
51
46
52 function positionAtBeginning() {
47 function positionAtBeginning() {
53 categoryView.positionAtBeginning()
48 categoryView.positionAtBeginning()
@@ -119,6 +114,7 @@ FocusScope {
119 model: scopeView.categories
114 model: scopeView.categories
120 forceNoClip: previewListView.open
115 forceNoClip: previewListView.open
121 pixelAligned: true
116 pixelAligned: true
117+ interactive: !dashNavigation.showList
122
118
123 property string expandedCategoryId: ""
119 property string expandedCategoryId: ""
124
120
@@ -211,6 +207,10 @@ FocusScope {
211 baseItem.expand(shouldExpand, false /*animate*/);
207 baseItem.expand(shouldExpand, false /*animate*/);
212 }
208 }
213 updateDelegateCreationRange();
209 updateDelegateCreationRange();
210+ if (scope && scope.id === "clickscope" && (categoryId === "predefined" || categoryId === "local")) {
211+ // Yeah, hackish :/
212+ cardTool.artShapeSize = Qt.size(units.gu(8), units.gu(7.5));
213+ }
214 item.cardTool = cardTool;
214 item.cardTool = cardTool;
215 }
215 }
216
216
@@ -387,10 +387,10 @@ FocusScope {
387 title: scopeView.scope ? scopeView.scope.name : ""
387 title: scopeView.scope ? scopeView.scope.name : ""
388 showBackButton: scopeView.hasBackAction
388 showBackButton: scopeView.hasBackAction
389 searchEntryEnabled: true
389 searchEntryEnabled: true
390− searchInProgress: scopeView.scope ? scopeView.scope.searchInProgress : false
391 scopeStyle: scopeView.scopeStyle
390 scopeStyle: scopeView.scopeStyle
392
391
393− bottomItem: DashDepartments {
392+ bottomItem: DashNavigation {
393+ id: dashNavigation
394 scope: scopeView.scope
394 scope: scopeView.scope
395 width: parent.width <= units.gu(60) ? parent.width : units.gu(40)
395 width: parent.width <= units.gu(60) ? parent.width : units.gu(40)
396 anchors.right: parent.right
396 anchors.right: parent.right
qml/Dash/PreviewListView.qml+23−27
@@ -32,6 +32,9 @@ Item {
32 property alias currentItem: previewListView.currentItem
32 property alias currentItem: previewListView.currentItem
33 property alias count: previewListView.count
33 property alias count: previewListView.count
34
34
35+ readonly property bool processing: currentItem && (!currentItem.previewModel.loaded
36+ || currentItem.previewModel.processingAction)
37+
35 PageHeader {
38 PageHeader {
36 id: header
39 id: header
37 objectName: "pageHeader"
40 objectName: "pageHeader"
@@ -83,39 +86,32 @@ Item {
83 }
86 }
84 }
87 }
85
88
86− delegate: Item {
89+ delegate: Previews.Preview {
90+ id: preview
87− objectName: "previewItem" + index
91+ objectName: "preview" + index
88 height: previewListView.height
92 height: previewListView.height
89 width: previewListView.width
93 width: previewListView.width
90
94
91− readonly property bool ready: preview.previewModel.loaded
95+ isCurrent: ListView.isCurrentItem
92−
93− Previews.Preview {
94− id: preview
95− objectName: "preview" + index
96− anchors.fill: parent
97
96
98− isCurrent: parent.ListView.isCurrentItem
99−
100− previewModel: {
97+ previewModel: {
101− var previewStack = root.scope.preview(result);
98+ var previewStack = root.scope.preview(result);
102− return previewStack.getPreviewModel(0);
99+ return previewStack.getPreviewModel(0);
103− }
104− scopeStyle: root.scopeStyle
105 }
100 }
101+ scopeStyle: root.scopeStyle
102+ }
103+ }
106
104
107− MouseArea {
105+ MouseArea {
108− id: processingMouseArea
106+ id: processingMouseArea
109− objectName: "processingMouseArea"
107+ objectName: "processingMouseArea"
110− anchors.fill: parent
108+ anchors {
111− enabled: !preview.previewModel.loaded || preview.previewModel.processingAction
109+ left: parent.left
112−
110+ right: parent.right
113− ActivityIndicator {
111+ top: pageHeader.bottom
114− anchors.centerIn: parent
112+ bottom: parent.bottom
115− visible: root.open && parent.enabled
116− running: visible
117− }
118− }
119 }
113 }
114+
115+ enabled: root.processing
120 }
116 }
121}
117}
qml/Dash/Previews/PreviewExpandable.qmlnew file+101
@@ -0,0 +1,101 @@
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.3
18+import Ubuntu.Components 1.1
19+import "../../Components"
20+
21+/*! \brief Preview widget for expandable widgets.
22+
23+ This widget shows a list of widgets defined in widgetData["widgets"]
24+ Those widgets can be collapsed or uncollapsed. When uncollapsed
25+ all the widgets are shown, when collapsed only the first
26+ widgetData["collapsed-widgets"] are shown. It has a title that comes
27+ in via widgetData["title"]
28+ */
29+
30+PreviewWidget {
31+ id: root
32+ implicitHeight: childrenRect.height
33+
34+ expanded: false
35+
36+ Label {
37+ id: titleLabel
38+ objectName: "titleLabel"
39+ anchors {
40+ left: parent.left
41+ right: expandButton.left
42+ }
43+ fontSize: "large"
44+ color: root.scopeStyle ? root.scopeStyle.foreground : "grey"
45+ visible: text !== ""
46+ opacity: .8
47+ text: widgetData["title"] || ""
48+ wrapMode: Text.Wrap
49+ }
50+
51+ AbstractButton {
52+ id: expandButton
53+ objectName: "expandButton"
54+ width: titleLabel.height
55+ height: titleLabel.height
56+ anchors.right: parent.right
57+ onClicked: {
58+ root.expanded = !root.expanded;
59+ }
60+ Icon {
61+ anchors.fill: parent
62+ width: 64
63+ height: 64
64+ name: root.expanded ? "view-collapse" : "view-expand"
65+ }
66+ }
67+
68+ Column {
69+ anchors {
70+ top: titleLabel.bottom
71+ topMargin: units.gu(1)
72+ left: parent.left
73+ right: parent.right
74+ }
75+ spacing: units.gu(1)
76+ Repeater {
77+ id: repeater
78+ objectName: "repeater"
79+ model: widgetData["widgets"]
80+ delegate: PreviewWidgetFactory {
81+ height: visible ? implicitHeight : 0
82+ width: parent.width
83+ widgetId: modelData.widgetId
84+ widgetType: modelData.type
85+ widgetData: modelData.properties
86+ isCurrentPreview: root.isCurrentPreview
87+ scopeStyle: root.scopeStyle
88+ anchors {
89+ left: parent.left
90+ right: parent.right
91+ }
92+ expanded: root.expanded
93+ visible: root.expanded || index < root.widgetData["collapsed-widgets"]
94+
95+ onTriggered: {
96+ root.triggered(widgetId, actionId, data);
97+ }
98+ }
99+ }
100+ }
101+}
qml/Dash/Previews/PreviewImageGallery.qml+1
@@ -15,6 +15,7 @@
15 */
15 */
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18+import Ubuntu.Components 1.1
18import "../../Components"
19import "../../Components"
19
20
20/*! This preview widget shows a horizontal list of images.
21/*! This preview widget shows a horizontal list of images.
qml/Dash/Previews/PreviewTextSummary.qml+3−16
@@ -23,7 +23,7 @@ import "../../Components"
23 This widget shows text contained in widgetData["text"]
23 This widget shows text contained in widgetData["text"]
24 along with a title that comes from widgetData["title"].
24 along with a title that comes from widgetData["title"].
25
25
26− In case the text does not fit in 7 lines a See More / Less widget is also shown.
26+ In case the widget is collapsed it only shows 3 lines of text.
27 */
27 */
28
28
29PreviewWidget {
29PreviewWidget {
@@ -50,14 +50,14 @@ PreviewWidget {
50 id: textLabel
50 id: textLabel
51 objectName: "textLabel"
51 objectName: "textLabel"
52
52
53− readonly property int maximumCollapsedLineCount: 7
53+ readonly property int maximumCollapsedLineCount: 3
54
54
55 anchors {
55 anchors {
56 left: parent.left
56 left: parent.left
57 right: parent.right
57 right: parent.right
58 top: titleLabel.visible ? titleLabel.bottom : parent.top
58 top: titleLabel.visible ? titleLabel.bottom : parent.top
59 }
59 }
60− height: (!seeMore.visible || seeMore.more) ? contentHeight : contentHeight / lineCount * (maximumCollapsedLineCount - 2)
60+ height: (lineCount <= maximumCollapsedLineCount || root.expanded) ? contentHeight : contentHeight / lineCount * maximumCollapsedLineCount
61 clip: true
61 clip: true
62 fontSize: "small"
62 fontSize: "small"
63 lineHeight: 1.2
63 lineHeight: 1.2
@@ -70,17 +70,4 @@ PreviewWidget {
70 UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration }
70 UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration }
71 }
71 }
72 }
72 }
73−
74− SeeMore {
75− id: seeMore
76− objectName: "seeMore"
77− anchors {
78− left: parent.left
79− right: parent.right
80− top: textLabel.bottom
81− topMargin: visible ? units.gu(1) : 0
82− }
83− height: visible ? implicitHeight : 0
84− visible: textLabel.lineCount > textLabel.maximumCollapsedLineCount
85− }
86}
73}
qml/Dash/Previews/PreviewWidget.qml+3
@@ -31,6 +31,9 @@ Item {
31 //! The ScopeStyle component.
31 //! The ScopeStyle component.
32 property var scopeStyle: null
32 property var scopeStyle: null
33
33
34+ //! Should the widget show in expanded mode (For those that support it)
35+ property bool expanded: true
36+
34 /*! \brief This signal should be emitted when a preview action was triggered.
37 /*! \brief This signal should be emitted when a preview action was triggered.
35 *
38 *
36 * \param widgetId, actionId Respective identifiers from widgetData.
39 * \param widgetId, actionId Respective identifiers from widgetData.
qml/Dash/Previews/PreviewWidgetFactory.qml+5
@@ -34,6 +34,9 @@ Loader {
34 //! The ScopeStyle component.
34 //! The ScopeStyle component.
35 property var scopeStyle: null
35 property var scopeStyle: null
36
36
37+ //! Should the widget show in expanded mode (For those that support it)
38+ property bool expanded: true
39+
37 //! Set to true if the parent preview is displayed.
40 //! Set to true if the parent preview is displayed.
38 property bool isCurrentPreview: false
41 property bool isCurrentPreview: false
39
42
@@ -47,6 +50,7 @@ Loader {
47 switch (widgetType) {
50 switch (widgetType) {
48 case "actions": return "PreviewActions.qml";
51 case "actions": return "PreviewActions.qml";
49 case "audio": return "PreviewAudioPlayback.qml";
52 case "audio": return "PreviewAudioPlayback.qml";
53+ case "expandable": return "PreviewExpandable.qml";
50 case "gallery": return "PreviewImageGallery.qml";
54 case "gallery": return "PreviewImageGallery.qml";
51 case "header": return "PreviewHeader.qml";
55 case "header": return "PreviewHeader.qml";
52 case "image": return "PreviewZoomableImage.qml";
56 case "image": return "PreviewZoomableImage.qml";
@@ -65,6 +69,7 @@ Loader {
65 item.widgetId = Qt.binding(function() { return root.widgetId } )
69 item.widgetId = Qt.binding(function() { return root.widgetId } )
66 item.widgetData = Qt.binding(function() { return root.widgetData } )
70 item.widgetData = Qt.binding(function() { return root.widgetData } )
67 item.isCurrentPreview = Qt.binding(function() { return root.isCurrentPreview } )
71 item.isCurrentPreview = Qt.binding(function() { return root.isCurrentPreview } )
72+ item.expanded = Qt.binding(function() { return root.expanded } )
68 if (item.hasOwnProperty("scopeStyle")) item.scopeStyle = root.scopeStyle;
73 if (item.hasOwnProperty("scopeStyle")) item.scopeStyle = root.scopeStyle;
69 }
74 }
70
75
qml/Dash/ScopeListView.qml−5
@@ -20,9 +20,4 @@ import Dash 0.1
20ListViewWithPageHeader {
20ListViewWithPageHeader {
21 maximumFlickVelocity: height * 10
21 maximumFlickVelocity: height * 10
22 flickDeceleration: height * 2
22 flickDeceleration: height * 2
23−
24− Connections {
25− target: greeter
26− onShownChanged: if (greeter.shown) showHeader()
27− }
28}
23}
qml/Dash/graphics/phone/screenshots/unity8-dash@12.pngnew file

Binary file not shown.

qml/Greeter/Greeter.qml+1−1
@@ -70,7 +70,7 @@ Showable {
70 DraggingArea {
70 DraggingArea {
71 id: dragHandle
71 id: dragHandle
72 anchors.fill: parent
72 anchors.fill: parent
73− enabled: (greeter.narrowMode || !greeter.locked) && greeter.enabled
73+ enabled: (greeter.narrowMode || !greeter.locked) && greeter.enabled && greeter.shown
74 orientation: Qt.Horizontal
74 orientation: Qt.Horizontal
75 propagateComposedEvents: true
75 propagateComposedEvents: true
76
76
qml/Launcher/Launcher.qml+2−3
@@ -29,8 +29,7 @@ Item {
29 property int dragAreaWidth: units.gu(1)
29 property int dragAreaWidth: units.gu(1)
30 property int minimizeDistance: units.gu(26)
30 property int minimizeDistance: units.gu(26)
31 property real progress: dragArea.dragging && dragArea.touchX > panelWidth ?
31 property real progress: dragArea.dragging && dragArea.touchX > panelWidth ?
32− (width * (dragArea.touchX-panelWidth) / (width - panelWidth)) :
32+ (width * (dragArea.touchX-panelWidth) / (width - panelWidth)) : 0
33− (dragArea.dragging ? 0.001 : 0)
34
33
35 readonly property bool shown: panel.x > -panel.width
34 readonly property bool shown: panel.x > -panel.width
36
35
@@ -245,7 +244,7 @@ Item {
245 if (!dragging) {
244 if (!dragging) {
246 if (distance > panel.width / 2) {
245 if (distance > panel.width / 2) {
247 if (distance > minimizeDistance) {
246 if (distance > minimizeDistance) {
248− root.dash()
247+ root.dash();
249 } else {
248 } else {
250 root.switchToNextState("visible")
249 root.switchToNextState("visible")
251 }
250 }
qml/Notifications/NotificationMenuItemFactory.qml+3
@@ -76,6 +76,9 @@ Loader {
76 }
76 }
77 echoMode: checkBox.checked ? TextInput.Normal : TextInput.Password
77 echoMode: checkBox.checked ? TextInput.Normal : TextInput.Password
78 height: units.gu(5)
78 height: units.gu(5)
79+ Component.onCompleted: {
80+ forceActiveFocus();
81+ }
79 onTextChanged: {
82 onTextChanged: {
80 menuModel.changeState(menuIndex, text);
83 menuModel.changeState(menuIndex, text);
81 }
84 }
qml/Panel/Indicators/MenuItemFactory.qml+74
@@ -57,6 +57,7 @@ Item {
57
57
58 "unity.widgets.systemsettings.tablet.wifisection" : wifiSection,
58 "unity.widgets.systemsettings.tablet.wifisection" : wifiSection,
59 "unity.widgets.systemsettings.tablet.accesspoint" : accessPoint,
59 "unity.widgets.systemsettings.tablet.accesspoint" : accessPoint,
60+ "com.canonical.indicator.network.modeminfoitem" : modeminfoitem,
60 }
61 }
61
62
62 function getExtendedProperty(object, propertyName, defaultValue) {
63 function getExtendedProperty(object, propertyName, defaultValue) {
@@ -374,6 +375,79 @@ Item {
374 }
375 }
375 }
376 }
376
377
378+ Component {
379+ id: modeminfoitem;
380+ ModemInfoItem {
381+ objectName: "modemInfoItem"
382+ property QtObject menuData: null
383+ property var menuModel: menuFactory.menuModel
384+ property int menuIndex: -1
385+ property var extendedData: menuData && menuData.ext || undefined
386+
387+ property var statusLabelAction: UnityMenuAction {
388+ model: menuModel
389+ index: menuIndex
390+ name: getExtendedProperty(extendedData, "xCanonicalModemStatusLabelAction", "")
391+ }
392+ statusText: statusLabelAction.valid ? statusLabelAction.state : ""
393+
394+ property var statusIconAction: UnityMenuAction {
395+ model: menuModel
396+ index: menuIndex
397+ name: getExtendedProperty(extendedData, "xCanonicalModemStatusIconAction", "")
398+ }
399+ statusIcon: statusIconAction.valid ? statusIconAction.state : ""
400+
401+ property var connectivityIconAction: UnityMenuAction {
402+ model: menuModel
403+ index: menuIndex
404+ name: getExtendedProperty(extendedData, "xCanonicalModemConnectivityIconAction", "")
405+ }
406+ connectivityIcon: connectivityIconAction.valid ? connectivityIconAction.state : ""
407+
408+ property var simIdentifierLabelAction: UnityMenuAction {
409+ model: menuModel
410+ index: menuIndex
411+ name: getExtendedProperty(extendedData, "xCanonicalModemSimIdentifierLabelAction", "")
412+ }
413+ simIdentifierText: simIdentifierLabelAction.valid ? simIdentifierLabelAction.state : ""
414+
415+ property var roamingAction: UnityMenuAction {
416+ model: menuModel
417+ index: menuIndex
418+ name: getExtendedProperty(extendedData, "xCanonicalModemRoamingAction", "")
419+ }
420+ roaming: roamingAction.valid ? roamingAction.state : false
421+
422+ property var unlockAction: UnityMenuAction {
423+ model: menuModel
424+ index: menuIndex
425+ name: getExtendedProperty(extendedData, "xCanonicalModemLockedAction", "")
426+ }
427+ onUnlock: {
428+ unlockAction.activate();
429+ }
430+ locked: unlockAction.valid ? unlockAction.state : false
431+
432+ onMenuModelChanged: {
433+ loadAttributes();
434+ }
435+ onMenuIndexChanged: {
436+ loadAttributes();
437+ }
438+
439+ function loadAttributes() {
440+ if (!menuModel || menuIndex == -1) return;
441+ menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-modem-status-label-action': 'string',
442+ 'x-canonical-modem-status-icon-action': 'string',
443+ 'x-canonical-modem-connectivity-icon-action': 'string',
444+ 'x-canonical-modem-sim-identifier-label-action': 'string',
445+ 'x-canonical-modem-roaming-action': 'string',
446+ 'x-canonical-modem-locked-action': 'string'});
447+ }
448+ }
449+ }
450+
377 Component {
451 Component {
378 id: messageItem
452 id: messageItem
379
453
qml/Panel/Indicators/ModemInfoItem.qmlnew file+111
@@ -0,0 +1,111 @@
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 Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import QtQuick.Layouts 1.1
19+import Ubuntu.Components 0.1
20+import Ubuntu.Components.ListItems 0.1 as ListItem
21+
22+ListItem.Empty {
23+ id: menu
24+ implicitHeight: mainColumn.implicitHeight
25+ + mainColumn.anchors.topMargin
26+ + mainColumn.anchors.bottomMargin
27+
28+ property alias statusIcon: statusIcon.name
29+ property alias statusText: labelStatus.text
30+ property alias connectivityIcon: iconConnectivity.name
31+ property alias simIdentifierText: labelSimIdentifier.text
32+ property bool locked : false
33+ property bool roaming: false
34+ signal unlock
35+
36+ ColumnLayout {
37+ id: mainColumn
38+ anchors.fill: parent
39+ anchors.margins: menu.__contentsMargins
40+ spacing: units.gu(0.5)
41+
42+ Label {
43+ id: labelSimIdentifier
44+ elide: Text.ElideRight
45+ visible: text !== ""
46+ font.bold: true
47+ opacity: menu.locked ? 0.6 : 1.0
48+ }
49+
50+ RowLayout {
51+ id: statusRow
52+ spacing: units.gu(1)
53+
54+ height: labelStatus.height
55+ width: parent.width
56+
57+ Label {
58+ id: labelStatus
59+ elide: Text.ElideRight
60+ opacity: 0.6
61+ }
62+
63+ RowLayout {
64+ spacing: 0.5
65+ height: parent.height
66+ Icon {
67+ id: statusIcon
68+ color: Theme.palette.selected.backgroundText
69+
70+ Layout.preferredHeight: parent.height
71+ Layout.preferredWidth: Layout.preferredHeight
72+
73+ visible: name !== ""
74+ }
75+
76+ Icon {
77+ id: iconConnectivity
78+ color: Theme.palette.selected.backgroundText
79+
80+ Layout.preferredHeight: parent.height
81+ Layout.preferredWidth: Layout.preferredHeight
82+
83+ visible: name !== ""
84+ }
85+ }
86+
87+ Item {
88+ // eat up all the excess space so that RoamingIndication
89+ // ends up to the far right
90+ Layout.fillWidth: true
91+ }
92+
93+ RoamingIndication {
94+ id: roamingIndication
95+ visible: menu.roaming
96+ Layout.fillHeight: true
97+ }
98+ }
99+
100+ Button {
101+ id: buttonUnlock
102+ objectName: "buttonUnlockSim"
103+ visible: menu.locked
104+
105+ text: i18n.tr("Unlock SIM")
106+ Layout.preferredWidth: implicitWidth + units.gu(5)
107+
108+ onTriggered: menu.unlock()
109+ }
110+ }
111+}
qml/Panel/Indicators/RoamingIndication.qmlnew file+40
@@ -0,0 +1,40 @@
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 Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import QtQuick.Layouts 1.1
19+import Ubuntu.Components 0.1
20+
21+RowLayout {
22+ spacing: units.gu(0.5)
23+ Label {
24+ id: labelRoaming
25+ elide: Text.ElideRight
26+ fontSize: "x-small"
27+ text: i18n.tr("Roaming")
28+ opacity: 0.6
29+ }
30+
31+ Icon {
32+ id: iconRoaming
33+ color: Theme.palette.selected.backgroundText
34+
35+ Layout.preferredHeight: parent.height
36+ Layout.preferredWidth: Layout.preferredHeight
37+
38+ name: "network-cellular-roaming"
39+ }
40+}
qml/ScopeTool.qml+2−11
@@ -17,6 +17,7 @@
17import QtQuick 2.0
17import QtQuick 2.0
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19import Ubuntu.Components.Popups 0.1
19import Ubuntu.Components.Popups 0.1
20+import Ubuntu.Thumbnailer 0.1 // Register support for image://thumbnailer/ and image://albumart/
20import Utils 0.1
21import Utils 0.1
21import Unity 0.2
22import Unity 0.2
22import "Components"
23import "Components"
@@ -45,16 +46,6 @@ Rectangle {
45 signal searchClicked
46 signal searchClicked
46 }
47 }
47
48
48− SortFilterProxyModel {
49− id: filteredScopes
50− model: Scopes {
51− id: scopes
52− }
53− dynamicSortFilter: true
54−
55− filterRole: Scopes.RoleVisible
56− filterRegExp: RegExp("^true$")
57− }
58
49
59 Rectangle {
50 Rectangle {
60 anchors.fill: dashContent
51 anchors.fill: dashContent
@@ -72,8 +63,8 @@ Rectangle {
72 DashContent {
63 DashContent {
73 id: dashContent
64 id: dashContent
74
65
75− model: filteredScopes
76 property var scope: scopes.getScope(currentIndex)
66 property var scope: scopes.getScope(currentIndex)
67+ scopes: Scopes { }
77
68
78 anchors {
69 anchors {
79 top: parent.top
70 top: parent.top
qml/Shell.qml+28−153
@@ -25,7 +25,6 @@ import Utils 0.1
25import LightDM 0.1 as LightDM
25import LightDM 0.1 as LightDM
26import Powerd 0.1
26import Powerd 0.1
27import SessionBroadcast 0.1
27import SessionBroadcast 0.1
28−import "Dash"
29import "Greeter"
28import "Greeter"
30import "Launcher"
29import "Launcher"
31import "Panel"
30import "Panel"
@@ -34,6 +33,7 @@ import "Notifications"
34import "Stages"
33import "Stages"
35import Unity.Notifications 1.0 as NotificationBackend
34import Unity.Notifications 1.0 as NotificationBackend
36import Unity.Session 0.1
35import Unity.Session 0.1
36+import Unity.DashCommunicator 0.1
37
37
38Item {
38Item {
39 id: shell
39 id: shell
@@ -48,8 +48,6 @@ Item {
48 property url background
48 property url background
49 readonly property real panelHeight: panel.panelHeight
49 readonly property real panelHeight: panel.panelHeight
50
50
51− property bool dashShown: dash.shown && dash.available && underlay.visible
52−
53 property bool sideStageEnabled: shell.width >= units.gu(100)
51 property bool sideStageEnabled: shell.width >= units.gu(100)
54 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
52 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
55
53
@@ -59,7 +57,6 @@ Item {
59 } else {
57 } else {
60 var execFlags = shell.sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;
58 var execFlags = shell.sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;
61 ApplicationManager.startApplication(appId, execFlags);
59 ApplicationManager.startApplication(appId, execFlags);
62− stages.show();
63 }
60 }
64 }
61 }
65
62
@@ -86,6 +83,11 @@ Item {
86 id: volumeControl
83 id: volumeControl
87 }
84 }
88
85
86+ DashCommunicator {
87+ id: dash
88+ objectName: "dashCommunicator"
89+ }
90+
89 WindowKeysFilter {
91 WindowKeysFilter {
90 // Handle but do not filter out volume keys
92 // Handle but do not filter out volume keys
91 Keys.onVolumeUpPressed: { volumeControl.volumeUp(); event.accepted = false; }
93 Keys.onVolumeUpPressed: { volumeControl.volumeUp(); event.accepted = false; }
@@ -110,131 +112,12 @@ Item {
110 }
112 }
111 }
113 }
112
114
113− Item {
114− id: underlay
115− objectName: "underlay"
116− anchors.fill: parent
117−
118− // Whether the underlay is fully covered by opaque UI elements.
119− property bool fullyCovered: (panel.indicators.fullyOpened && shell.width <= panel.indicatorsMenuWidth)
120− || stages.fullyShown || greeterWrapper.fullyShown
121− visible: !fullyCovered
122−
123− Image {
124− anchors.fill: dash
125− source: shell.width > shell.height ? "Dash/graphics/paper_landscape.png" : "Dash/graphics/paper_portrait.png"
126− fillMode: Image.PreserveAspectCrop
127− horizontalAlignment: Image.AlignRight
128− verticalAlignment: Image.AlignTop
129− }
130−
131− Dash {
132− id: dash
133− objectName: "dash"
134−
135− available: !LightDM.Greeter.active
136− hides: [stages, launcher, panel.indicators]
137− shown: disappearingAnimationProgress !== 1.0 && greeterWrapper.showProgress !== 1.0 &&
138− !(panel.indicators.fullyOpened && !sideStageEnabled)
139− enabled: disappearingAnimationProgress === 0.0 && greeterWrapper.showProgress === 0.0 && edgeDemo.dashEnabled
140−
141− anchors {
142− fill: parent
143− topMargin: panel.panelHeight
144− }
145−
146− contentScale: 1.0 - 0.2 * disappearingAnimationProgress
147− opacity: 1.0 - disappearingAnimationProgress
148− property real disappearingAnimationProgress: stages.showProgress
149−
150− // FIXME: only necessary because stages.showProgress is not animated
151− Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }}
152− }
153− }
154−
155− EdgeDragArea {
156− id: stagesDragArea
157− direction: Direction.Leftwards
158−
159− anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
160− width: shell.edgeSize
161−
162− property real progress: stages.width
163−
164− onTouchXChanged: {
165− if (status == DirectionalDragArea.Recognized) {
166− if (ApplicationManager.empty) {
167− progress = Math.max(stages.width - stagesDragArea.width + touchX, stages.width * .3);
168− } else {
169− progress = stages.width - stagesDragArea.width + touchX;
170− }
171− }
172− }
173−
174− onDraggingChanged: {
175− if (!dragging) {
176− if (!ApplicationManager.empty && progress < stages.width - units.gu(10)) {
177− stages.show();
178− }
179− stagesDragArea.progress = Qt.binding(function () { return stages.width; });
180− }
181− }
182− }
183−
184 Item {
115 Item {
185 id: stages
116 id: stages
186 objectName: "stages"
117 objectName: "stages"
187 width: parent.width
118 width: parent.width
188 height: parent.height
119 height: parent.height
189−
190− visible: !fullyHidden && !ApplicationManager.empty
120+ visible: !ApplicationManager.empty
191−
192− x: {
193− if (shown) {
194− if (locked || greeter.fakeActiveForApp !== "") {
195− return 0;
196− }
197− return launcher.progress;
198− } else {
199− return stagesDragArea.progress
200− }
201− }
202− Behavior on x { SmoothedAnimation { velocity: 600; duration: UbuntuAnimation.FastDuration } }
203−
204− property bool shown: false
205− onShownChanged: {
206− if (shown) {
207− if (ApplicationManager.count > 0) {
208− ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
209− }
210− } else {
211− if (ApplicationManager.focusedApplicationId) {
212− ApplicationManager.updateScreenshot(ApplicationManager.focusedApplicationId);
213− ApplicationManager.unfocusCurrentApplication();
214− }
215− }
216− }
217−
218− // Avoid a silent "divide by zero -> NaN" situation during init as shell.width will be
219− // zero. That breaks the property binding and the function won't be reevaluated once
220− // shell.width is set, with the NaN result staying there for good.
221− property real showProgress: shell.width ? MathUtils.clamp(1 - x / shell.width, 0, 1) : 0
222−
223− property bool fullyShown: x == 0
224− property bool fullyHidden: x == width
225−
226− property bool locked: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.locked : false
227−
228− // It might technically not be fullyShown but visually it just looks so.
229− property bool roughlyFullyShown: x >= 0 && x <= units.gu(1)
230−
231− function show() {
232− shown = true;
233− }
234−
235− function hide() {
236− shown = false;
237− }
238
121
239 Connections {
122 Connections {
240 target: ApplicationManager
123 target: ApplicationManager
@@ -243,7 +126,6 @@ Item {
243 lockscreen.show();
126 lockscreen.show();
244 }
127 }
245 greeter.hide();
128 greeter.hide();
246− stages.show();
247 }
129 }
248
130
249 onFocusedApplicationIdChanged: {
131 onFocusedApplicationIdChanged: {
@@ -254,18 +136,9 @@ Item {
254 }
136 }
255
137
256 onApplicationAdded: {
138 onApplicationAdded: {
257− if (greeter.shown) {
139+ if (greeter.shown && appId != "unity8-dash") {
258 greeter.hide();
140 greeter.hide();
259 }
141 }
260− if (!stages.shown) {
261− stages.show();
262− }
263− }
264−
265− onEmptyChanged: {
266− if (ApplicationManager.empty) {
267− stages.hide();
268− }
269 }
142 }
270 }
143 }
271
144
@@ -294,13 +167,17 @@ Item {
294 Binding {
167 Binding {
295 target: applicationsDisplayLoader.item
168 target: applicationsDisplayLoader.item
296 property: "interactive"
169 property: "interactive"
297− value: stages.roughlyFullyShown && !greeter.shown && !lockscreen.shown
170+ value: edgeDemo.stagesEnabled && !greeter.shown && !lockscreen.shown && panel.indicators.fullyClosed && launcher.progress == 0
298− && panel.indicators.fullyClosed
299 }
171 }
300 Binding {
172 Binding {
301 target: applicationsDisplayLoader.item
173 target: applicationsDisplayLoader.item
302 property: "spreadEnabled"
174 property: "spreadEnabled"
303− value: greeter.fakeActiveForApp === "" // to support emergency dialer hack
175+ value: edgeDemo.stagesEnabled && greeter.fakeActiveForApp === "" // to support emergency dialer hack
176+ }
177+ Binding {
178+ target: applicationsDisplayLoader.item
179+ property: "inverseProgress"
180+ value: launcher.progress
304 }
181 }
305 }
182 }
306 }
183 }
@@ -504,7 +381,7 @@ Item {
504 onDisplayPowerStateChange: {
381 onDisplayPowerStateChange: {
505 // We ignore any display-off signals when the proximity sensor
382 // We ignore any display-off signals when the proximity sensor
506 // is active. This usually indicates something like a phone call.
383 // is active. This usually indicates something like a phone call.
507− if (status == Powerd.Off && reason != Powerd.Proximity) {
384+ if (status == Powerd.Off && reason != Powerd.Proximity && !edgeDemo.running) {
508 greeter.showNow();
385 greeter.showNow();
509 }
386 }
510
387
@@ -537,25 +414,20 @@ Item {
537
414
538 var animate = !LightDM.Greeter.active && !stages.shown
415 var animate = !LightDM.Greeter.active && !stages.shown
539 dash.setCurrentScope("clickscope", animate, false)
416 dash.setCurrentScope("clickscope", animate, false)
540− stages.hide()
417+ ApplicationManager.requestFocusApplication("unity8-dash")
541 }
418 }
542
419
543 function showDash() {
420 function showDash() {
544 if (LightDM.Greeter.active && !LightDM.Greeter.promptless) {
421 if (LightDM.Greeter.active && !LightDM.Greeter.promptless) {
545 return;
422 return;
546 }
423 }
547−
548− if (!stages.locked) {
549− stages.hide();
550− launcher.fadeOut();
551− } else {
552− launcher.switchToNextState("visible");
553− }
554−
555 if (greeter.shown) {
424 if (greeter.shown) {
556 greeter.hideRight();
425 greeter.hideRight();
557 launcher.fadeOut();
426 launcher.fadeOut();
558 }
427 }
428+
429+ ApplicationManager.requestFocusApplication("unity8-dash")
430+ launcher.fadeOut();
559 }
431 }
560
432
561 Item {
433 Item {
@@ -580,8 +452,8 @@ Item {
580 ApplicationManager.focusedApplicationId &&
452 ApplicationManager.focusedApplicationId &&
581 ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).fullscreen
453 ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).fullscreen
582
454
583− fullscreenMode: (stages.roughlyFullyShown && topmostApplicationIsFullscreen
455+ fullscreenMode: (topmostApplicationIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
584− && !LightDM.Greeter.active) || greeter.fakeActiveForApp !== ""
456+ || greeter.fakeActiveForApp !== ""
585 }
457 }
586
458
587 Launcher {
459 Launcher {
@@ -598,7 +470,11 @@ Item {
598
470
599 onShowDashHome: showHome()
471 onShowDashHome: showHome()
600 onDash: showDash()
472 onDash: showDash()
473+ onDashSwipeChanged: {
474+ if (dashSwipe && ApplicationManager.focusedApplicationId !== "unity8-dash") {
601− onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("clickscope", false, true)
475+ dash.setCurrentScope("clickscope", false, true)
476+ }
477+ }
602 onLauncherApplicationSelected: {
478 onLauncherApplicationSelected: {
603 if (greeter.fakeActiveForApp !== "") {
479 if (greeter.fakeActiveForApp !== "") {
604 lockscreen.show()
480 lockscreen.show()
@@ -690,9 +566,8 @@ Item {
690 z: alphaDisclaimerLabel.z + 10
566 z: alphaDisclaimerLabel.z + 10
691 greeter: greeter
567 greeter: greeter
692 launcher: launcher
568 launcher: launcher
693− dash: dash
694 indicators: panel.indicators
569 indicators: panel.indicators
695− underlay: underlay
570+ stages: stages
696 }
571 }
697
572
698 Connections {
573 Connections {
qml/Stages/AppSurfaceContainer.qmlnew file+96
@@ -0,0 +1,96 @@
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 Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+*/
16+
17+import QtQuick 2.0
18+import "Animations"
19+
20+SurfaceContainer {
21+ id: container
22+ property var promptSurfaces
23+
24+ property bool appHasCreatedASurface: false
25+
26+ onSurfaceChanged: {
27+ if (surface) {
28+ if (!appHasCreatedASurface) {
29+ surface.visible = false; // hide until splash screen removed
30+ appHasCreatedASurface = true;
31+ }
32+ }
33+ }
34+
35+ function revealSurface() {
36+ surface.visible = true;
37+ splashLoader.source = "";
38+ }
39+
40+ Timer { //FIXME - need to delay removing splash screen to allow surface resize to complete
41+ id: surfaceRevealDelay
42+ interval: 100
43+ onTriggered: surfaceContainer.revealSurface()
44+ }
45+
46+ Loader {
47+ z: 3
48+ id: splashLoader
49+ anchors.fill: parent
50+ }
51+
52+ Repeater {
53+ model: container.promptSurfaces
54+
55+ delegate: SurfaceContainer {
56+ anchors {
57+ fill: container
58+ topMargin: container.surface.anchors.topMargin
59+ rightMargin: container.surface.anchors.rightMargin
60+ bottomMargin: container.surface.anchors.bottomMargin
61+ leftMargin: container.surface.anchors.leftMargin
62+ }
63+
64+ z: 4 + index
65+ surface: modelData
66+
67+ Component.onCompleted: {
68+ animateIn();
69+ }
70+ }
71+ }
72+
73+ StateGroup {
74+ id: appSurfaceState
75+ states: [
76+ State {
77+ name: "noSurfaceYet"
78+ when: !surfaceContainer.appHasCreatedASurface
79+ StateChangeScript {
80+ script: { splashLoader.setSource("Splash.qml", { "name": model.name, "image": model.icon }); }
81+ }
82+ },
83+ State {
84+ name: "hasSurface"
85+ when: surfaceContainer.appHasCreatedASurface && (surfaceContainer.surface !== null)
86+ StateChangeScript { script: { surfaceRevealDelay.start(); } }
87+ },
88+ State {
89+ name: "surfaceLostButAppStillAlive"
90+ when: surfaceContainer.appHasCreatedASurface && (surfaceContainer.surface === null)
91+ // TODO - use app snapshot
92+ }
93+ ]
94+ state: "noSurfaceYet"
95+ }
96+}
qml/Stages/PhoneStage.qml+59−26
@@ -21,7 +21,7 @@ import Unity.Application 0.1
21import Utils 0.1
21import Utils 0.1
22import "../Components"
22import "../Components"
23
23
24−Item {
24+Rectangle {
25 id: root
25 id: root
26
26
27 // Controls to be set from outside
27 // Controls to be set from outside
@@ -29,9 +29,9 @@ Item {
29 property real maximizedAppTopMargin
29 property real maximizedAppTopMargin
30 property bool interactive
30 property bool interactive
31 property bool spreadEnabled: true // If false, animations and right edge will be disabled
31 property bool spreadEnabled: true // If false, animations and right edge will be disabled
32+ property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.
32
33
33− // State information propagated to the outside
34+ color: "black"
34− readonly property bool locked: spreadView.phase == 2
35
35
36 function select(appId) {
36 function select(appId) {
37 spreadView.snapTo(priv.indexOf(appId));
37 spreadView.snapTo(priv.indexOf(appId));
@@ -43,6 +43,16 @@ Item {
43 spreadView.contentX = -spreadView.shift;
43 spreadView.contentX = -spreadView.shift;
44 }
44 }
45
45
46+ onInverseProgressChanged: {
47+ if (inverseProgress == 0 && priv.oldInverseProgress > 0) {
48+ // left edge drag released. Minimum distance is given by design.
49+ if (priv.oldInverseProgress > units.gu(22)) {
50+ ApplicationManager.focusApplication("unity8-dash");
51+ }
52+ }
53+ priv.oldInverseProgress = inverseProgress;
54+ }
55+
46 Connections {
56 Connections {
47 target: ApplicationManager
57 target: ApplicationManager
48
58
@@ -50,7 +60,7 @@ Item {
50 if (spreadView.phase > 0) {
60 if (spreadView.phase > 0) {
51 spreadView.snapTo(priv.indexOf(appId));
61 spreadView.snapTo(priv.indexOf(appId));
52 } else {
62 } else {
53− priv.switchToApp(appId);
63+ ApplicationManager.focusApplication(appId);
54 }
64 }
55 }
65 }
56
66
@@ -60,7 +70,7 @@ Item {
60 } else {
70 } else {
61 spreadView.phase = 0;
71 spreadView.phase = 0;
62 spreadView.contentX = -spreadView.shift;
72 spreadView.contentX = -spreadView.shift;
63− priv.switchToApp(appId);
73+ ApplicationManager.focusApplication(appId);
64 }
74 }
65 }
75 }
66
76
@@ -79,15 +89,11 @@ Item {
79
89
80 property string focusedAppId: ApplicationManager.focusedApplicationId
90 property string focusedAppId: ApplicationManager.focusedApplicationId
81 property var focusedApplication: ApplicationManager.findApplication(focusedAppId)
91 property var focusedApplication: ApplicationManager.findApplication(focusedAppId)
92+ property var focusedAppDelegate: null
82
93
83− function switchToApp(appId) {
94+ property real oldInverseProgress: 0
84− if (priv.focusedAppId) {
95+
85− spreadView.focusChanging = true;
96+ onFocusedAppIdChanged: focusedAppDelegate = spreadRepeater.itemAt(0);
86− ApplicationManager.focusApplication(appId);
87− } else {
88− ApplicationManager.focusApplication(appId);
89− }
90− }
91
97
92 function indexOf(appId) {
98 function indexOf(appId) {
93 for (var i = 0; i < ApplicationManager.count; i++) {
99 for (var i = 0; i < ApplicationManager.count; i++) {
@@ -100,14 +106,6 @@ Item {
100
106
101 }
107 }
102
108
103− Rectangle {
104− id: coverFlipBackground
105− anchors.fill: parent
106− color: "black"
107− visible: spreadView.visible
108− }
109−
110−
111 Flickable {
109 Flickable {
112 id: spreadView
110 id: spreadView
113 objectName: "spreadView"
111 objectName: "spreadView"
@@ -116,6 +114,10 @@ Item {
116 contentWidth: spreadRow.width - shift
114 contentWidth: spreadRow.width - shift
117 contentX: -shift
115 contentX: -shift
118
116
117+ // This indicates when the spreadView is active. That means, all the animations
118+ // are activated and tiles need to line up for the spread.
119+ readonly property bool active: shiftedContentX > 0 || spreadDragArea.dragging
120+
119 // The flickable needs to fill the screen in order to get touch events all over.
121 // The flickable needs to fill the screen in order to get touch events all over.
120 // However, we don't want to the user to be able to scroll back all the way. For
122 // However, we don't want to the user to be able to scroll back all the way. For
121 // that, the beginning of the gesture starts with a negative value for contentX
123 // that, the beginning of the gesture starts with a negative value for contentX
@@ -198,6 +200,12 @@ Item {
198 snapAnimation.start();
200 snapAnimation.start();
199 }
201 }
200
202
203+ // In case the ApplicationManager already holds an app when starting up we're missing animations
204+ // Make sure we end up in the same state
205+ Component.onCompleted: {
206+ spreadView.contentX = -spreadView.shift
207+ }
208+
201 SequentialAnimation {
209 SequentialAnimation {
202 id: snapAnimation
210 id: snapAnimation
203 property int targetContentX: -spreadView.shift
211 property int targetContentX: -spreadView.shift
@@ -260,14 +268,33 @@ Item {
260 && spreadView.shiftedContentX === 0 && root.interactive && index === 0
268 && spreadView.shiftedContentX === 0 && root.interactive && index === 0
261 swipeToCloseEnabled: spreadView.interactive
269 swipeToCloseEnabled: spreadView.interactive
262 maximizedAppTopMargin: root.maximizedAppTopMargin
270 maximizedAppTopMargin: root.maximizedAppTopMargin
263− dropShadow: spreadView.shiftedContentX > 0 || spreadDragArea.status == DirectionalDragArea.Undecided
271+ dropShadow: spreadView.active ||
272+ priv.focusedAppDelegate.x !== 0
273+
274+ readonly property bool isDash: model.appId == "unity8-dash"
275+
276+ z: isDash && !spreadView.active ? -1 : behavioredIndex
264
277
265− z: behavioredIndex
278+ x: {
279+ // focused app is always positioned at 0 except when following left edge drag
280+ if (index == 0) {
281+ if (!isDash && root.inverseProgress > 0) {
282+ return root.inverseProgress;
283+ }
284+ return 0;
285+ }
286+ if (isDash && !spreadView.active && !spreadDragArea.dragging) {
287+ return 0;
288+ }
289+
290+ // Otherwise line up for the spread
266− x: index == 0 ? 0 : spreadView.width + (index - 1) * spreadView.tileDistance
291+ return spreadView.width + (index - 1) * spreadView.tileDistance;
292+ }
267 property real behavioredIndex: index
293 property real behavioredIndex: index
268 Behavior on behavioredIndex {
294 Behavior on behavioredIndex {
269 enabled: spreadView.closingIndex >= 0
295 enabled: spreadView.closingIndex >= 0
270 UbuntuNumberAnimation {
296 UbuntuNumberAnimation {
297+ id: appXAnimation
271 onRunningChanged: {
298 onRunningChanged: {
272 if (!running) {
299 if (!running) {
273 spreadView.closingIndex = -1;
300 spreadView.closingIndex = -1;
@@ -277,11 +304,13 @@ Item {
277 }
304 }
278
305
279 Behavior on x {
306 Behavior on x {
280− enabled: spreadView.focusChanging && index == 0 && root.spreadEnabled
307+ enabled: root.spreadEnabled &&
308+ !spreadView.active &&
309+ !snapAnimation.running
281 UbuntuNumberAnimation {
310 UbuntuNumberAnimation {
282 duration: UbuntuAnimation.FastDuration
311 duration: UbuntuAnimation.FastDuration
283 onRunningChanged: {
312 onRunningChanged: {
284− if (!running) {
313+ if (!running && root.inverseProgress == 0) {
285 spreadView.focusChanging = false;
314 spreadView.focusChanging = false;
286 }
315 }
287 }
316 }
@@ -322,6 +351,10 @@ Item {
322 return progress;
351 return progress;
323 }
352 }
324
353
354+ // Hiding tiles when their progress is negative or reached the maximum
355+ visible: (progress >= 0 && progress < 1.7) ||
356+ (isDash && priv.focusedAppDelegate.x !== 0)
357+
325 EasingCurve {
358 EasingCurve {
326 id: snappingCurve
359 id: snappingCurve
327 type: EasingCurve.Linear
360 type: EasingCurve.Linear
qml/Stages/SpreadDelegate.qml+8−52
@@ -35,25 +35,12 @@ Item {
35 signal clicked()
35 signal clicked()
36 signal closed()
36 signal closed()
37
37
38− SurfaceContainer {
38+ AppSurfaceContainer {
39 id: surfaceContainer
39 id: surfaceContainer
40+ objectName: "surfaceContainer"
40 anchors.fill: parent
41 anchors.fill: parent
41 surface: model.surface
42 surface: model.surface
42− property bool appHasCreatedASurface: false
43+ promptSurfaces: model.application.promptSurfaces
43−
44− onSurfaceChanged: {
45− if (surface) {
46− if (!appHasCreatedASurface) {
47− surface.visible = false; // hide until splash screen removed
48− appHasCreatedASurface = true;
49− }
50− }
51− }
52−
53− function revealSurface() {
54− surface.visible = true;
55− splashLoader.source = "";
56− }
57
44
58 Binding {
45 Binding {
59 target: surfaceContainer.surface
46 target: surfaceContainer.surface
@@ -74,12 +61,6 @@ Item {
74 value: root.interactive
61 value: root.interactive
75 }
62 }
76
63
77− Timer { //FIXME - need to delay removing splash screen to allow surface resize to complete
78− id: surfaceRevealDelay
79− interval: 100
80− onTriggered: surfaceContainer.revealSurface()
81− }
82−
83 Connections {
64 Connections {
84 target: surface
65 target: surface
85 // FIXME: I would rather not need to do this, but currently it doesn't get
66 // FIXME: I would rather not need to do this, but currently it doesn't get
@@ -114,36 +95,6 @@ Item {
114 }
95 }
115 }
96 }
116
97
117−
118− StateGroup {
119− id: appSurfaceState
120− states: [
121− State {
122− name: "noSurfaceYet"
123− when: !surfaceContainer.appHasCreatedASurface
124− StateChangeScript {
125− script: { splashLoader.setSource("Splash.qml", { "name": model.name, "image": model.icon }); }
126− }
127− },
128− State {
129− name: "hasSurface"
130− when: surfaceContainer.appHasCreatedASurface && (surfaceContainer.surface !== null)
131− StateChangeScript { script: { surfaceRevealDelay.start(); } }
132− },
133− State {
134− name: "surfaceLostButAppStillAlive"
135− when: surfaceContainer.appHasCreatedASurface && (surfaceContainer.surface === null)
136− // TODO - use app snapshot
137− }
138− ]
139− state: "noSurfaceYet"
140− }
141−
142− Loader {
143− id: splashLoader
144− anchors.fill: surfaceContainer
145− }
146−
147 DraggingArea {
98 DraggingArea {
148 id: dragArea
99 id: dragArea
149 anchors.fill: parent
100 anchors.fill: parent
@@ -172,6 +123,11 @@ Item {
172 }
123 }
173
124
174 onDragEnd: {
125 onDragEnd: {
126+ if (model.appId == "unity8-dash") {
127+ animation.animate("center")
128+ return;
129+ }
130+
175 // velocity and distance values specified by design prototype
131 // velocity and distance values specified by design prototype
176 if ((dragVelocity < -units.gu(40) && distance < -units.gu(8)) || distance < -root.height / 2) {
132 if ((dragVelocity < -units.gu(40) && distance < -units.gu(8)) || distance < -root.height / 2) {
177 animation.animate("up")
133 animation.animate("up")
qml/Stages/SurfaceContainer.qml+5−22
@@ -40,19 +40,12 @@ Item {
40 childSurfaces[i].removed();
40 childSurfaces[i].removed();
41 }
41 }
42
42
43− //if we don't have children, nothing will tell us to animate out, so do it.
44− if (childSurfaces.length === 0) {
45− animateOut();
46− }
47− // tell our parent to animate out.
48− if (surface.parentSurface) {
49− surface.parentSurface.parent.animateOut();
43+ animateOut();
50− }
51 }
44 }
52 }
45 }
53
46
54 Repeater {
47 Repeater {
55− model: container.surface ? container.surface.childSurfaces : 0
48+ model: surface.childSurfaces
56
49
57 delegate: Loader {
50 delegate: Loader {
58 z: 2
51 z: 2
@@ -68,14 +61,13 @@ Item {
68 source: Qt.resolvedUrl("SurfaceContainer.qml")
61 source: Qt.resolvedUrl("SurfaceContainer.qml")
69 onLoaded: {
62 onLoaded: {
70 item.surface = modelData;
63 item.surface = modelData;
71− item.animateIn(swipeFromBottom);
64+ item.animateIn();
72− container.animateIn(swipeUp);
73 }
65 }
74 }
66 }
75 }
67 }
76
68
77− function animateIn(component) {
69+ function animateIn() {
78− var animation = component.createObject(container, { "surface": container.surface });
70+ var animation = swipeFromBottom.createObject(container, { "surface": container.surface });
79 animation.start();
71 animation.start();
80
72
81 var tmp = d.animations;
73 var tmp = d.animations;
@@ -104,20 +96,11 @@ Item {
104 id: swipeFromBottom
96 id: swipeFromBottom
105 SwipeFromBottomAnimation {}
97 SwipeFromBottomAnimation {}
106 }
98 }
107− Component {
108− id: swipeUp
109− SwipeUpAnimation {}
110− }
111− Component {
112− id: darkenFade
113− DarkenAndFadeInAnimation {}
114− }
115
99
116 states: [
100 states: [
117 State {
101 State {
118 name: "initial"
102 name: "initial"
119 PropertyChanges { target: surface; anchors.fill: container }
103 PropertyChanges { target: surface; anchors.fill: container }
120 }
104 }
121− // TODO: more animations!
122 ]
105 ]
123}
106}
qml/Stages/TabletStage.qml+85−41
@@ -21,10 +21,11 @@ import Unity.Application 0.1
21import Utils 0.1
21import Utils 0.1
22import "../Components"
22import "../Components"
23
23
24−Item {
24+Rectangle {
25 id: root
25 id: root
26 objectName: "stages"
26 objectName: "stages"
27 anchors.fill: parent
27 anchors.fill: parent
28+ color: "black"
28
29
29 // Controls to be set from outside
30 // Controls to be set from outside
30 property bool shown: false
31 property bool shown: false
@@ -32,9 +33,17 @@ Item {
32 property int dragAreaWidth
33 property int dragAreaWidth
33 property real maximizedAppTopMargin
34 property real maximizedAppTopMargin
34 property bool interactive
35 property bool interactive
36+ property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.
35
37
36− // State information propagated to the outside
38+ onInverseProgressChanged: {
37− readonly property bool locked: spreadView.phase == 2
39+ if (inverseProgress == 0 && priv.oldInverseProgress > 0) {
40+ // left edge drag released. Minimum distance is given by design.
41+ if (priv.oldInverseProgress > units.gu(22)) {
42+ ApplicationManager.focusApplication("unity8-dash");
43+ }
44+ }
45+ priv.oldInverseProgress = inverseProgress;
46+ }
38
47
39 QtObject {
48 QtObject {
40 id: priv
49 id: priv
@@ -49,6 +58,8 @@ Item {
49 property string appId0
58 property string appId0
50 property string appId1
59 property string appId1
51
60
61+ property int oldInverseProgress: 0
62+
52 onFocusedAppIdChanged: {
63 onFocusedAppIdChanged: {
53 if (priv.focusedAppId.length > 0) {
64 if (priv.focusedAppId.length > 0) {
54 var focusedApp = ApplicationManager.findApplication(focusedAppId);
65 var focusedApp = ApplicationManager.findApplication(focusedAppId);
@@ -107,16 +118,26 @@ Item {
107 }
118 }
108 }
119 }
109
120
121+ onApplicationAdded: {
122+ if (spreadView.phase == 2) {
123+ spreadView.snapTo(ApplicationManager.count - 1);
124+ } else {
125+ spreadView.phase = 0;
126+ spreadView.contentX = -spreadView.shift;
127+ ApplicationManager.focusApplication(appId);
128+ }
129+ }
130+
110 onApplicationRemoved: {
131 onApplicationRemoved: {
111 if (priv.mainStageAppId == appId) {
132 if (priv.mainStageAppId == appId) {
112− priv.mainStageAppId = "";
133+ ApplicationManager.focusApplication("unity8-dash")
113 }
134 }
114 if (priv.sideStageAppId == appId) {
135 if (priv.sideStageAppId == appId) {
115 priv.sideStageAppId = "";
136 priv.sideStageAppId = "";
116 }
137 }
117 if (ApplicationManager.count == 0) {
138 if (ApplicationManager.count == 0) {
118 spreadView.phase = 0;
139 spreadView.phase = 0;
119− spreadView.contentX = 0;
140+ spreadView.contentX = -spreadView.shift;
120 }
141 }
121 }
142 }
122 }
143 }
@@ -124,13 +145,26 @@ Item {
124 Flickable {
145 Flickable {
125 id: spreadView
146 id: spreadView
126 anchors.fill: parent
147 anchors.fill: parent
127− contentWidth: spreadRow.width
128 interactive: (spreadDragArea.status == DirectionalDragArea.Recognized || phase > 1) && draggedIndex == -1
148 interactive: (spreadDragArea.status == DirectionalDragArea.Recognized || phase > 1) && draggedIndex == -1
149+ contentWidth: spreadRow.width - shift
150+ contentX: -shift
129
151
130 property int tileDistance: units.gu(20)
152 property int tileDistance: units.gu(20)
131 property int sideStageWidth: units.gu(40)
153 property int sideStageWidth: units.gu(40)
132 property bool sideStageVisible: priv.sideStageAppId
154 property bool sideStageVisible: priv.sideStageAppId
133
155
156+ // This indicates when the spreadView is active. That means, all the animations
157+ // are activated and tiles need to line up for the spread.
158+ readonly property bool active: shiftedContentX > 0 || spreadDragArea.dragging
159+
160+ // The flickable needs to fill the screen in order to get touch events all over.
161+ // However, we don't want to the user to be able to scroll back all the way. For
162+ // that, the beginning of the gesture starts with a negative value for contentX
163+ // so the flickable wants to pull it into the view already. "shift" tunes the
164+ // distance where to "lock" the content.
165+ readonly property real shift: width / 2
166+ readonly property real shiftedContentX: contentX + shift
167+
134 // Phase of the animation:
168 // Phase of the animation:
135 // 0: Starting from right edge, a new app (index 1) comes in from the right
169 // 0: Starting from right edge, a new app (index 1) comes in from the right
136 // 1: The app has reached the first snap position.
170 // 1: The app has reached the first snap position.
@@ -168,6 +202,12 @@ Item {
168 }
202 }
169 }
203 }
170
204
205+ // In case the ApplicationManager already holds an app when starting up we're missing animations
206+ // Make sure we end up in the same state
207+ Component.onCompleted: {
208+ spreadView.contentX = -spreadView.shift
209+ }
210+
171 property int nextInStack: {
211 property int nextInStack: {
172 switch (state) {
212 switch (state) {
173 case "main":
213 case "main":
@@ -224,31 +264,31 @@ Item {
224 return "empty";
264 return "empty";
225 }
265 }
226
266
227− onContentXChanged: {
267+ onShiftedContentXChanged: {
228− if (spreadView.phase == 0 && spreadView.contentX > spreadView.width * spreadView.positionMarker2) {
268+ if (spreadView.phase == 0 && spreadView.shiftedContentX > spreadView.width * spreadView.positionMarker2) {
229 spreadView.phase = 1;
269 spreadView.phase = 1;
230− } else if (spreadView.phase == 1 && spreadView.contentX > spreadView.width * spreadView.positionMarker4) {
270+ } else if (spreadView.phase == 1 && spreadView.shiftedContentX > spreadView.width * spreadView.positionMarker4) {
231 spreadView.phase = 2;
271 spreadView.phase = 2;
232− } else if (spreadView.phase == 1 && spreadView.contentX < spreadView.width * spreadView.positionMarker2) {
272+ } else if (spreadView.phase == 1 && spreadView.shiftedContentX < spreadView.width * spreadView.positionMarker2) {
233 spreadView.phase = 0;
273 spreadView.phase = 0;
234 }
274 }
235 }
275 }
236
276
237 function snap() {
277 function snap() {
238− if (contentX < phase0Width) {
278+ if (shiftedContentX < phase0Width) {
239− snapAnimation.targetContentX = 0;
279+ snapAnimation.targetContentX = -shift;
240 snapAnimation.start();
280 snapAnimation.start();
241− } else if (contentX < phase1Width) {
281+ } else if (shiftedContentX < phase1Width) {
242 snapTo(1);
282 snapTo(1);
243 } else {
283 } else {
244 // Add 1 pixel to make sure we definitely hit positionMarker4 even with rounding errors of the animation.
284 // Add 1 pixel to make sure we definitely hit positionMarker4 even with rounding errors of the animation.
245− snapAnimation.targetContentX = spreadView.width * spreadView.positionMarker4 + 1;
285+ snapAnimation.targetContentX = spreadView.width * spreadView.positionMarker4 + 1 - shift;
246 snapAnimation.start();
286 snapAnimation.start();
247 }
287 }
248 }
288 }
249 function snapTo(index) {
289 function snapTo(index) {
250 spreadView.selectedIndex = index;
290 spreadView.selectedIndex = index;
251− snapAnimation.targetContentX = 0;
291+ snapAnimation.targetContentX = -shift;
252 snapAnimation.start();
292 snapAnimation.start();
253 }
293 }
254
294
@@ -261,12 +301,12 @@ Item {
261 return index;
301 return index;
262 }
302 }
263
303
264− var isActive = app.appId == priv.mainStageAppId || app.appId == priv.sideStageAppId;
304+ var active = app.appId == priv.mainStageAppId || app.appId == priv.sideStageAppId;
265− if (isActive && app.stage == ApplicationInfoInterface.MainStage) {
305+ if (active && app.stage == ApplicationInfoInterface.MainStage) {
266 // if this app is active, and its the MainStage, always put it to index 0
306 // if this app is active, and its the MainStage, always put it to index 0
267 return 0;
307 return 0;
268 }
308 }
269− if (isActive && app.stage == ApplicationInfoInterface.SideStage) {
309+ if (active && app.stage == ApplicationInfoInterface.SideStage) {
270 if (!priv.mainStageAppId) {
310 if (!priv.mainStageAppId) {
271 // Only have SS apps running. Put the active one at 0
311 // Only have SS apps running. Put the active one at 0
272 return 0;
312 return 0;
@@ -309,7 +349,7 @@ Item {
309
349
310 SequentialAnimation {
350 SequentialAnimation {
311 id: snapAnimation
351 id: snapAnimation
312− property int targetContentX: 0
352+ property int targetContentX: -spreadView.shift
313
353
314 UbuntuNumberAnimation {
354 UbuntuNumberAnimation {
315 target: spreadView
355 target: spreadView
@@ -325,15 +365,14 @@ Item {
325 spreadView.selectedIndex = -1;
365 spreadView.selectedIndex = -1;
326 ApplicationManager.focusApplication(ApplicationManager.get(newIndex).appId);
366 ApplicationManager.focusApplication(ApplicationManager.get(newIndex).appId);
327 spreadView.phase = 0;
367 spreadView.phase = 0;
328− spreadView.contentX = 0;
368+ spreadView.contentX = -spreadView.shift;
329 }
369 }
330 }
370 }
331 }
371 }
332 }
372 }
333
373
334− Rectangle {
374+ Item {
335 id: spreadRow
375 id: spreadRow
336− color: "black"
337 x: spreadView.contentX
376 x: spreadView.contentX
338 height: root.height
377 height: root.height
339 width: spreadView.width + Math.max(spreadView.width, ApplicationManager.count * spreadView.tileDistance)
378 width: spreadView.width + Math.max(spreadView.width, ApplicationManager.count * spreadView.tileDistance)
@@ -380,7 +419,7 @@ Item {
380 MouseArea {
419 MouseArea {
381 id: sideStageDragHandleMouseArea
420 id: sideStageDragHandleMouseArea
382 anchors.fill: parent
421 anchors.fill: parent
383− enabled: spreadView.contentX == 0
422+ enabled: spreadView.shiftedContentX == 0
384 property int startX
423 property int startX
385 property var gesturePoints: new Array()
424 property var gesturePoints: new Array()
386
425
@@ -413,7 +452,7 @@ Item {
413
452
414 onRunningChanged: {
453 onRunningChanged: {
415 if (!running) {
454 if (!running) {
416− sideStageDragHandle.dragging = false;;
455+ sideStageDragHandle.dragging = false;
417 }
456 }
418 }
457 }
419 }
458 }
@@ -427,17 +466,26 @@ Item {
427 id: spreadTile
466 id: spreadTile
428 height: spreadView.height
467 height: spreadView.height
429 width: model.stage == ApplicationInfoInterface.MainStage ? spreadView.width : spreadView.sideStageWidth
468 width: model.stage == ApplicationInfoInterface.MainStage ? spreadView.width : spreadView.sideStageWidth
430− x: spreadView.width
431− z: spreadView.indexToZIndex(index)
432 active: model.appId == priv.mainStageAppId || model.appId == priv.sideStageAppId
469 active: model.appId == priv.mainStageAppId || model.appId == priv.sideStageAppId
433− zIndex: z
470+ zIndex: spreadView.indexToZIndex(index)
434 selected: spreadView.selectedIndex == index
471 selected: spreadView.selectedIndex == index
435 otherSelected: spreadView.selectedIndex >= 0 && !selected
472 otherSelected: spreadView.selectedIndex >= 0 && !selected
436 isInSideStage: priv.sideStageAppId == model.appId
473 isInSideStage: priv.sideStageAppId == model.appId
437 interactive: !spreadView.interactive && spreadView.phase === 0 && root.interactive
474 interactive: !spreadView.interactive && spreadView.phase === 0 && root.interactive
438 swipeToCloseEnabled: spreadView.interactive
475 swipeToCloseEnabled: spreadView.interactive
439 maximizedAppTopMargin: root.maximizedAppTopMargin
476 maximizedAppTopMargin: root.maximizedAppTopMargin
440− dropShadow: spreadView.contentX > 0 || spreadDragArea.status == DirectionalDragArea.Undecided
477+ dragOffset: !isDash && model.appId == priv.mainStageAppId && root.inverseProgress > 0 ? root.inverseProgress : 0
478+
479+ readonly property bool isDash: model.appId == "unity8-dash"
480+
481+ // FIXME: A regular binding doesn't update any more after closing an app.
482+ // Using a Binding for now.
483+ Binding {
484+ target: spreadTile
485+ property: "z"
486+ value: (!spreadView.active && isDash && !active) ? -1 : spreadTile.zIndex
487+ }
488+ x: spreadView.width
441
489
442 property real behavioredZIndex: zIndex
490 property real behavioredZIndex: zIndex
443 Behavior on behavioredZIndex {
491 Behavior on behavioredZIndex {
@@ -458,7 +506,7 @@ Item {
458 }
506 }
459
507
460 progress: {
508 progress: {
461− var tileProgress = (spreadView.contentX - behavioredZIndex * spreadView.tileDistance) / spreadView.width;
509+ var tileProgress = (spreadView.shiftedContentX - behavioredZIndex * spreadView.tileDistance) / spreadView.width;
462 // Some tiles (nextInStack, active) need to move directly from the beginning, normalize progress to immediately start at 0
510 // Some tiles (nextInStack, active) need to move directly from the beginning, normalize progress to immediately start at 0
463 if ((index == spreadView.nextInStack && spreadView.phase < 2) || (active && spreadView.phase < 1)) {
511 if ((index == spreadView.nextInStack && spreadView.phase < 2) || (active && spreadView.phase < 1)) {
464 tileProgress += behavioredZIndex * spreadView.tileDistance / spreadView.width;
512 tileProgress += behavioredZIndex * spreadView.tileDistance / spreadView.width;
@@ -481,11 +529,7 @@ Item {
481
529
482 onClicked: {
530 onClicked: {
483 if (spreadView.phase == 2) {
531 if (spreadView.phase == 2) {
484− if (ApplicationManager.focusedApplicationId == ApplicationManager.get(index).appId) {
485− spreadView.snapTo(index);
532+ spreadView.snapTo(index);
486− } else {
487− ApplicationManager.requestFocusApplication(ApplicationManager.get(index).appId);
488− }
489 }
533 }
490 }
534 }
491
535
@@ -518,12 +562,12 @@ Item {
518 onTouchXChanged: {
562 onTouchXChanged: {
519 if (!dragging) {
563 if (!dragging) {
520 spreadView.phase = 0;
564 spreadView.phase = 0;
521− spreadView.contentX = 0;
565+ spreadView.contentX = -spreadView.shift;
522 }
566 }
523
567
524− if (attachedToView) {
568+ if (dragging && attachedToView) {
525− spreadView.contentX = -touchX + spreadDragArea.width;
569+ spreadView.contentX = -touchX + spreadDragArea.width - spreadView.shift;
526− if (spreadView.contentX > spreadView.phase0Width + spreadView.phase1Width / 2) {
570+ if (spreadView.shiftedContentX > spreadView.phase0Width + spreadView.phase1Width / 2) {
527 attachedToView = false;
571 attachedToView = false;
528 spreadView.snap();
572 spreadView.snap();
529 }
573 }
@@ -548,14 +592,14 @@ Item {
548 var oneWayFlick = priv.evaluateOneWayFlick(gesturePoints);
592 var oneWayFlick = priv.evaluateOneWayFlick(gesturePoints);
549 gesturePoints = [];
593 gesturePoints = [];
550
594
551− if (oneWayFlick && spreadView.contentX < spreadView.positionMarker1 * spreadView.width) {
595+ if (oneWayFlick && spreadView.shiftedContentX < spreadView.positionMarker1 * spreadView.width) {
552 // If it was a short one-way movement, do the Alt+Tab switch
596 // If it was a short one-way movement, do the Alt+Tab switch
553 // no matter if we didn't cross positionMarker1 yet.
597 // no matter if we didn't cross positionMarker1 yet.
554 spreadView.snapTo(spreadView.nextInStack);
598 spreadView.snapTo(spreadView.nextInStack);
555 } else if (!dragging && attachedToView) {
599 } else if (!dragging && attachedToView) {
556− if (spreadView.contentX < spreadView.width * spreadView.positionMarker1) {
600+ if (spreadView.shiftedContentX < spreadView.width * spreadView.positionMarker1) {
557 spreadView.snap();
601 spreadView.snap();
558− } else if (spreadView.contentX < spreadView.width * spreadView.positionMarker2) {
602+ } else if (spreadView.shiftedContentX < spreadView.width * spreadView.positionMarker2) {
559 spreadView.snapTo(spreadView.nextInStack);
603 spreadView.snapTo(spreadView.nextInStack);
560 } else {
604 } else {
561 // otherwise snap to the closest snap position we can find
605 // otherwise snap to the closest snap position we can find
qml/Stages/TransformedSpreadDelegate.qml+6−5
@@ -46,9 +46,6 @@ SpreadDelegate {
46 property real startDistance: units.gu(5)
46 property real startDistance: units.gu(5)
47 property real endDistance: units.gu(.5)
47 property real endDistance: units.gu(.5)
48
48
49− // Hiding tiles when their progress is negative or reached the maximum
50− visible: progress >= 0 && progress < 1.7
51−
52 onSelectedChanged: {
49 onSelectedChanged: {
53 if (selected) {
50 if (selected) {
54 priv.snapshot();
51 priv.snapshot();
@@ -132,6 +129,10 @@ SpreadDelegate {
132 // the selected tile, which is animated from the snapshotted position to be fullscreen.
129 // the selected tile, which is animated from the snapshotted position to be fullscreen.
133
130
134 readonly property real xTranslate: {
131 readonly property real xTranslate: {
132+ if (!spreadView.active) {
133+ return 0;
134+ }
135+
135 if (otherSelected) {
136 if (otherSelected) {
136 if (spreadView.phase < 2 && index == 0) {
137 if (spreadView.phase < 2 && index == 0) {
137 return linearAnimation(selectedProgress, 0, selectedXTranslate,
138 return linearAnimation(selectedProgress, 0, selectedXTranslate,
@@ -183,7 +184,7 @@ SpreadDelegate {
183 }
184 }
184
185
185 readonly property real angle: {
186 readonly property real angle: {
186− if (spreadView.focusChanging) {
187+ if (!spreadView.active) {
187 return 0;
188 return 0;
188 }
189 }
189
190
@@ -216,7 +217,7 @@ SpreadDelegate {
216 }
217 }
217
218
218 readonly property real scale: {
219 readonly property real scale: {
219− if (spreadView.focusChanging) {
220+ if (!spreadView.active) {
220 return 1;
221 return 1;
221 }
222 }
222 if (priv.otherSelected) {
223 if (priv.otherSelected) {
qml/Stages/TransformedTabletSpreadDelegate.qml+28
@@ -47,6 +47,11 @@ SpreadDelegate {
47
47
48 property bool isInSideStage: false
48 property bool isInSideStage: false
49
49
50+ property int dragOffset: 0
51+
52+ dropShadow: spreadView.active ||
53+ (active && model.stage == ApplicationInfoInterface.MainStage && priv.xTranslate != 0)
54+
50 onSelectedChanged: {
55 onSelectedChanged: {
51 if (selected) {
56 if (selected) {
52 priv.snapshot();
57 priv.snapshot();
@@ -129,6 +134,16 @@ SpreadDelegate {
129 return helperEasingCurve.value * (endValue - startValue) + startValue;
134 return helperEasingCurve.value * (endValue - startValue) + startValue;
130 }
135 }
131
136
137+ Behavior on xTranslate {
138+ enabled: !spreadView.active &&
139+ !snapAnimation.running &&
140+ model.appId !== "unity8-dash" &&
141+ !spreadView.sideStageDragging
142+ UbuntuNumberAnimation {
143+ duration: UbuntuAnimation.FastDuration
144+ }
145+ }
146+
132 property real xTranslate: {
147 property real xTranslate: {
133 var newTranslate = 0;
148 var newTranslate = 0;
134
149
@@ -155,7 +170,12 @@ SpreadDelegate {
155 if (spreadView.phase == 0 && shouldMoveAway) {
170 if (spreadView.phase == 0 && shouldMoveAway) {
156 newTranslate += linearAnimation(0, spreadView.positionMarker2, 0, -units.gu(4), root.animatedProgress);
171 newTranslate += linearAnimation(0, spreadView.positionMarker2, 0, -units.gu(4), root.animatedProgress);
157 }
172 }
173+ newTranslate += root.dragOffset;
174+ }
175+ if (!spreadView.active && model.appId == "unity8-dash" && !root.active) {
176+ newTranslate -= root.width;
158 }
177 }
178+
159 if (nextInStack && spreadView.phase == 0) {
179 if (nextInStack && spreadView.phase == 0) {
160 if (model.stage == ApplicationInfoInterface.MainStage) {
180 if (model.stage == ApplicationInfoInterface.MainStage) {
161 if (spreadView.sideStageVisible && root.progress > 0) {
181 if (spreadView.sideStageVisible && root.progress > 0) {
@@ -205,6 +225,10 @@ SpreadDelegate {
205 }
225 }
206
226
207 property real scale: {
227 property real scale: {
228+ if (!spreadView.active) {
229+ return 1;
230+ }
231+
208 if (otherSelected) {
232 if (otherSelected) {
209 return selectedScale;
233 return selectedScale;
210 }
234 }
@@ -249,6 +273,10 @@ SpreadDelegate {
249 }
273 }
250
274
251 property real angle: {
275 property real angle: {
276+ if (!spreadView.active) {
277+ return 0;
278+ }
279+
252 if (otherSelected) {
280 if (otherSelected) {
253 return selectedAngle;
281 return selectedAngle;
254 }
282 }
run_on_device.sh+1−3
@@ -2,7 +2,6 @@
2CODE_DIR=shell
2CODE_DIR=shell
3USER=phablet
3USER=phablet
4USER_ID=32011
4USER_ID=32011
5−PASSWORD=phablet
6PACKAGE=unity8
5PACKAGE=unity8
7BINARY=unity8
6BINARY=unity8
8TARGET_IP=${TARGET_IP-127.0.0.1}
7TARGET_IP=${TARGET_IP-127.0.0.1}
@@ -13,7 +12,6 @@ SETUP=false
13GDB=false
12GDB=false
14PINLOCK=false
13PINLOCK=false
15KEYLOCK=false
14KEYLOCK=false
16−SUDO="echo $PASSWORD | sudo -S"
17NUM_JOBS='$(( `grep -c ^processor /proc/cpuinfo` + 1 ))'
15NUM_JOBS='$(( `grep -c ^processor /proc/cpuinfo` + 1 ))'
18FLIPPED=false
16FLIPPED=false
19CHROOT_PREFIX="/data/ubuntu"
17CHROOT_PREFIX="/data/ubuntu"
@@ -76,7 +74,7 @@ setup_adb_forwarding() {
76
74
77install_dependencies() {
75install_dependencies() {
78 exec_with_adb apt-get update
76 exec_with_adb apt-get update
79− exec_with_ssh $SUDO apt-get -y install build-essential rsync bzr ccache gdb ninja-build devscripts equivs unity-plugin-scopes
77+ exec_with_adb apt-get -y --force-yes install build-essential rsync bzr ccache gdb ninja-build devscripts equivs unity-plugin-scopes
80}
78}
81
79
82sync_code() {
80sync_code() {
src/CMakeLists.txt+1
@@ -35,3 +35,4 @@ install(TARGETS ${SHELL_APP}
35 )
35 )
36
36
37add_subdirectory(Panel)
37add_subdirectory(Panel)
38+add_subdirectory(Dash)
src/Dash/CMakeLists.txtnew file+13
@@ -0,0 +1,13 @@
1+set(DASH_SRCS
2+ main.cpp
3+ ../MouseTouchAdaptor.cpp
4+)
5+
6+add_executable(unity8-dash ${DASH_SRCS})
7+
8+qt5_use_modules(unity8-dash Gui Qml Quick Test)
9+
10+# install binaries
11+install(TARGETS ${DASH_APP}
12+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
13+)
src/Dash/main.cppnew file+96
@@ -0,0 +1,96 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Michael Zanetti <michael.zanetti@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+#include <QtQuick/QQuickView>
21+#include <QtGui/QGuiApplication>
22+#include <QtQml/QQmlEngine>
23+#include <QtQml/QQmlContext>
24+#include <QDebug>
25+#include <QCommandLineParser>
26+#include <QLibrary>
27+#include <libintl.h>
28+
29+#include <paths.h>
30+#include "../MouseTouchAdaptor.h"
31+
32+int main(int argc, const char *argv[])
33+{
34+ QGuiApplication *application = new QGuiApplication(argc, (char**)argv);
35+
36+ QCommandLineParser parser;
37+ parser.setApplicationDescription("Description: Unity 8 Shell Dash");
38+ parser.addHelpOption();
39+
40+ QCommandLineOption mousetouchOption("mousetouch",
41+ "Allow the mouse to provide touch input");
42+ parser.addOption(mousetouchOption);
43+
44+ // FIXME Remove once we drop the need of the hint
45+ QCommandLineOption desktopFileHintOption("desktop_file_hint",
46+ "The desktop_file_hint option for QtMir", "hint_file");
47+ parser.addOption(desktopFileHintOption);
48+
49+ // Treat args with single dashes the same as arguments with two dashes
50+ // Ex: -fullscreen == --fullscreen
51+ parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
52+ parser.process(*application);
53+
54+ if (getenv("QT_LOAD_TESTABILITY")) {
55+ QLibrary testLib(QLatin1String("qttestability"));
56+ if (testLib.load()) {
57+ typedef void (*TasInitialize)(void);
58+ TasInitialize initFunction = (TasInitialize)testLib.resolve("qt_testability_init");
59+ if (initFunction) {
60+ initFunction();
61+ } else {
62+ qCritical("Library qttestability resolve failed!");
63+ }
64+ } else {
65+ qCritical("Library qttestability load failed!");
66+ }
67+ }
68+
69+ bindtextdomain("unity8", translationDirectory().toUtf8().data());
70+
71+ QQuickView* view = new QQuickView();
72+ view->setResizeMode(QQuickView::SizeRootObjectToView);
73+ view->setTitle("Unity Dash");
74+
75+ // You will need this if you want to interact with touch-only components using a mouse
76+ // Needed only when manually testing on a desktop.
77+ MouseTouchAdaptor *mouseTouchAdaptor = 0;
78+ if (parser.isSet(mousetouchOption)) {
79+ mouseTouchAdaptor = new MouseTouchAdaptor;
80+ application->installNativeEventFilter(mouseTouchAdaptor);
81+ }
82+
83+ QUrl source(::qmlDirectory()+"Dash/DashApplication.qml");
84+ prependImportPaths(view->engine(), ::overrideImportPaths());
85+ appendImportPaths(view->engine(), ::fallbackImportPaths());
86+
87+ view->setSource(source);
88+ view->show();
89+
90+ int result = application->exec();
91+
92+ delete view;
93+ delete application;
94+
95+ return result;
96+}
tests/autopilot/unity8/application_lifecycle/tests/test_application_lifecycle.py+1−1
@@ -106,7 +106,7 @@ class ApplicationLifecycleTests(tests.ApplicationLifeCycleTestCase):
106 self.assert_current_focused_application(application_name)
106 self.assert_current_focused_application(application_name)
107
107
108 self.main_window.show_dash_swiping()
108 self.main_window.show_dash_swiping()
109− self.assert_current_focused_application('')
109+ self.assert_current_focused_application('unity8-dash')
110
110
111 process_helpers.lock_unity()
111 process_helpers.lock_unity()
112 greeter = self.main_window.get_greeter()
112 greeter = self.main_window.get_greeter()
tests/autopilot/unity8/application_lifecycle/tests/test_url_dispatcher.py+3−2
@@ -39,7 +39,8 @@ class URLDispatcherTestCase(tests.ApplicationLifeCycleTestCase):
39 desktop_file_name = os.path.basename(desktop_file_path)
39 desktop_file_name = os.path.basename(desktop_file_path)
40 application_name, _ = os.path.splitext(desktop_file_name)
40 application_name, _ = os.path.splitext(desktop_file_name)
41
41
42+ self.assertEqual(
42− self.assertEqual('', self.main_window.get_current_focused_app_id())
43+ 'unity8-dash', self.main_window.get_current_focused_app_id())
43 self.addCleanup(os.system, 'pkill qmlscene')
44 self.addCleanup(os.system, 'pkill qmlscene')
44
45
45 subprocess.check_call(
46 subprocess.check_call(
@@ -47,4 +48,4 @@ class URLDispatcherTestCase(tests.ApplicationLifeCycleTestCase):
47 self.assert_current_focused_application(application_name)
48 self.assert_current_focused_application(application_name)
48
49
49 self.main_window.show_dash_swiping()
50 self.main_window.show_dash_swiping()
50− self.assert_current_focused_application('')
51+ self.assert_current_focused_application('unity8-dash')
tests/autopilot/unity8/fixture_setup.pynew file+64
@@ -0,0 +1,64 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2014 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+import fixtures
21+from autopilot import introspection
22+
23+from unity8 import process_helpers
24+from unity8.shell import emulators
25+
26+
27+class LaunchDashApp(fixtures.Fixture):
28+
29+ """Fixture to launch the Dash app."""
30+
31+ def __init__(self, binary_path, variables):
32+ """Initialize an instance.
33+
34+ :param str binary_path: The path to the Dash app binary.
35+ :param variables: The variables to use when launching the app.
36+ :type variables: A dictionary.
37+
38+ """
39+ super(LaunchDashApp, self).__init__()
40+ self.binary_path = binary_path
41+ self.variables = variables
42+
43+ def setUp(self):
44+ """Launch the dash app when the fixture is used."""
45+ super(LaunchDashApp, self).setUp()
46+ self.addCleanup(self.stop_application)
47+ self.application_proxy = self.launch_application()
48+
49+ def launch_application(self):
50+ binary_arg = 'BINARY={}'.format(self.binary_path)
51+ testability_arg = 'QT_LOAD_TESTABILITY={}'.format(1)
52+ env_args = [
53+ '{}={}'.format(key, value) for key, value in self.variables.items()
54+ ]
55+ all_args = [binary_arg, testability_arg] + env_args
56+
57+ pid = process_helpers.start_job('unity8-dash', *all_args)
58+ return introspection.get_proxy_object_for_existing_process(
59+ pid=pid,
60+ emulator_base=emulators.UnityEmulatorBase,
61+ )
62+
63+ def stop_application(self):
64+ process_helpers.stop_job('unity8-dash')
tests/autopilot/unity8/process_helpers.py+89−20
@@ -36,6 +36,10 @@ from unity8.shell.emulators import main_window as main_window_emulator
36logger = logging.getLogger(__name__)
36logger = logging.getLogger(__name__)
37
37
38
38
39+class JobError(Exception):
40+ pass
41+
42+
39class CannotAccessUnity(Exception):
43class CannotAccessUnity(Exception):
40 pass
44 pass
41
45
@@ -134,48 +138,113 @@ def restart_unity(*args):
134 """
138 """
135 status = _get_unity_status()
139 status = _get_unity_status()
136 if "start/" in status:
140 if "start/" in status:
137− try:
141+ stop_job('unity8')
138− output = subprocess.check_output(
142+
139− ['/sbin/initctl', 'stop', 'unity8'])
143+ pid = start_job('unity8', *args)
140− logger.info(output)
144+ return _get_unity_proxy_object(pid)
141− except subprocess.CalledProcessError as e:
142− e.args += (
143− "Failed to stop running instance of unity8: %s" % e.output,
144− )
145− raise
146
145
146+
147+def start_job(name, *args):
148+ """Start a job.
149+
150+ :param str name: The name of the job.
151+ :param args: The arguments to be used when starting the job.
152+ :return: The process id of the started job.
153+ :raises CalledProcessError: if the job failed to start.
154+
155+ """
156+ logger.info('Starting job {} with arguments {}.'.format(name, args))
157+ command = ['/sbin/initctl', 'start', name] + list(args)
147 try:
158 try:
148− command = ['/sbin/initctl', 'start', 'unity8'] + list(args)
149 output = subprocess.check_output(
159 output = subprocess.check_output(
150 command,
160 command,
151 stderr=subprocess.STDOUT,
161 stderr=subprocess.STDOUT,
152 universal_newlines=True,
162 universal_newlines=True,
153 )
163 )
154 logger.info(output)
164 logger.info(output)
155− pid = _get_unity_pid()
165+ pid = get_job_pid(name)
156 except subprocess.CalledProcessError as e:
166 except subprocess.CalledProcessError as e:
157− e.args += ("Failed to start unity8: %s" % e.output,)
167+ e.args += ('Failed to start {}: {}.'.format(name, e.output),)
158 raise
168 raise
159 else:
169 else:
160− return _get_unity_proxy_object(pid)
170+ return pid
161
171
162
172
163−def _get_unity_status():
173+def get_job_pid(name):
174+ """Return the process id of a running job.
175+
176+ :param str name: The name of the job.
177+ :raises JobError: if the job is not running.
178+
179+ """
180+ status = get_job_status(name)
181+ if "start/" not in status:
182+ raise JobError('{} is not in the running state.'.format(name))
183+ return int(status.split()[-1])
184+
185+
186+def get_job_status(name):
187+ """Return the status of a job.
188+
189+ :param str name: The name of the job.
190+ :raises JobError: if it's not possible to get the status of the job.
191+
192+ """
164 try:
193 try:
165 return subprocess.check_output([
194 return subprocess.check_output([
166 '/sbin/initctl',
195 '/sbin/initctl',
167 'status',
196 'status',
168− 'unity8'
197+ name
169 ], universal_newlines=True)
198 ], universal_newlines=True)
199+ except subprocess.CalledProcessError as error:
200+ raise JobError(
201+ "Unable to get {}'s status: {}".format(name, error)
202+ )
203+
204+
205+def stop_job(name):
206+ """Stop a job.
207+
208+ :param str name: The name of the job.
209+ :raises CalledProcessError: if the job failed to stop.
210+
211+ """
212+ logger.info('Stoping job {}.'.format(name))
213+ command = ['/sbin/initctl', 'stop', name]
214+ try:
215+ output = subprocess.check_output(
216+ command,
217+ stderr=subprocess.STDOUT,
218+ universal_newlines=True,
219+ )
220+ logger.info(output)
170 except subprocess.CalledProcessError as e:
221 except subprocess.CalledProcessError as e:
171− raise CannotAccessUnity("Unable to get unity's status: %s" % str(e))
222+ e.args += ('Failed to stop {}: {}.'.format(name, e.output),)
223+ raise
224+
225+
226+def is_job_running(name):
227+ """Return True if the job is running. Otherwise, False.
228+
229+ :param str name: The name of the job.
230+ :raises JobError: if it's not possible to get the status of the job.
231+
232+ """
233+ return 'start/' in get_job_status(name)
234+
235+
236+def _get_unity_status():
237+ try:
238+ return get_job_status('unity8')
239+ except JobError as error:
240+ raise CannotAccessUnity(str(error))
172
241
173
242
174def _get_unity_pid():
243def _get_unity_pid():
175− status = _get_unity_status()
244+ try:
176− if "start/" not in status:
245+ return get_job_pid('unity8')
246+ except JobError as error:
177− raise CannotAccessUnity("Unity is not in the running state.")
247+ raise CannotAccessUnity(str(error))
178− return int(status.split()[-1])
179
248
180
249
181def _get_unity_proxy_object(pid):
250def _get_unity_proxy_object(pid):
tests/autopilot/unity8/shell/emulators/dash.py+22−9
@@ -31,6 +31,17 @@ from ubuntuuitoolkit import emulators as toolkit_emulators
31logger = logging.getLogger(__name__)
31logger = logging.getLogger(__name__)
32
32
33
33
34+class DashApp(object):
35+
36+ """Autopilot helper for the Dash app."""
37+
38+ def __init__(self, app_proxy):
39+ self.app_proxy = app_proxy
40+ self.main_view = self.app_proxy.select_single(
41+ toolkit_emulators.MainView)
42+ self.dash = self.main_view.select_single(Dash)
43+
44+
34class Dash(emulators.UnityEmulatorBase):
45class Dash(emulators.UnityEmulatorBase):
35 """An emulator that understands the Dash."""
46 """An emulator that understands the Dash."""
36
47
@@ -109,20 +120,22 @@ class Dash(emulators.UnityEmulatorBase):
109 @autopilot_logging.log_action(logger.info)
120 @autopilot_logging.log_action(logger.info)
110 def _scroll_to_left_scope(self):
121 def _scroll_to_left_scope(self):
111 original_index = self.dash_content_list.currentIndex
122 original_index = self.dash_content_list.currentIndex
112− dashContent = self.select_single(objectName="dashContent")
123+ dash_content = self.select_single(objectName="dashContent")
124+ x, y, width, height = dash_content.globalRect
113− start_x = dashContent.width / 3
125+ start_x = x + width / 3
114− stop_x = dashContent.width / 3 * 2
126+ stop_x = x + width / 3 * 2
115− start_y = stop_y = dashContent.globalRect.y + 1
127+ start_y = stop_y = y + 1
116 self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
128 self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
117 self.dash_content_list.currentIndex.wait_for(original_index - 1)
129 self.dash_content_list.currentIndex.wait_for(original_index - 1)
118
130
119 @autopilot_logging.log_action(logger.info)
131 @autopilot_logging.log_action(logger.info)
120 def _scroll_to_right_scope(self):
132 def _scroll_to_right_scope(self):
121 original_index = self.dash_content_list.currentIndex
133 original_index = self.dash_content_list.currentIndex
122− dashContent = self.select_single(objectName="dashContent")
134+ dash_content = self.select_single(objectName="dashContent")
135+ x, y, width, height = dash_content.globalRect
123− start_x = dashContent.width / 3 * 2
136+ start_x = x + width / 3 * 2
124− stop_x = dashContent.width / 3
137+ stop_x = x + width / 3
125− start_y = stop_y = dashContent.globalRect.y + 1
138+ start_y = stop_y = y + 1
126 self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
139 self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
127 self.dash_content_list.currentIndex.wait_for(original_index + 1)
140 self.dash_content_list.currentIndex.wait_for(original_index + 1)
128
141
@@ -137,7 +150,7 @@ class Dash(emulators.UnityEmulatorBase):
137 headerContainer.contentY.wait_for(0)
150 headerContainer.contentY.wait_for(0)
138 search_text_field = self._get_search_text_field()
151 search_text_field = self._get_search_text_field()
139 search_text_field.write(query)
152 search_text_field.write(query)
140− current_header.select_single(objectName="searchIndicator").running.wait_for(False)
153+ self.select_single(objectName="processingIndicator").visible.wait_for(False)
141
154
142 def _get_search_text_field(self):
155 def _get_search_text_field(self):
143 page_header = self._get_current_page_header()
156 page_header = self._get_current_page_header()
tests/autopilot/unity8/shell/emulators/greeter.py+4−1
@@ -17,6 +17,8 @@
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18#
18#
19
19
20+import ubuntuuitoolkit
21+
20from unity8.shell.emulators import UnityEmulatorBase
22from unity8.shell.emulators import UnityEmulatorBase
21
23
22
24
@@ -37,4 +39,5 @@ class Greeter(UnityEmulatorBase):
37 self.created.wait_for(False)
39 self.created.wait_for(False)
38
40
39 def get_prompt(self):
41 def get_prompt(self):
42+ return self.select_single(
40− return self.select_single("TextField", objectName="passwordInput")
43+ ubuntuuitoolkit.TextField, objectName='passwordInput')
tests/autopilot/unity8/shell/emulators/main_window.py+34−20
@@ -25,7 +25,6 @@ from autopilot import input
25from unity8.shell import emulators
25from unity8.shell import emulators
26from unity8.shell.emulators.greeter import Greeter
26from unity8.shell.emulators.greeter import Greeter
27from unity8.shell.emulators.hud import Hud
27from unity8.shell.emulators.hud import Hud
28−from unity8.shell.emulators.dash import Dash
29from unity8.shell.emulators.launcher import Launcher
28from unity8.shell.emulators.launcher import Launcher
30
29
31logger = logging.getLogger(__name__)
30logger = logging.getLogger(__name__)
@@ -61,9 +60,6 @@ class QQuickView(emulators.UnityEmulatorBase):
61 def get_hud_edge_drag_area(self):
60 def get_hud_edge_drag_area(self):
62 return self.select_single(objectName="hudDragArea")
61 return self.select_single(objectName="hudDragArea")
63
62
64− def get_dash(self):
65− return self.select_single(Dash)
66−
67 def get_bottombar(self):
63 def get_bottombar(self):
68 return self.select_single("Bottombar")
64 return self.select_single("Bottombar")
69
65
@@ -76,12 +72,6 @@ class QQuickView(emulators.UnityEmulatorBase):
76 objectName="pinPadLoader"
72 objectName="pinPadLoader"
77 )
73 )
78
74
79− def get_pinPadButton(self, buttonId):
80− return self.select_single(
81− "PinPadButton",
82− objectName="pinPadButton%i" % buttonId
83− )
84−
85 def get_lockscreen(self):
75 def get_lockscreen(self):
86 return self.select_single("Lockscreen")
76 return self.select_single("Lockscreen")
87
77
@@ -117,20 +107,44 @@ class QQuickView(emulators.UnityEmulatorBase):
117 @autopilot_logging.log_action(logger.info)
107 @autopilot_logging.log_action(logger.info)
118 def show_dash_swiping(self):
108 def show_dash_swiping(self):
119 """Show the dash swiping from the left."""
109 """Show the dash swiping from the left."""
120− width = self.width
110+ x, y, width, height = self._get_shell().globalRect
121− height = self.height
122− start_x = 0
111+ start_x = x
123− start_y = height // 2
124− end_x = width
112+ end_x = x + width
125− end_y = start_y
113+ start_y = end_y = y + height // 2
126
114
127 self.pointing_device.drag(start_x, start_y, end_x, end_y)
115 self.pointing_device.drag(start_x, start_y, end_x, end_y)
116+
117+ def _get_shell(self):
128− return self.get_dash()
118+ return self.select_single('Shell')
129
119
130 def get_current_focused_app_id(self):
120 def get_current_focused_app_id(self):
131 """Return the id of the focused application."""
121 """Return the id of the focused application."""
132− return self.select_single('Shell').focusedApplicationId
122+ return self._get_shell().focusedApplicationId
133
123
134 @autopilot_logging.log_action(logger.info)
124 @autopilot_logging.log_action(logger.info)
135− def search(self, query):
125+ def enter_pin_code(self, code):
136− self.get_dash().enter_search_query(query)
126+ """Enter code 'code' into the single-pin lightdm pincode entry screen.
127+
128+ :param code: must be a string of numeric characters.
129+ :raises: TypeError if code is not a string.
130+ :raises: ValueError if code contains non-numeric characters.
131+
132+ """
133+ if not isinstance(code, str):
134+ raise TypeError(
135+ "'code' parameter must be a string, not %r."
136+ % type(code)
137+ )
138+ for num in code:
139+ if not num.isdigit():
140+ raise ValueError(
141+ "'code' parameter contains non-numeric characters."
142+ )
143+ self.pointing_device.click_object(
144+ self._get_pinpad_button(int(num)))
145+
146+ def _get_pinpad_button(self, button_id):
147+ return self.select_single(
148+ 'PinPadButton',
149+ objectName='pinPadButton{}'.format(button_id)
150+ )
tests/autopilot/unity8/shell/tests/__init__.py+141−48
@@ -24,6 +24,7 @@ try:
24except ImportError:
24except ImportError:
25 Gio = None
25 Gio = None
26
26
27+from autopilot import introspection
27from autopilot.platform import model
28from autopilot.platform import model
28from autopilot.testcase import AutopilotTestCase
29from autopilot.testcase import AutopilotTestCase
29from autopilot.matchers import Eventually
30from autopilot.matchers import Eventually
@@ -34,6 +35,10 @@ import os.path
34import subprocess
35import subprocess
35import sys
36import sys
36from testtools.matchers import Equals
37from testtools.matchers import Equals
38+from ubuntuuitoolkit import (
39+ fixture_setup as toolkit_fixtures,
40+ ubuntu_scenarios
41+)
37
42
38from unity8 import (
43from unity8 import (
39 get_lib_path,
44 get_lib_path,
@@ -42,9 +47,15 @@ from unity8 import (
42 get_default_extra_mock_libraries,
47 get_default_extra_mock_libraries,
43 get_data_dirs
48 get_data_dirs
44)
49)
45−from unity8.process_helpers import restart_unity_with_testability
50+from unity8 import (
51+ fixture_setup,
52+ process_helpers
53+)
54+from unity8.shell import emulators
55+from unity8.shell.emulators import (
56+ dash as dash_helpers,
46−from unity8.shell.emulators import main_window as main_window_emulator
57+ main_window as main_window_emulator,
47−from unity8.shell.emulators.dash import Dash
58+)
48
59
49
60
50logger = logging.getLogger(__name__)
61logger = logging.getLogger(__name__)
@@ -78,6 +89,26 @@ def _get_device_emulation_scenarios(devices='All'):
78 return [native]
89 return [native]
79
90
80
91
92+def is_unity7_running():
93+ """Return True if Unity7 is running. Otherwise, return False."""
94+ return (
95+ Gio is not None and
96+ UNITYSHELL_GSETTINGS_SCHEMA in
97+ Gio.Settings.list_relocatable_schemas()
98+ )
99+
100+
101+def get_qml_import_path_with_mock():
102+ """Return the QML2_IMPORT_PATH value with the mock path prepended."""
103+ qml_import_path = [get_mocks_library_path()]
104+ if os.getenv('QML2_IMPORT_PATH') is not None:
105+ qml_import_path.append(os.getenv('QML2_IMPORT_PATH'))
106+
107+ qml_import_path = ':'.join(qml_import_path)
108+ logger.info("New QML2 import path: %s", qml_import_path)
109+ return qml_import_path
110+
111+
81class UnityTestCase(AutopilotTestCase):
112class UnityTestCase(AutopilotTestCase):
82
113
83 """A test case base class for the Unity shell tests."""
114 """A test case base class for the Unity shell tests."""
@@ -118,23 +149,8 @@ class UnityTestCase(AutopilotTestCase):
118
149
119 def setUp(self):
150 def setUp(self):
120 super(UnityTestCase, self).setUp()
151 super(UnityTestCase, self).setUp()
121− if (Gio is not None and
152+ if is_unity7_running():
122− UNITYSHELL_GSETTINGS_SCHEMA in
153+ self.useFixture(toolkit_fixtures.HideUnity7Launcher())
123− Gio.Settings.list_relocatable_schemas()):
124−
125− # Hide Unity launcher
126− self._unityshell_schema = Gio.Settings.new_with_path(
127− UNITYSHELL_GSETTINGS_SCHEMA,
128− UNITYSHELL_GSETTINGS_PATH,
129− )
130− self._launcher_hide_mode = self._unityshell_schema.get_int(
131− UNITYSHELL_LAUNCHER_KEY,
132− )
133− self._unityshell_schema.set_int(
134− UNITYSHELL_LAUNCHER_KEY,
135− UNITYSHELL_LAUNCHER_MODE,
136− )
137− self.addCleanup(self._reset_launcher)
138
154
139 self._proxy = None
155 self._proxy = None
140 self._lightdm_mock_type = None
156 self._lightdm_mock_type = None
@@ -151,13 +167,6 @@ class UnityTestCase(AutopilotTestCase):
151 self.touch = Touch.create()
167 self.touch = Touch.create()
152 self._setup_display_details()
168 self._setup_display_details()
153
169
154− def _reset_launcher(self):
155− """Reset Unity launcher hide mode"""
156− self._unityshell_schema.set_int(
157− UNITYSHELL_LAUNCHER_KEY,
158− self._launcher_hide_mode,
159− )
160−
161 def _setup_display_details(self):
170 def _setup_display_details(self):
162 scale_divisor = self._determine_geometry()
171 scale_divisor = self._determine_geometry()
163 self._setup_grid_size(scale_divisor)
172 self._setup_grid_size(scale_divisor)
@@ -263,7 +272,9 @@ class UnityTestCase(AutopilotTestCase):
263 self.patch_lightdm_mock()
272 self.patch_lightdm_mock()
264
273
265 if self._qml_mock_enabled:
274 if self._qml_mock_enabled:
266− self._setup_extra_mock_environment_patch()
275+ self._environment['QML2_IMPORT_PATH'] = (
276+ get_qml_import_path_with_mock()
277+ )
267
278
268 if self._data_dirs_mock_enabled:
279 if self._data_dirs_mock_enabled:
269 self._patch_data_dirs()
280 self._patch_data_dirs()
@@ -292,9 +303,14 @@ class UnityTestCase(AutopilotTestCase):
292
303
293 # Ensure that the dash is visible before we return:
304 # Ensure that the dash is visible before we return:
294 logger.debug("Unity started, waiting for it to be ready.")
305 logger.debug("Unity started, waiting for it to be ready.")
295− self.assertUnityReady()
306+ self.wait_for_unity()
296 logger.debug("Unity loaded and ready.")
307 logger.debug("Unity loaded and ready.")
297
308
309+ if model() == 'Desktop':
310+ # On desktop, close the dash because it's opened in a separate
311+ # window and it gets in the way.
312+ process_helpers.stop_job('unity8-dash')
313+
298 return app_proxy
314 return app_proxy
299
315
300 def _launch_unity_with_upstart(self, binary_path, args):
316 def _launch_unity_with_upstart(self, binary_path, args):
@@ -308,7 +324,7 @@ class UnityTestCase(AutopilotTestCase):
308
324
309 self.addCleanup(self._cleanup_launching_upstart_unity)
325 self.addCleanup(self._cleanup_launching_upstart_unity)
310
326
311− return restart_unity_with_testability(*all_args)
327+ return process_helpers.restart_unity_with_testability(*all_args)
312
328
313 def _cleanup_launching_upstart_unity(self):
329 def _cleanup_launching_upstart_unity(self):
314 logger.info("Stopping unity")
330 logger.info("Stopping unity")
@@ -353,15 +369,6 @@ class UnityTestCase(AutopilotTestCase):
353 )
369 )
354 return lightdm_mock_path
370 return lightdm_mock_path
355
371
356− def _setup_extra_mock_environment_patch(self):
357− qml_import_path = [get_mocks_library_path()]
358− if os.getenv('QML2_IMPORT_PATH') is not None:
359− qml_import_path.append(os.getenv('QML2_IMPORT_PATH'))
360−
361− qml_import_path = ':'.join(qml_import_path)
362− logger.info("New QML2 import path: %s", qml_import_path)
363− self._environment['QML2_IMPORT_PATH'] = qml_import_path
364−
365 def _set_proxy(self, proxy):
372 def _set_proxy(self, proxy):
366 """Keep a copy of the proxy object, so we can use it to get common
373 """Keep a copy of the proxy object, so we can use it to get common
367 parts of the shell later on.
374 parts of the shell later on.
@@ -373,10 +380,80 @@ class UnityTestCase(AutopilotTestCase):
373 def _clear_proxy(self):
380 def _clear_proxy(self):
374 self._proxy = None
381 self._proxy = None
375
382
376− def assertUnityReady(self):
383+ def wait_for_unity(self):
384+ greeter_content_loader = self.main_window.wait_select_single(
385+ objectName='greeterContentLoader')
386+ greeter_content_loader.progress.wait_for(1)
387+
377− dash = self.get_dash()
388+ def get_dash(self):
378− home_scope = dash.get_scope('clickscope')
389+ pid = process_helpers.get_job_pid('unity8-dash')
390+ dash_proxy = introspection.get_proxy_object_for_existing_process(
391+ pid=pid,
392+ emulator_base=emulators.UnityEmulatorBase,
393+ )
394+ dash_app = dash_helpers.DashApp(dash_proxy)
395+ return dash_app.dash
396+
397+ @property
398+ def main_window(self):
399+ return self._proxy.select_single(main_window_emulator.QQuickView)
379
400
401+
402+class DashBaseTestCase(AutopilotTestCase):
403+
404+ scenarios = ubuntu_scenarios.get_device_simulation_scenarios()
405+ qml_mock_enabled = True
406+ environment = {}
407+
408+ def setUp(self):
409+ super(DashBaseTestCase, self).setUp()
410+
411+ if is_unity7_running():
412+ self.useFixture(toolkit_fixtures.HideUnity7Launcher())
413+
414+ if model() != 'Desktop':
415+ # On the phone, we need unity to be running and unlocked.
416+ self.addCleanup(process_helpers.stop_job, 'unity8')
417+ process_helpers.restart_unity_with_testability()
418+ process_helpers.unlock_unity()
419+
420+ self.ensure_dash_not_running()
421+
422+ if self.qml_mock_enabled:
423+ self.environment['QML2_IMPORT_PATH'] = (
424+ get_qml_import_path_with_mock()
425+ )
426+
427+ if self.should_simulate_device():
428+ # This sets the grid units, so it should be called before launching
429+ # the app.
430+ self.simulate_device()
431+
432+ binary_path = get_binary_path('unity8-dash')
433+ dash_proxy = self.launch_dash(binary_path, self.environment)
434+
435+ if self.should_simulate_device():
436+ # XXX Currently we have no way to launch the application with a
437+ # specific size, so we must resize it after it's launched.
438+ # --elopio - 2014-06-25
439+ self.resize_window()
440+
441+ self.dash_app = dash_helpers.DashApp(dash_proxy)
442+ self.dash = self.dash_app.dash
443+ self.wait_for_dash()
444+
445+ def ensure_dash_not_running(self):
446+ if process_helpers.is_job_running('unity8-dash'):
447+ process_helpers.stop_job('unity8-dash')
448+
449+ def launch_dash(self, binary_path, variables):
450+ launch_dash_app_fixture = fixture_setup.LaunchDashApp(
451+ binary_path, variables)
452+ self.useFixture(launch_dash_app_fixture)
453+ return launch_dash_app_fixture.application_proxy
454+
455+ def wait_for_dash(self):
456+ home_scope = self.dash.get_scope('clickscope')
380 # FIXME! There is a huge timeout here for when we're doing CI on
457 # FIXME! There is a huge timeout here for when we're doing CI on
381 # VMs. See lp:1203715
458 # VMs. See lp:1203715
382 self.assertThat(
459 self.assertThat(
@@ -385,10 +462,26 @@ class UnityTestCase(AutopilotTestCase):
385 )
462 )
386 self.assertThat(home_scope.isCurrent, Eventually(Equals(True)))
463 self.assertThat(home_scope.isCurrent, Eventually(Equals(True)))
387
464
388− def get_dash(self):
465+ def should_simulate_device(self):
389− dash = self._proxy.wait_select_single(Dash)
466+ return (hasattr(self, 'app_width') and hasattr(self, 'app_height') and
390− return dash
467+ hasattr(self, 'grid_unit_px'))
391
468
392− @property
469+ def simulate_device(self):
393− def main_window(self):
470+ simulate_device_fixture = self.useFixture(
394− return self._proxy.select_single(main_window_emulator.QQuickView)
471+ toolkit_fixtures.SimulateDevice(
472+ self.app_width, self.app_height, self.grid_unit_px))
473+ self.app_width = simulate_device_fixture.app_width
474+ self.app_height = simulate_device_fixture.app_height
475+
476+ def resize_window(self):
477+ application = self.process_manager.get_running_applications()[0]
478+ window = application.get_windows()[0]
479+ window.resize(self.app_width, self.app_height)
480+
481+ def get_window_size():
482+ _, _, window_width, window_height = window.geometry
483+ return window_width, window_height
484+
485+ self.assertThat(
486+ get_window_size,
487+ Eventually(Equals((self.app_width, self.app_height))))
tests/autopilot/unity8/shell/tests/test_emulators.py+7−18
@@ -47,24 +47,13 @@ class MainWindowTestCase(tests.UnityTestCase):
47 unity_proxy = self.launch_unity()
47 unity_proxy = self.launch_unity()
48 process_helpers.unlock_unity(unity_proxy)
48 process_helpers.unlock_unity(unity_proxy)
49
49
50− def test_search(self):
51− self.main_window.search('Test')
52− text_field = self.main_window.get_dash()._get_search_text_field()
53− self.assertEqual(text_field.text, 'Test')
54−
55−
56−class DashBaseTestCase(tests.UnityTestCase):
57−
58− scenarios = tests._get_device_emulation_scenarios()
59
50
60− def setUp(self):
61− super(DashBaseTestCase, self).setUp()
51+class DashEmulatorTestCase(tests.DashBaseTestCase):
62− unity_proxy = self.launch_unity()
63− process_helpers.unlock_unity(unity_proxy)
64− self.dash = self.main_window.get_dash()
65
52
66−
53+ def test_search(self):
67−class DashEmulatorTestCase(DashBaseTestCase):
54+ self.dash.enter_search_query('Test')
55+ text_field = self.dash._get_search_text_field()
56+ self.assertEqual(text_field.text, 'Test')
68
57
69 def test_open_unexisting_scope(self):
58 def test_open_unexisting_scope(self):
70 scope_name = 'unexisting'
59 scope_name = 'unexisting'
@@ -145,7 +134,7 @@ class DashEmulatorTestCase(DashBaseTestCase):
145 self.assertIsInstance(scope, dash_emulators.GenericScopeView)
134 self.assertIsInstance(scope, dash_emulators.GenericScopeView)
146
135
147
136
148−class GenericScopeViewEmulatorTestCase(DashBaseTestCase):
137+class GenericScopeViewEmulatorTestCase(tests.DashBaseTestCase):
149
138
150 def setUp(self):
139 def setUp(self):
151 # Set up the fake scopes before launching unity.
140 # Set up the fake scopes before launching unity.
@@ -159,7 +148,7 @@ class GenericScopeViewEmulatorTestCase(DashBaseTestCase):
159 self.assertTrue(preview.isCurrent)
148 self.assertTrue(preview.isCurrent)
160
149
161
150
162−class DashAppsEmulatorTestCase(DashBaseTestCase):
151+class DashAppsEmulatorTestCase(tests.DashBaseTestCase):
163
152
164 available_applications = [
153 available_applications = [
165 'Title.2.0', 'Title.2.1', 'Title.2.2', 'Title.2.3', 'Title.2.4',
154 'Title.2.0', 'Title.2.1', 'Title.2.2', 'Title.2.3', 'Title.2.4',
tests/autopilot/unity8/shell/tests/test_lock_screen.py+7−47
@@ -51,7 +51,7 @@ class TestLockscreen(UnityTestCase):
51 if greeter.narrowMode:
51 if greeter.narrowMode:
52 unlock_unity(unity_proxy)
52 unlock_unity(unity_proxy)
53 lockscreen = self._wait_for_lockscreen()
53 lockscreen = self._wait_for_lockscreen()
54− self._enter_pincode("1234")
54+ self.main_window.enter_pin_code("1234")
55 self.assertThat(lockscreen.shown, Eventually(Equals(False)))
55 self.assertThat(lockscreen.shown, Eventually(Equals(False)))
56 else:
56 else:
57 self._enter_prompt_passphrase("1234")
57 self._enter_prompt_passphrase("1234")
@@ -81,7 +81,7 @@ class TestLockscreen(UnityTestCase):
81 if greeter.narrowMode:
81 if greeter.narrowMode:
82 unlock_unity(unity_proxy)
82 unlock_unity(unity_proxy)
83 lockscreen = self._wait_for_lockscreen()
83 lockscreen = self._wait_for_lockscreen()
84− self._enter_pincode("4321")
84+ self.main_window.enter_pin_code("4321")
85 pinentryField = self.main_window.get_pinentryField()
85 pinentryField = self.main_window.get_pinentryField()
86 self.assertThat(pinentryField.text, Eventually(Equals("")))
86 self.assertThat(pinentryField.text, Eventually(Equals("")))
87 self.assertThat(lockscreen.shown, Eventually(Equals(True)))
87 self.assertThat(lockscreen.shown, Eventually(Equals(True)))
@@ -118,28 +118,6 @@ class TestLockscreen(UnityTestCase):
118 self.assertThat(lockscreen.shown, Eventually(Equals(True)))
118 self.assertThat(lockscreen.shown, Eventually(Equals(True)))
119 return lockscreen
119 return lockscreen
120
120
121− def _enter_pincode(self, code):
122− """Enter code 'code' into the single-pin lightdm pincode entry
123− screen.
124−
125− :param code: must be a string of numeric characters.
126− :raises: TypeError if code is not a string.
127− :raises: ValueError if code contains non-numeric characters.
128−
129− """
130−
131− if not isinstance(code, basestring):
132− raise TypeError(
133− "'code' parameter must be a string, not %r."
134− % type(code)
135− )
136− for num in code:
137− if not num.isdigit():
138− raise ValueError(
139− "'code' parameter contains non-numeric characters."
140− )
141− self.touch.tap_object(self.main_window.get_pinPadButton(int(num)))
142−
143 def _enter_pin_passphrase(self, passphrase):
121 def _enter_pin_passphrase(self, passphrase):
144 """Enter the password specified in 'passphrase' into the password entry
122 """Enter the password specified in 'passphrase' into the password entry
145 field of the pin lock screen.
123 field of the pin lock screen.
@@ -148,18 +126,15 @@ class TestLockscreen(UnityTestCase):
148 :raises: TypeError if passphrase is not a string.
126 :raises: TypeError if passphrase is not a string.
149
127
150 """
128 """
151− if not isinstance(passphrase, basestring):
129+ if not isinstance(passphrase, str):
152 raise TypeError(
130 raise TypeError(
153 "'passphrase' parameter must be a string, not %r."
131 "'passphrase' parameter must be a string, not %r."
154 % type(passphrase)
132 % type(passphrase)
155 )
133 )
156
134
157− pinentryField = self.main_window.get_pinentryField()
135+ pin_entry_field = self.main_window.get_pinentryField()
158− self.touch.tap_object(pinentryField)
136+ pin_entry_field.write(passphrase)
159− self.assertThat(pinentryField.activeFocus, Eventually(Equals(True)))
160− for character in passphrase:
161− self._type_character(character, pinentryField)
162− logger.debug("Typed passphrase: %s", pinentryField.text)
137+ logger.debug("Typed passphrase: %s", pin_entry_field.text)
163 self.keyboard.type("\n")
138 self.keyboard.type("\n")
164
139
165 def _enter_prompt_passphrase(self, passphrase):
140 def _enter_prompt_passphrase(self, passphrase):
@@ -177,21 +152,6 @@ class TestLockscreen(UnityTestCase):
177 )
152 )
178
153
179 prompt = self.main_window.get_greeter().get_prompt()
154 prompt = self.main_window.get_greeter().get_prompt()
180− self.touch.tap_object(prompt)
181− self.assertThat(prompt.activeFocus, Eventually(Equals(True)))
182− for character in passphrase:
155+ prompt.write(passphrase)
183− self._type_character(character, prompt)
184 logger.debug("Typed passphrase: %s", prompt.text)
156 logger.debug("Typed passphrase: %s", prompt.text)
185 self.keyboard.type("\n")
157 self.keyboard.type("\n")
186−
187− def _type_character(self, character, prompt, retries=5):
188− current_text = prompt.text
189− self.keyboard.type(character)
190− try:
191− self.assertThat(
192− prompt.text, Eventually(Equals(current_text + character)))
193− except AssertionError:
194− if retries > 0:
195− self._type_character(character, prompt, retries-1)
196− else:
197− raise
tests/autopilot/unity8/shell/tests/test_notifications.py+12−7
@@ -154,7 +154,7 @@ class InteractiveNotificationBase(NotificationsBase):
154 'Notification', objectName='notification1')
154 'Notification', objectName='notification1')
155 notification = get_notification()
155 notification = get_notification()
156
156
157− self.touch.tap_object(
157+ notification.pointing_device.click_object(
158 notification.select_single(objectName="interactiveArea")
158 notification.select_single(objectName="interactiveArea")
159 )
159 )
160
160
@@ -201,11 +201,14 @@ class InteractiveNotificationBase(NotificationsBase):
201 'Notification', objectName='notification1')
201 'Notification', objectName='notification1')
202 notification = get_notification()
202 notification = get_notification()
203 self._assert_notification(notification, summary, body, True, True, 1.0)
203 self._assert_notification(notification, summary, body, True, True, 1.0)
204− initial_height = notification.height
204+ notification.pointing_device.click_object(
205− self.touch.tap_object(notification.select_single(objectName="combobutton_dropdown"))
205+ notification.select_single(objectName="combobutton_dropdown"))
206+ self.assertThat(
206− self.assertThat(notification.select_single(objectName="button2").expanded, Eventually(Equals(True)))
207+ notification.select_single(objectName="button2").expanded,
208+ Eventually(Equals(True)))
207 time.sleep(2)
209 time.sleep(2)
210+ notification.pointing_device.click_object(
208− self.touch.tap_object(notification.select_single(objectName="button4"))
211+ notification.select_single(objectName="button4"))
209 self.assert_notification_action_id_was_called("action_decline_4")
212 self.assert_notification_action_id_was_called("action_decline_4")
210
213
211 def test_modal_sd_without_greeter(self):
214 def test_modal_sd_without_greeter(self):
@@ -249,7 +252,8 @@ class InteractiveNotificationBase(NotificationsBase):
249 notification = get_notification()
252 notification = get_notification()
250 self._assert_notification(
253 self._assert_notification(
251 notification, summary, body, True, False, 1.0)
254 notification, summary, body, True, False, 1.0)
255+ notification.pointing_device.click_object(
252− self.touch.tap_object(notification.select_single(objectName="button0"))
256+ notification.select_single(objectName="button0"))
253 self.assert_notification_action_id_was_called("action_accept")
257 self.assert_notification_action_id_was_called("action_accept")
254
258
255 def test_modal_sd_with_greeter(self):
259 def test_modal_sd_with_greeter(self):
@@ -291,7 +295,8 @@ class InteractiveNotificationBase(NotificationsBase):
291 notification = get_notification()
295 notification = get_notification()
292 self._assert_notification(
296 self._assert_notification(
293 notification, summary, body, True, False, 1.0)
297 notification, summary, body, True, False, 1.0)
298+ notification.pointing_device.click_object(
294− self.touch.tap_object(notification.select_single(objectName="button0"))
299+ notification.select_single(objectName="button0"))
295 self.assert_notification_action_id_was_called("action_accept")
300 self.assert_notification_action_id_was_called("action_accept")
296
301
297 def _create_interactive_notification(
302 def _create_interactive_notification(
tests/autopilot/unity8/shell/tests/test_upstart.py+2−2
@@ -119,7 +119,7 @@ class UpstartIntegrationTests(UnityTestCase):
119 self._set_proxy()
119 self._set_proxy()
120
120
121 logger.debug("Unity started, waiting for it to be ready.")
121 logger.debug("Unity started, waiting for it to be ready.")
122− self.assertUnityReady()
122+ self.wait_for_unity()
123 logger.debug("Unity loaded and ready.")
123 logger.debug("Unity loaded and ready.")
124
124
125 def test_expect_sigstop(self):
125 def test_expect_sigstop(self):
@@ -137,5 +137,5 @@ class UpstartIntegrationTests(UnityTestCase):
137
137
138 logger.debug("Unity started, waiting for it to be ready.")
138 logger.debug("Unity started, waiting for it to be ready.")
139 self._set_proxy()
139 self._set_proxy()
140− self.assertUnityReady()
140+ self.wait_for_unity()
141 logger.debug("Unity loaded and ready.")
141 logger.debug("Unity loaded and ready.")
tests/mocks/Unity/Application/ApplicationDBusAdaptor.cpp+10−4
@@ -43,9 +43,9 @@ MirSurfaceItem* topSurface(MirSurfaceItem* surface)
43 return child ? child : surface;
43 return child ? child : surface;
44}
44}
45
45
46−quint32 ApplicationDBusAdaptor::addChildSurface(const QString &appId, const QString &surfaceImage)
46+quint32 ApplicationDBusAdaptor::addPromptSurface(const QString &appId, const QString &surfaceImage)
47{
47{
48− qDebug() << "ApplicationDBusAdaptor::addChildSurface - " << appId;
48+ qDebug() << "ApplicationDBusAdaptor::addPromptSurface to " << appId;
49
49
50 ApplicationInfo* application = m_applicationManager->findApplication(appId);
50 ApplicationInfo* application = m_applicationManager->findApplication(appId);
51 if (!application) {
51 if (!application) {
@@ -53,12 +53,18 @@ quint32 ApplicationDBusAdaptor::addChildSurface(const QString &appId, const QStr
53 return 0;
53 return 0;
54 }
54 }
55 quint32 surfaceId = ++nextId;
55 quint32 surfaceId = ++nextId;
56− MirSurfaceItem* surface = new MirSurfaceItem(QString("ChildSurface%1").arg(surfaceId),
56+ MirSurfaceItem* surface = new MirSurfaceItem(QString("%1-ChildSurface%2").arg(appId).arg(surfaceId),
57 MirSurfaceItem::Normal,
57 MirSurfaceItem::Normal,
58 MirSurfaceItem::Maximized,
58 MirSurfaceItem::Maximized,
59 QUrl(surfaceImage));
59 QUrl(surfaceImage));
60 m_childItems[surfaceId] = surface;
60 m_childItems[surfaceId] = surface;
61+
62+ if (application->promptSurfaceList().count() > 0) {
61− surface->setParentSurface(topSurface(application->surface()));
63+ surface->setParentSurface(topSurface(application->promptSurfaceList()[0]));
64+ } else {
65+ application->addPromptSurface(surface);
66+ }
67+
62 return surfaceId;
68 return surfaceId;
63}
69}
64
70
tests/mocks/Unity/Application/ApplicationDBusAdaptor.h+1−1
@@ -31,7 +31,7 @@ public:
31 ApplicationDBusAdaptor(ApplicationManager* applicationManager);
31 ApplicationDBusAdaptor(ApplicationManager* applicationManager);
32
32
33public Q_SLOTS:
33public Q_SLOTS:
34− quint32 addChildSurface(const QString& appId, const QString& surfaceImage);
34+ quint32 addPromptSurface(const QString& appId, const QString& surfaceImage);
35 void removeChildSurface(int surfaceId);
35 void removeChildSurface(int surfaceId);
36
36
37private:
37private:
tests/mocks/Unity/Application/ApplicationInfo.cpp+35−44
@@ -31,8 +31,6 @@ ApplicationInfo::ApplicationInfo(const QString &appId, QObject *parent)
31 , m_state(Starting)
31 , m_state(Starting)
32 , m_focused(false)
32 , m_focused(false)
33 , m_fullscreen(false)
33 , m_fullscreen(false)
34− , m_windowItem(0)
35− , m_windowComponent(0)
36 , m_parentItem(0)
34 , m_parentItem(0)
37 , m_surface(0)
35 , m_surface(0)
38{
36{
@@ -45,8 +43,6 @@ ApplicationInfo::ApplicationInfo(QObject *parent)
45 , m_state(Starting)
43 , m_state(Starting)
46 , m_focused(false)
44 , m_focused(false)
47 , m_fullscreen(false)
45 , m_fullscreen(false)
48− , m_windowItem(0)
49− , m_windowComponent(0)
50 , m_parentItem(0)
46 , m_parentItem(0)
51 , m_surface(0)
47 , m_surface(0)
52{
48{
@@ -61,12 +57,6 @@ ApplicationInfo::~ApplicationInfo()
61 }
57 }
62}
58}
63
59
64−void ApplicationInfo::onWindowComponentStatusChanged(QQmlComponent::Status status)
65−{
66− if (status == QQmlComponent::Ready && !m_windowItem)
67− doCreateWindowItem();
68−}
69−
70void ApplicationInfo::onStateChanged(State state)
60void ApplicationInfo::onStateChanged(State state)
71{
61{
72 if (state == ApplicationInfo::Running) {
62 if (state == ApplicationInfo::Running) {
@@ -88,6 +78,7 @@ void ApplicationInfo::createSurface()
88
78
89void ApplicationInfo::setSurface(MirSurfaceItem* surface)
79void ApplicationInfo::setSurface(MirSurfaceItem* surface)
90{
80{
81+ qDebug() << "Application::setSurface - appId=" << appId() << "surface=" << surface;
91 if (m_surface == surface)
82 if (m_surface == surface)
92 return;
83 return;
93
84
@@ -109,54 +100,54 @@ void ApplicationInfo::setSurface(MirSurfaceItem* surface)
109 SurfaceManager::singleton()->registerSurface(m_surface);
100 SurfaceManager::singleton()->registerSurface(m_surface);
110}
101}
111
102
112−void ApplicationInfo::createWindowComponent()
103+void ApplicationInfo::addPromptSurface(MirSurfaceItem* surface)
113{
104{
114− // The assumptions I make here really should hold.
105+ qDebug() << "ApplicationInfo::addPromptSurface " << surface->name() << " to " << name();
115− QQuickView *quickView =
106+ if (surface == m_surface || m_promptSurfaces.contains(surface)) return;
116− qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]);
117−
118− QQmlEngine *engine = quickView->engine();
119
107
120− m_windowComponent = new QQmlComponent(engine, this);
108+ surface->setApplication(this);
121− m_windowComponent->setData(m_windowQml.toLatin1(), QUrl());
109+ m_promptSurfaces.append(surface);
110+ Q_EMIT promptSurfacesChanged();
122}
111}
123
112
124−void ApplicationInfo::doCreateWindowItem()
113+void ApplicationInfo::removeSurface(MirSurfaceItem* surface)
125{
114{
126− m_windowItem = qobject_cast<QQuickItem *>(m_windowComponent->create());
115+ if (m_surface == surface) {
127− m_windowItem->setParentItem(m_parentItem);
116+ setSurface(nullptr);
128−}
117+ } else if (m_promptSurfaces.contains(surface)) {
118+ qDebug() << "Application::removeSurface " << surface->name() << " from " << name();
129
119
130−void ApplicationInfo::createWindowItem()
120+ m_promptSurfaces.removeAll(surface);
131−{
121+ surface->setApplication(nullptr);
132− if (!m_windowComponent)
122+
133− createWindowComponent();
123+ Q_EMIT promptSurfacesChanged();
134−
135− // only create the windowItem once the component is ready
136− if (!m_windowComponent->isReady()) {
137− connect(m_windowComponent, &QQmlComponent::statusChanged,
138− this, &ApplicationInfo::onWindowComponentStatusChanged);
139− } else {
140− doCreateWindowItem();
141 }
124 }
142}
125}
143
126
144−void ApplicationInfo::showWindow(QQuickItem *parent)
127+QList<MirSurfaceItem*> ApplicationInfo::promptSurfaceList() const
145{
128{
146− m_parentItem = parent;
129+ return m_promptSurfaces;
130+}
147
131
148− if (!m_windowItem)
132+QQmlListProperty<MirSurfaceItem> ApplicationInfo::promptSurfaces()
149− createWindowItem();
133+{
134+ return QQmlListProperty<MirSurfaceItem>(this,
135+ 0,
136+ ApplicationInfo::promptSurfaceCount,
137+ ApplicationInfo::promptSurfaceAt);
138+}
150
139
151− if (m_windowItem) {
140+int ApplicationInfo::promptSurfaceCount(QQmlListProperty<MirSurfaceItem> *prop)
152− m_windowItem->setVisible(true);
141+{
153− }
142+ ApplicationInfo *p = qobject_cast<ApplicationInfo*>(prop->object);
143+ return p->m_promptSurfaces.count();
154}
144}
155
145
156−void ApplicationInfo::hideWindow()
146+MirSurfaceItem* ApplicationInfo::promptSurfaceAt(QQmlListProperty<MirSurfaceItem> *prop, int index)
157{
147{
158− if (!m_windowItem)
148+ ApplicationInfo *p = qobject_cast<ApplicationInfo*>(prop->object);
159− return;
160
149
161− m_windowItem->setVisible(false);
150+ if (index < 0 || index >= p->m_promptSurfaces.count())
151+ return nullptr;
152+ return p->m_promptSurfaces[index];
162}
153}
tests/mocks/Unity/Application/ApplicationInfo.h+13−10
@@ -38,6 +38,7 @@ class ApplicationInfo : public ApplicationInfoInterface {
38 Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged)
38 Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged)
39 Q_PROPERTY(Stage stage READ stage WRITE setStage NOTIFY stageChanged)
39 Q_PROPERTY(Stage stage READ stage WRITE setStage NOTIFY stageChanged)
40 Q_PROPERTY(MirSurfaceItem* surface READ surface NOTIFY surfaceChanged)
40 Q_PROPERTY(MirSurfaceItem* surface READ surface NOTIFY surfaceChanged)
41+ Q_PROPERTY(QQmlListProperty<MirSurfaceItem> promptSurfaces READ promptSurfaces NOTIFY promptSurfacesChanged DESIGNABLE false)
41
42
42 // Only exists in this fake implementation
43 // Only exists in this fake implementation
43
44
@@ -85,29 +86,31 @@ public:
85 void setSurface(MirSurfaceItem* surface);
86 void setSurface(MirSurfaceItem* surface);
86 MirSurfaceItem* surface() const { return m_surface; }
87 MirSurfaceItem* surface() const { return m_surface; }
87
88
89+ void removeSurface(MirSurfaceItem* surface);
90+
91+ void addPromptSurface(MirSurfaceItem* surface);
92+ QList<MirSurfaceItem*> promptSurfaceList() const;
93+ QQmlListProperty<MirSurfaceItem> promptSurfaces();
94+
88Q_SIGNALS:
95Q_SIGNALS:
89 void surfaceChanged(MirSurfaceItem*);
96 void surfaceChanged(MirSurfaceItem*);
90−
97+ void promptSurfacesChanged();
91−public:
92− void showWindow(QQuickItem *parent);
93− void hideWindow();
94
98
95private Q_SLOTS:
99private Q_SLOTS:
96− void onWindowComponentStatusChanged(QQmlComponent::Status status);
97 void onStateChanged(State state);
100 void onStateChanged(State state);
98
101
99 void createSurface();
102 void createSurface();
100
103
101private:
104private:
102− void createWindowItem();
105+ static int promptSurfaceCount(QQmlListProperty<MirSurfaceItem> *prop);
103− void doCreateWindowItem();
106+ static MirSurfaceItem* promptSurfaceAt(QQmlListProperty<MirSurfaceItem> *prop, int index);
104− void createWindowComponent();
107+
105− QQuickItem *m_windowItem;
106− QQmlComponent *m_windowComponent;
107 QQuickItem *m_parentItem;
108 QQuickItem *m_parentItem;
108 MirSurfaceItem* m_surface;
109 MirSurfaceItem* m_surface;
110+ QList<MirSurfaceItem*> m_promptSurfaces;
109};
111};
110
112
111Q_DECLARE_METATYPE(ApplicationInfo*)
113Q_DECLARE_METATYPE(ApplicationInfo*)
114+Q_DECLARE_METATYPE(QQmlListProperty<MirSurfaceItem>)
112
115
113#endif // APPLICATION_H
116#endif // APPLICATION_H
tests/mocks/Unity/Application/ApplicationManager.cpp+20−147
@@ -48,16 +48,15 @@ ApplicationManager *ApplicationManager::singleton()
48ApplicationManager::ApplicationManager(QObject *parent)
48ApplicationManager::ApplicationManager(QObject *parent)
49 : ApplicationManagerInterface(parent)
49 : ApplicationManagerInterface(parent)
50 , m_suspended(false)
50 , m_suspended(false)
51− , m_mainStageComponent(0)
52− , m_mainStage(0)
53− , m_sideStageComponent(0)
54− , m_sideStage(0)
55− , m_rightMargin(0)
56{
51{
57 m_roleNames.insert(RoleSurface, "surface");
52 m_roleNames.insert(RoleSurface, "surface");
58 m_roleNames.insert(RoleFullscreen, "fullscreen");
53 m_roleNames.insert(RoleFullscreen, "fullscreen");
54+ m_roleNames.insert(RoleApplication, "application");
59
55
60 buildListOfAvailableApplications();
56 buildListOfAvailableApplications();
57+
58+ startApplication("unity8-dash");
59+ focusApplication("unity8-dash");
61}
60}
62
61
63ApplicationManager::~ApplicationManager()
62ApplicationManager::~ApplicationManager()
@@ -94,6 +93,8 @@ QVariant ApplicationManager::data(const QModelIndex& index, int role) const {
94 return QVariant::fromValue(app->surface());
93 return QVariant::fromValue(app->surface());
95 case RoleFullscreen:
94 case RoleFullscreen:
96 return app->fullscreen();
95 return app->fullscreen();
96+ case RoleApplication:
97+ return QVariant::fromValue(app);
97 default:
98 default:
98 return QVariant();
99 return QVariant();
99 }
100 }
@@ -136,7 +137,6 @@ void ApplicationManager::add(ApplicationInfo *application) {
136 Q_EMIT applicationAdded(application->appId());
137 Q_EMIT applicationAdded(application->appId());
137 Q_EMIT countChanged();
138 Q_EMIT countChanged();
138 if (count() == 1) Q_EMIT emptyChanged(isEmpty()); // was empty but not anymore
139 if (count() == 1) Q_EMIT emptyChanged(isEmpty()); // was empty but not anymore
139− Q_EMIT focusRequested(application->appId());
140
140
141 connect(application, &ApplicationInfo::surfaceChanged, this, [application, this]() {
141 connect(application, &ApplicationInfo::surfaceChanged, this, [application, this]() {
142 QModelIndex appIndex = findIndex(application);
142 QModelIndex appIndex = findIndex(application);
@@ -222,6 +222,10 @@ ApplicationInfo* ApplicationManager::startApplication(const QString &appId,
222
222
223bool ApplicationManager::stopApplication(const QString &appId)
223bool ApplicationManager::stopApplication(const QString &appId)
224{
224{
225+ if (appId == "unity8-dash") {
226+ return false;
227+ }
228+
225 ApplicationInfo *application = findApplication(appId);
229 ApplicationInfo *application = findApplication(appId);
226 if (application == nullptr)
230 if (application == nullptr)
227 return false;
231 return false;
@@ -294,39 +298,25 @@ bool ApplicationManager::focusApplication(const QString &appId)
294 for (ApplicationInfo *app : m_runningApplications) {
298 for (ApplicationInfo *app : m_runningApplications) {
295 if (app->focused() && app->stage() == ApplicationInfo::MainStage) {
299 if (app->focused() && app->stage() == ApplicationInfo::MainStage) {
296 app->setFocused(false);
300 app->setFocused(false);
297− app->hideWindow();
298 app->setState(ApplicationInfo::Suspended);
301 app->setState(ApplicationInfo::Suspended);
299 }
302 }
300 }
303 }
301
304
302 // focus this app
305 // focus this app
303 application->setFocused(true);
306 application->setFocused(true);
304− if (!m_mainStage)
305− createMainStage();
306 application->setState(ApplicationInfo::Running);
307 application->setState(ApplicationInfo::Running);
307− application->showWindow(m_mainStage);
308− m_mainStage->setZ(-1000);
309− if (m_sideStage)
310− m_sideStage->setZ(-2000);
311 } else if (application->stage() == ApplicationInfo::SideStage) {
308 } else if (application->stage() == ApplicationInfo::SideStage) {
312 // unfocus currently focused sidestage app
309 // unfocus currently focused sidestage app
313 for (ApplicationInfo *app : m_runningApplications) {
310 for (ApplicationInfo *app : m_runningApplications) {
314 if (app->focused() && app->stage() == ApplicationInfo::SideStage) {
311 if (app->focused() && app->stage() == ApplicationInfo::SideStage) {
315 app->setFocused(false);
312 app->setFocused(false);
316− app->hideWindow();
317 app->setState(ApplicationInfo::Suspended);
313 app->setState(ApplicationInfo::Suspended);
318 }
314 }
319 }
315 }
320
316
321 // focus this app
317 // focus this app
322 application->setFocused(true);
318 application->setFocused(true);
323− if (!m_sideStage)
324− createSideStage();
325 application->setState(ApplicationInfo::Running);
319 application->setState(ApplicationInfo::Running);
326− application->showWindow(m_sideStage);
327− m_sideStage->setZ(-1000);
328− if (m_mainStage)
329− m_mainStage->setZ(-2000);
330 }
320 }
331
321
332 // move app to top of stack
322 // move app to top of stack
@@ -337,18 +327,14 @@ bool ApplicationManager::focusApplication(const QString &appId)
337
327
338bool ApplicationManager::requestFocusApplication(const QString &appId)
328bool ApplicationManager::requestFocusApplication(const QString &appId)
339{
329{
340− if (appId != focusedApplicationId()) {
341− QMetaObject::invokeMethod(this, "focusRequested", Qt::QueuedConnection, Q_ARG(QString, appId));
330+ QMetaObject::invokeMethod(this, "focusRequested", Qt::QueuedConnection, Q_ARG(QString, appId));
342− return true;
331+ return true;
343− }
344− return false;
345}
332}
346
333
347void ApplicationManager::unfocusCurrentApplication()
334void ApplicationManager::unfocusCurrentApplication()
348{
335{
349 for (ApplicationInfo *app : m_runningApplications) {
336 for (ApplicationInfo *app : m_runningApplications) {
350 if (app->focused()) {
337 if (app->focused()) {
351− app->hideWindow();
352 app->setFocused(false);
338 app->setFocused(false);
353 }
339 }
354 }
340 }
@@ -357,42 +343,6 @@ void ApplicationManager::unfocusCurrentApplication()
357
343
358void ApplicationManager::generateQmlStrings(ApplicationInfo *application)
344void ApplicationManager::generateQmlStrings(ApplicationInfo *application)
359{
345{
360− // TODO: Is there a better way of solving this fullscreen vs. regular
361− // application height?
362− QString topMargin;
363− if (application->fullscreen()) {
364− topMargin.append("0");
365− } else {
366− // Taken from Panel.panelHeight
367− topMargin.append("units.gu(3) + units.dp(2)");
368− }
369−
370− QString windowQml = QString(
371− "import QtQuick 2.0\n"
372− "Image {\n"
373− " anchors.fill: parent\n"
374− " anchors.topMargin: %1\n"
375− " anchors.rightMargin: %2\n"
376− " source: \"file://%3/Dash/graphics/phone/screenshots/%4.png\"\n"
377− " smooth: true\n"
378− " fillMode: Image.PreserveAspectCrop\n"
379− "}").arg(topMargin)
380− .arg(m_rightMargin)
381− .arg(qmlDirectory())
382− .arg(application->icon().toString());
383− application->setWindowQml(windowQml);
384−
385− QString imageQml = QString(
386− "import QtQuick 2.0\n"
387− "Image {\n"
388− " anchors.fill: parent\n"
389− " source: \"file://%1/Dash/graphics/phone/screenshots/%2.png\"\n"
390− " smooth: true\n"
391− " fillMode: Image.PreserveAspectCrop\n"
392− "}").arg(qmlDirectory())
393− .arg(application->icon().toString());
394− application->setImageQml(imageQml);
395−
396 application->setScreenshot(QString("file://%1/Dash/graphics/phone/screenshots/%2@12.png").arg(qmlDirectory())
346 application->setScreenshot(QString("file://%1/Dash/graphics/phone/screenshots/%2@12.png").arg(qmlDirectory())
397 .arg(application->icon().toString()));
347 .arg(application->icon().toString()));
398}
348}
@@ -401,6 +351,14 @@ void ApplicationManager::buildListOfAvailableApplications()
401{
351{
402 ApplicationInfo *application;
352 ApplicationInfo *application;
403
353
354+ application = new ApplicationInfo(this);
355+ application->setAppId("unity8-dash");
356+ application->setName("Unity 8 Mock Dash");
357+ application->setIcon(QUrl("unity8-dash"));
358+ application->setStage(ApplicationInfo::MainStage);
359+ generateQmlStrings(application);
360+ m_availableApplications.append(application);
361+
404 application = new ApplicationInfo(this);
362 application = new ApplicationInfo(this);
405 application->setAppId("dialer-app");
363 application->setAppId("dialer-app");
406 application->setName("Dialer");
364 application->setName("Dialer");
@@ -521,78 +479,6 @@ void ApplicationManager::buildListOfAvailableApplications()
521 m_availableApplications.append(application);
479 m_availableApplications.append(application);
522}
480}
523
481
524−void ApplicationManager::createMainStageComponent()
525−{
526− // The assumptions I make here really should hold.
527− QQuickView *quickView =
528− qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]);
529−
530− QQmlEngine *engine = quickView->engine();
531−
532− m_mainStageComponent = new QQmlComponent(engine, this);
533− QString mainStageQml =
534− "import QtQuick 2.0\n"
535− "Rectangle {\n"
536− " anchors.fill: parent\n"
537− " color: 'black'\n"
538− " z: -2000\n"
539− "}\n";
540− m_mainStageComponent->setData(mainStageQml.toLatin1(), QUrl());
541−}
542−
543−void ApplicationManager::createMainStage()
544−{
545− if (!m_mainStageComponent)
546− createMainStageComponent();
547−
548− // The assumptions I make here really should hold.
549− QQuickView *quickView =
550− qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]);
551−
552− QQuickItem *shell = quickView->rootObject();
553−
554− m_mainStage = qobject_cast<QQuickItem *>(m_mainStageComponent->create());
555− m_mainStage->setParentItem(shell);
556−}
557−
558−void ApplicationManager::createSideStageComponent()
559−{
560− // The assumptions I make here really should hold.
561− QQuickView *quickView =
562− qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]);
563−
564− QQmlEngine *engine = quickView->engine();
565−
566− m_sideStageComponent = new QQmlComponent(engine, this);
567− QString sideStageQml =
568− "import QtQuick 2.0\n"
569− "import Ubuntu.Components 0.1\n"
570− "Item {\n"
571− " width: units.gu(40)\n" // from SideStage in Shell.qml
572− " anchors.top: parent.top\n"
573− " anchors.bottom: parent.bottom\n"
574− " anchors.right: parent.right\n"
575− " z: -1000\n"
576− "}\n";
577− m_sideStageComponent->setData(sideStageQml.toLatin1(), QUrl());
578−}
579−
580−void ApplicationManager::createSideStage()
581−{
582− if (!m_sideStageComponent)
583− createSideStageComponent();
584−
585− // The assumptions I make here really should hold.
586− QQuickView *quickView =
587− qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]);
588−
589− QQuickItem *shell = quickView->rootObject();
590−
591− m_sideStage = qobject_cast<QQuickItem *>(m_sideStageComponent->create());
592− m_sideStage->setParentItem(shell);
593− m_sideStage->setFlag(QQuickItem::ItemHasContents, false);
594−}
595−
596QStringList ApplicationManager::availableApplications()
482QStringList ApplicationManager::availableApplications()
597{
483{
598 QStringList appIds;
484 QStringList appIds;
@@ -602,19 +488,6 @@ QStringList ApplicationManager::availableApplications()
602 return appIds;
488 return appIds;
603}
489}
604
490
605−int ApplicationManager::rightMargin() const
606−{
607− return m_rightMargin;
608−}
609−
610−void ApplicationManager::setRightMargin(int rightMargin)
611−{
612− m_rightMargin = rightMargin;
613− Q_FOREACH(ApplicationInfo *app, m_availableApplications) {
614− generateQmlStrings(app);
615− }
616−}
617−
618bool ApplicationManager::isEmpty() const
491bool ApplicationManager::isEmpty() const
619{
492{
620 return m_runningApplications.isEmpty();
493 return m_runningApplications.isEmpty();
tests/mocks/Unity/Application/ApplicationManager.h+1−16
@@ -44,10 +44,6 @@ class ApplicationManager : public ApplicationManagerInterface {
44
44
45 Q_PROPERTY(bool fake READ fake CONSTANT)
45 Q_PROPERTY(bool fake READ fake CONSTANT)
46
46
47− // Only for testing
48− // This can be used to place some controls to right, like make tryPhoneStage for example
49− Q_PROPERTY(int rightMargin READ rightMargin WRITE setRightMargin)
50−
51 public:
47 public:
52 ApplicationManager(QObject *parent = NULL);
48 ApplicationManager(QObject *parent = NULL);
53 virtual ~ApplicationManager();
49 virtual ~ApplicationManager();
@@ -57,6 +53,7 @@ class ApplicationManager : public ApplicationManagerInterface {
57 enum MoreRoles {
53 enum MoreRoles {
58 RoleSurface = RoleScreenshot+1,
54 RoleSurface = RoleScreenshot+1,
59 RoleFullscreen,
55 RoleFullscreen,
56+ RoleApplication,
60 };
57 };
61 enum Role {
58 enum Role {
62 Dash, Default, Indicators, Notifications, Greeter, Launcher, OnScreenKeyboard,
59 Dash, Default, Indicators, Notifications, Greeter, Launcher, OnScreenKeyboard,
@@ -108,8 +105,6 @@ class ApplicationManager : public ApplicationManagerInterface {
108
105
109 // Only for testing
106 // Only for testing
110 Q_INVOKABLE QStringList availableApplications();
107 Q_INVOKABLE QStringList availableApplications();
111− int rightMargin() const;
112− void setRightMargin(int rightMargin);
113
108
114 QModelIndex findIndex(ApplicationInfo* application);
109 QModelIndex findIndex(ApplicationInfo* application);
115
110
@@ -126,19 +121,9 @@ class ApplicationManager : public ApplicationManagerInterface {
126 void showApplicationWindow(ApplicationInfo *application);
121 void showApplicationWindow(ApplicationInfo *application);
127 void buildListOfAvailableApplications();
122 void buildListOfAvailableApplications();
128 void generateQmlStrings(ApplicationInfo *application);
123 void generateQmlStrings(ApplicationInfo *application);
129− void createMainStageComponent();
130− void createMainStage();
131− void createSideStageComponent();
132− void createSideStage();
133 bool m_suspended;
124 bool m_suspended;
134 QList<ApplicationInfo*> m_runningApplications;
125 QList<ApplicationInfo*> m_runningApplications;
135 QList<ApplicationInfo*> m_availableApplications;
126 QList<ApplicationInfo*> m_availableApplications;
136− QQmlComponent *m_mainStageComponent;
137− QQuickItem *m_mainStage;
138− QQmlComponent *m_sideStageComponent;
139− QQuickItem *m_sideStage;
140−
141− int m_rightMargin;
142
127
143 static ApplicationManager *the_application_manager;
128 static ApplicationManager *the_application_manager;
144};
129};
tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp+1−1
@@ -64,7 +64,7 @@ QImage ApplicationScreenshotProvider::requestImage(const QString &imageId, QSize
64 Q_FOREACH (QWindow *win, unity->allWindows()) {
64 Q_FOREACH (QWindow *win, unity->allWindows()) {
65 QQuickWindow *quickWin = qobject_cast<QQuickWindow*>(win);
65 QQuickWindow *quickWin = qobject_cast<QQuickWindow*>(win);
66 if (quickWin) {
66 if (quickWin) {
67− image = image.scaledToWidth(quickWin->width() - m_appManager->rightMargin());
67+ image = image.scaledToWidth(quickWin->width());
68 break;
68 break;
69 }
69 }
70 }
70 }
tests/mocks/Unity/Application/MirSurfaceItem.cpp+16−8
@@ -34,6 +34,8 @@ MirSurfaceItem::MirSurfaceItem(const QString& name,
34 , m_parentSurface(nullptr)
34 , m_parentSurface(nullptr)
35 , m_haveInputMethod(false)
35 , m_haveInputMethod(false)
36{
36{
37+ qDebug() << "MirSurfaceItem::MirSurfaceItem() " << this->name();
38+
37 QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
39 QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
38
40
39 // The virtual keyboard (input method) has a big transparent area so that
41 // The virtual keyboard (input method) has a big transparent area so that
@@ -46,6 +48,8 @@ MirSurfaceItem::MirSurfaceItem(const QString& name,
46
48
47MirSurfaceItem::~MirSurfaceItem()
49MirSurfaceItem::~MirSurfaceItem()
48{
50{
51+ qDebug() << "MirSurfaceItem::~MirSurfaceItem() " << name();
52+
49 QList<MirSurfaceItem*> children(m_children);
53 QList<MirSurfaceItem*> children(m_children);
50 for (MirSurfaceItem* child : children) {
54 for (MirSurfaceItem* child : children) {
51 child->setParentSurface(nullptr);
55 child->setParentSurface(nullptr);
@@ -54,7 +58,7 @@ MirSurfaceItem::~MirSurfaceItem()
54 m_parentSurface->removeChildSurface(this);
58 m_parentSurface->removeChildSurface(this);
55
59
56 if (m_application)
60 if (m_application)
57− m_application->setSurface(nullptr);
61+ m_application->removeSurface(this);
58}
62}
59
63
60void MirSurfaceItem::paint(QPainter * painter)
64void MirSurfaceItem::paint(QPainter * painter)
@@ -75,7 +79,7 @@ void MirSurfaceItem::release()
75 }
79 }
76
80
77 if (m_application) {
81 if (m_application) {
78− m_application->setSurface(nullptr);
82+ m_application->removeSurface(this);
79 }
83 }
80 if (!parent()) {
84 if (!parent()) {
81 deleteLater();
85 deleteLater();
@@ -104,20 +108,24 @@ void MirSurfaceItem::setParentSurface(MirSurfaceItem* surface)
104 Q_EMIT parentSurfaceChanged(surface);
108 Q_EMIT parentSurfaceChanged(surface);
105}
109}
106
110
111+void MirSurfaceItem::addChildSurface(MirSurfaceItem* surface)
112+{
113+ qDebug() << "MirSurfaceItem::addChildSurface " << surface->name() << " to " << name();
114+
115+ m_children.append(surface);
116+ Q_EMIT childSurfacesChanged();
117+}
118+
107void MirSurfaceItem::removeChildSurface(MirSurfaceItem* surface)
119void MirSurfaceItem::removeChildSurface(MirSurfaceItem* surface)
108{
120{
121+ qDebug() << "MirSurfaceItem::removeChildSurface " << surface->name() << " from " << name();
122+
109 if (m_children.contains(surface)) {
123 if (m_children.contains(surface)) {
110 m_children.removeOne(surface);
124 m_children.removeOne(surface);
111 Q_EMIT childSurfacesChanged();
125 Q_EMIT childSurfacesChanged();
112 }
126 }
113}
127}
114
128
115−void MirSurfaceItem::addChildSurface(MirSurfaceItem* surface)
116−{
117− m_children.append(surface);
118− Q_EMIT childSurfacesChanged();
119−}
120−
121QList<MirSurfaceItem*> MirSurfaceItem::childSurfaceList()
129QList<MirSurfaceItem*> MirSurfaceItem::childSurfaceList()
122{
130{
123 return m_children;
131 return m_children;
tests/mocks/Unity/Application/MirSurfaceItem.h+1
@@ -117,5 +117,6 @@ private:
117};
117};
118
118
119Q_DECLARE_METATYPE(MirSurfaceItem*)
119Q_DECLARE_METATYPE(MirSurfaceItem*)
120+Q_DECLARE_METATYPE(QList<MirSurfaceItem*>)
120
121
121#endif // MIRSURFACEITEM_H
122#endif // MIRSURFACEITEM_H
tests/mocks/Unity/CMakeLists.txt+4−3
@@ -2,11 +2,12 @@ add_subdirectory(Application)
2add_subdirectory(Indicators)
2add_subdirectory(Indicators)
3add_subdirectory(Launcher)
3add_subdirectory(Launcher)
4add_subdirectory(Notifications)
4add_subdirectory(Notifications)
5+add_subdirectory(DashCommunicator)
5
6
6pkg_search_module(DEE dee-1.0 REQUIRED)
7pkg_search_module(DEE dee-1.0 REQUIRED)
7pkg_search_module(GOBJECT gobject-2.0 REQUIRED)
8pkg_search_module(GOBJECT gobject-2.0 REQUIRED)
8pkg_search_module(DEEQT libdee-qt5 REQUIRED)
9pkg_search_module(DEEQT libdee-qt5 REQUIRED)
9−pkg_check_modules(SCOPES_API REQUIRED unity-shell-scopes=3)
10+pkg_check_modules(SCOPES_API REQUIRED unity-shell-scopes=4)
10
11
11include_directories(
12include_directories(
12 ${CMAKE_CURRENT_BINARY_DIR}
13 ${CMAKE_CURRENT_BINARY_DIR}
@@ -22,14 +23,14 @@ set(UnityQML_SOURCES
22 fake_scope.cpp
23 fake_scope.cpp
23 fake_scopes.cpp
24 fake_scopes.cpp
24 fake_categories.cpp
25 fake_categories.cpp
25− fake_department.cpp
26+ fake_navigation.cpp
26 fake_resultsmodel.cpp
27 fake_resultsmodel.cpp
27 fake_previewmodel.cpp
28 fake_previewmodel.cpp
28 fake_previewstack.cpp
29 fake_previewstack.cpp
29 fake_previewwidgetmodel.cpp
30 fake_previewwidgetmodel.cpp
30 fake_unity_plugin.cpp
31 fake_unity_plugin.cpp
31 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/CategoriesInterface.h
32 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/CategoriesInterface.h
32− ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/DepartmentInterface.h
33+ ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/NavigationInterface.h
33 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/PreviewModelInterface.h
34 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/PreviewModelInterface.h
34 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/PreviewStackInterface.h
35 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/PreviewStackInterface.h
35 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/PreviewWidgetModelInterface.h
36 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/PreviewWidgetModelInterface.h
tests/mocks/Unity/DashCommunicator/CMakeLists.txtnew file+18
@@ -0,0 +1,18 @@
1+include_directories(
2+ ${CMAKE_CURRENT_SOURCE_DIR}
3+)
4+
5+set(QMLDASHCOMMUNICATORPLUGIN_SRC
6+ plugin.cpp
7+ dashcommunicatorservice.cpp
8+ dashcommunicator.cpp
9+ )
10+
11+add_library(MockDashCommunicator-qml MODULE
12+ ${QMLDASHCOMMUNICATORPLUGIN_SRC}
13+ )
14+
15+qt5_use_modules(MockDashCommunicator-qml DBus Qml)
16+
17+# export the qmldir and qmltypes files
18+add_unity8_mock(Unity.DashCommunicator 0.1 Unity/DashCommunicator TARGETS MockDashCommunicator-qml)
tests/mocks/Unity/DashCommunicator/dashcommunicator.cppnew file+37
@@ -0,0 +1,37 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "dashcommunicator.h"
18+
19+#include <QObject>
20+#include <QDBusConnection>
21+#include <QDBusInterface>
22+#include <QDebug>
23+
24+DashCommunicator::DashCommunicator(QObject *parent):
25+ QObject(parent)
26+{
27+}
28+
29+DashCommunicator::~DashCommunicator()
30+{
31+}
32+
33+
34+void DashCommunicator::setCurrentScope(const QString &scopeId, bool animate, bool reset)
35+{
36+ Q_EMIT setCurrentScopeCalled(scopeId, animate, reset);
37+}
tests/mocks/Unity/DashCommunicator/dashcommunicator.hnew file+39
@@ -0,0 +1,39 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef DASHCOMMUNICATOR_H
18+#define DASHCOMMUNICATOR_H
19+
20+#include <QObject>
21+
22+class DashCommunicator: public QObject
23+{
24+ Q_OBJECT
25+ Q_CLASSINFO("D-Bus Interface", "com.canonical.Unity.DashCommunicator")
26+
27+public:
28+ DashCommunicator(QObject *parent = 0);
29+ ~DashCommunicator();
30+
31+public Q_SLOTS:
32+ void setCurrentScope(const QString &scopeId, bool animate, bool reset);
33+
34+Q_SIGNALS:
35+ // This mock just emits calls back to the QML api for the plugin to verify calls
36+ void setCurrentScopeCalled(const QString &scopeId, bool animate, bool reset);
37+};
38+
39+#endif
tests/mocks/Unity/DashCommunicator/dashcommunicatorservice.cppnew file+33
@@ -0,0 +1,33 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "dashcommunicatorservice.h"
18+
19+DashCommunicatorService::DashCommunicatorService(QObject *parent):
20+ QObject(parent)
21+{
22+}
23+
24+
25+DashCommunicatorService::~DashCommunicatorService()
26+{
27+
28+}
29+
30+void DashCommunicatorService::mockSetCurrentScope(const QString &scopeId, bool animate, bool reset)
31+{
32+ Q_EMIT setCurrentScopeRequested(scopeId, animate, reset);
33+}
tests/mocks/Unity/DashCommunicator/dashcommunicatorservice.hnew file+36
@@ -0,0 +1,36 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef DASHCOMMUNICATORSERVICE_H
18+#define DASHCOMMUNICATORSERVICE_H
19+
20+#include <QObject>
21+
22+class DashCommunicatorService: public QObject
23+{
24+ Q_OBJECT
25+public:
26+ DashCommunicatorService(QObject *parent = 0);
27+ ~DashCommunicatorService();
28+
29+Q_SIGNALS:
30+ void setCurrentScopeRequested(const QString &scopeId, bool animate, bool reset);
31+
32+public Q_SLOTS:
33+ void mockSetCurrentScope(const QString &scopeId, bool animate, bool reset);
34+};
35+
36+#endif // DBUSUNITYSESSIONSERVICE_H
tests/mocks/Unity/DashCommunicator/plugin.cppnew file+31
@@ -0,0 +1,31 @@
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+ * Authors: Michael Zanetti <michael.zanetti@canonical.com>
17+ */
18+
19+#include "plugin.h"
20+#include "dashcommunicator.h"
21+#include "dashcommunicatorservice.h"
22+
23+#include <QDBusConnection>
24+#include <QtQml/qqml.h>
25+
26+void DashCommunicatorPlugin::registerTypes(const char *uri)
27+{
28+ Q_ASSERT(uri == QStringLiteral("Unity.DashCommunicator"));
29+ qmlRegisterType<DashCommunicatorService>(uri, 0, 1, "DashCommunicatorService");
30+ qmlRegisterType<DashCommunicator>(uri, 0, 1, "DashCommunicator");
31+}
tests/mocks/Unity/DashCommunicator/plugin.hnew file+34
@@ -0,0 +1,34 @@
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+ * Authors: Michael Zanetti <michael.zanetti@canonical.com>
17+ */
18+
19+#ifndef DASHCOMMUNICATOR_PLUGIN_H
20+#define DASHCOMMUNICATOR_PLUGIN_H
21+
22+#include <QtQml/QQmlEngine>
23+#include <QtQml/QQmlExtensionPlugin>
24+
25+class DashCommunicatorPlugin : public QQmlExtensionPlugin
26+{
27+ Q_OBJECT
28+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
29+
30+public:
31+ void registerTypes(const char *uri);
32+};
33+
34+#endif
tests/mocks/Unity/DashCommunicator/qmldirnew file+3
@@ -0,0 +1,3 @@
1+module Unity.DashCommunicator
2+plugin MockDashCommunicator-qml
3+typeinfo DashCommunicator.qmltypes
tests/mocks/Unity/Unity.qmltypes+79−27
@@ -24,6 +24,12 @@ Module {
24 Parameter { name: "categoryId"; type: "string" }
24 Parameter { name: "categoryId"; type: "string" }
25 Parameter { name: "json"; type: "string" }
25 Parameter { name: "json"; type: "string" }
26 }
26 }
27+ Method {
28+ name: "data"
29+ type: "QVariant"
30+ Parameter { name: "row"; type: "int" }
31+ Parameter { name: "role"; type: "int" }
32+ }
27 }
33 }
28 Component {
34 Component {
29 name: "PreviewModel"
35 name: "PreviewModel"
@@ -62,6 +68,10 @@ Module {
62 prototype: "unity::shell::scopes::ScopeInterface"
68 prototype: "unity::shell::scopes::ScopeInterface"
63 exports: ["Unity/MockScope 0.2"]
69 exports: ["Unity/MockScope 0.2"]
64 exportMetaObjectRevisions: [0]
70 exportMetaObjectRevisions: [0]
71+ Signal {
72+ name: "performQuery"
73+ Parameter { name: "query"; type: "string" }
74+ }
65 Method {
75 Method {
66 name: "setSearchInProgress"
76 name: "setSearchInProgress"
67 Parameter { name: "inProg"; type: "bool" }
77 Parameter { name: "inProg"; type: "bool" }
@@ -81,18 +91,21 @@ Module {
81 Parameter { name: "scope"; type: "unity::shell::scopes::ScopeInterface"; isPointer: true }
91 Parameter { name: "scope"; type: "unity::shell::scopes::ScopeInterface"; isPointer: true }
82 }
92 }
83 Method {
93 Method {
84− name: "getDepartment"
94+ name: "getNavigation"
85− type: "unity::shell::scopes::DepartmentInterface*"
95+ type: "unity::shell::scopes::NavigationInterface*"
86− Parameter { name: "id"; type: "string" }
96+ Parameter { name: "navigationId"; type: "string" }
87 }
97 }
88 Method {
98 Method {
89− name: "loadDepartment"
99+ name: "getAltNavigation"
100+ type: "unity::shell::scopes::NavigationInterface*"
90− Parameter { name: "id"; type: "string" }
101+ Parameter { name: "altNavigationId"; type: "string" }
91 }
102 }
92 Method {
103 Method {
93− name: "performQuery"
104+ name: "setNavigationState"
94− Parameter { name: "query"; type: "string" }
105+ Parameter { name: "navigationId"; type: "string" }
106+ Parameter { name: "isAltNavigation"; type: "bool" }
95 }
107 }
108+ Method { name: "refresh" }
96 }
109 }
97 Component {
110 Component {
98 name: "Scopes"
111 name: "Scopes"
@@ -137,6 +150,7 @@ Module {
137 "RoleRawRendererTemplate": 3,
150 "RoleRawRendererTemplate": 3,
138 "RoleRenderer": 4,
151 "RoleRenderer": 4,
139 "RoleComponents": 5,
152 "RoleComponents": 5,
153+ "RoleHeaderLink": 6,
140 "RoleResults": 7,
154 "RoleResults": 7,
141 "RoleCount": 8
155 "RoleCount": 8
142 }
156 }
@@ -157,27 +171,28 @@ Module {
157 }
171 }
158 }
172 }
159 Component {
173 Component {
160− name: "unity::shell::scopes::DepartmentInterface"
174+ name: "unity::shell::scopes::NavigationInterface"
161 prototype: "QAbstractListModel"
175 prototype: "QAbstractListModel"
162− exports: ["Unity/Department 0.2"]
176+ exports: ["Unity/Navigation 0.2"]
163 isCreatable: false
177 isCreatable: false
164 exportMetaObjectRevisions: [0]
178 exportMetaObjectRevisions: [0]
165 Enum {
179 Enum {
166 name: "Roles"
180 name: "Roles"
167 values: {
181 values: {
168− "RoleDepartmentId": 0,
182+ "RoleNavigationId": 0,
169 "RoleLabel": 1,
183 "RoleLabel": 1,
170 "RoleHasChildren": 2,
184 "RoleHasChildren": 2,
171 "RoleIsActive": 3
185 "RoleIsActive": 3
172 }
186 }
173 }
187 }
174− Property { name: "departmentId"; type: "string"; isReadonly: true }
188+ Property { name: "navigationId"; type: "string"; isReadonly: true }
175 Property { name: "label"; type: "string"; isReadonly: true }
189 Property { name: "label"; type: "string"; isReadonly: true }
176 Property { name: "allLabel"; type: "string"; isReadonly: true }
190 Property { name: "allLabel"; type: "string"; isReadonly: true }
177− Property { name: "parentDepartmentId"; type: "string"; isReadonly: true }
191+ Property { name: "parentNavigationId"; type: "string"; isReadonly: true }
178 Property { name: "parentLabel"; type: "string"; isReadonly: true }
192 Property { name: "parentLabel"; type: "string"; isReadonly: true }
179 Property { name: "loaded"; type: "bool"; isReadonly: true }
193 Property { name: "loaded"; type: "bool"; isReadonly: true }
180 Property { name: "isRoot"; type: "bool"; isReadonly: true }
194 Property { name: "isRoot"; type: "bool"; isReadonly: true }
195+ Property { name: "hidden"; type: "bool"; isReadonly: true }
181 Property { name: "count"; type: "int"; isReadonly: true }
196 Property { name: "count"; type: "int"; isReadonly: true }
182 }
197 }
183 Component {
198 Component {
@@ -247,7 +262,8 @@ Module {
247 "RoleEmblem": 8,
262 "RoleEmblem": 8,
248 "RoleSummary": 9,
263 "RoleSummary": 9,
249 "RoleAttributes": 10,
264 "RoleAttributes": 10,
250− "RoleBackground": 11
265+ "RoleBackground": 11,
266+ "RoleOverlayColor": 12
251 }
267 }
252 }
268 }
253 Property { name: "categoryId"; type: "string" }
269 Property { name: "categoryId"; type: "string" }
@@ -259,13 +275,22 @@ Module {
259 exports: ["Unity/Scope 0.2"]
275 exports: ["Unity/Scope 0.2"]
260 isCreatable: false
276 isCreatable: false
261 exportMetaObjectRevisions: [0]
277 exportMetaObjectRevisions: [0]
278+ Enum {
279+ name: "Status"
280+ values: {
281+ "Okay": 0,
282+ "NoInternet": 1,
283+ "NoLocationData": 2,
284+ "Unknown": 3
285+ }
286+ }
262 Property { name: "id"; type: "string"; isReadonly: true }
287 Property { name: "id"; type: "string"; isReadonly: true }
263 Property { name: "name"; type: "string"; isReadonly: true }
288 Property { name: "name"; type: "string"; isReadonly: true }
264 Property { name: "iconHint"; type: "string"; isReadonly: true }
289 Property { name: "iconHint"; type: "string"; isReadonly: true }
265 Property { name: "description"; type: "string"; isReadonly: true }
290 Property { name: "description"; type: "string"; isReadonly: true }
266 Property { name: "searchHint"; type: "string"; isReadonly: true }
291 Property { name: "searchHint"; type: "string"; isReadonly: true }
267 Property { name: "searchInProgress"; type: "bool"; isReadonly: true }
292 Property { name: "searchInProgress"; type: "bool"; isReadonly: true }
268− Property { name: "visible"; type: "bool"; isReadonly: true }
293+ Property { name: "favorite"; type: "bool" }
269 Property { name: "shortcut"; type: "string"; isReadonly: true }
294 Property { name: "shortcut"; type: "string"; isReadonly: true }
270 Property {
295 Property {
271 name: "categories"
296 name: "categories"
@@ -273,13 +298,27 @@ Module {
273 isReadonly: true
298 isReadonly: true
274 isPointer: true
299 isPointer: true
275 }
300 }
301+ Property {
302+ name: "settings"
303+ type: "unity::shell::scopes::SettingsModelInterface"
304+ isReadonly: true
305+ isPointer: true
306+ }
276 Property { name: "searchQuery"; type: "string" }
307 Property { name: "searchQuery"; type: "string" }
277 Property { name: "noResultsHint"; type: "string" }
308 Property { name: "noResultsHint"; type: "string" }
278 Property { name: "formFactor"; type: "string" }
309 Property { name: "formFactor"; type: "string" }
279 Property { name: "isActive"; type: "bool" }
310 Property { name: "isActive"; type: "bool" }
311+ Property { name: "currentNavigationId"; type: "string"; isReadonly: true }
312+ Property { name: "hasNavigation"; type: "bool"; isReadonly: true }
280− Property { name: "currentDepartmentId"; type: "string"; isReadonly: true }
313+ Property { name: "currentAltNavigationId"; type: "string"; isReadonly: true }
281− Property { name: "hasDepartments"; type: "bool"; isReadonly: true }
314+ Property { name: "hasAltNavigation"; type: "bool"; isReadonly: true }
282 Property { name: "customizations"; type: "QVariantMap"; isReadonly: true }
315 Property { name: "customizations"; type: "QVariantMap"; isReadonly: true }
316+ Property {
317+ name: "status"
318+ type: "unity::shell::scopes::ScopeInterface::Status"
319+ isReadonly: true
320+ }
321+ Signal { name: "detailsChanged" }
283 Signal { name: "showDash" }
322 Signal { name: "showDash" }
284 Signal { name: "hideDash" }
323 Signal { name: "hideDash" }
285 Signal {
324 Signal {
@@ -298,10 +337,6 @@ Module {
298 name: "openScope"
337 name: "openScope"
299 Parameter { name: "scope"; type: "unity::shell::scopes::ScopeInterface"; isPointer: true }
338 Parameter { name: "scope"; type: "unity::shell::scopes::ScopeInterface"; isPointer: true }
300 }
339 }
301− Signal {
302− name: "activateApplication"
303− Parameter { name: "desktop"; type: "string" }
304− }
305 Method {
340 Method {
306 name: "activate"
341 name: "activate"
307 Parameter { name: "result"; type: "QVariant" }
342 Parameter { name: "result"; type: "QVariant" }
@@ -317,14 +352,25 @@ Module {
317 Parameter { name: "scope"; type: "unity::shell::scopes::ScopeInterface"; isPointer: true }
352 Parameter { name: "scope"; type: "unity::shell::scopes::ScopeInterface"; isPointer: true }
318 }
353 }
319 Method {
354 Method {
320− name: "getDepartment"
355+ name: "getNavigation"
321− type: "unity::shell::scopes::DepartmentInterface*"
356+ type: "unity::shell::scopes::NavigationInterface*"
322− Parameter { name: "departmentId"; type: "string" }
357+ Parameter { name: "navigationId"; type: "string" }
358+ }
359+ Method {
360+ name: "getAltNavigation"
361+ type: "unity::shell::scopes::NavigationInterface*"
362+ Parameter { name: "altNavigationId"; type: "string" }
323 }
363 }
324 Method {
364 Method {
325− name: "loadDepartment"
365+ name: "setNavigationState"
326− Parameter { name: "departmentId"; type: "string" }
366+ Parameter { name: "navId"; type: "string" }
367+ Parameter { name: "altNavigation"; type: "bool" }
327 }
368 }
369+ Method {
370+ name: "performQuery"
371+ Parameter { name: "cannedQuery"; type: "string" }
372+ }
373+ Method { name: "refresh" }
328 }
374 }
329 Component {
375 Component {
330 name: "unity::shell::scopes::ScopesInterface"
376 name: "unity::shell::scopes::ScopesInterface"
@@ -334,11 +380,17 @@ Module {
334 values: {
380 values: {
335 "RoleScope": 0,
381 "RoleScope": 0,
336 "RoleId": 1,
382 "RoleId": 1,
337− "RoleVisible": 2,
338− "RoleTitle": 3
383+ "RoleTitle": 2
339 }
384 }
340 }
385 }
341 Property { name: "loaded"; type: "bool"; isReadonly: true }
386 Property { name: "loaded"; type: "bool"; isReadonly: true }
387+ Property { name: "count"; type: "int"; isReadonly: true }
388+ Property {
389+ name: "overviewScope"
390+ type: "unity::shell::scopes::ScopeInterface"
391+ isReadonly: true
392+ isPointer: true
393+ }
342 Method {
394 Method {
343 name: "getScope"
395 name: "getScope"
344 type: "unity::shell::scopes::ScopeInterface*"
396 type: "unity::shell::scopes::ScopeInterface*"
tests/mocks/Unity/fake_department.cpp → tests/mocks/Unity/fake_navigation.cpprenamed+32−40
@@ -14,14 +14,15 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
15 */
16
16
17−#include "fake_department.h"
17+#include "fake_navigation.h"
18
18
19#include "fake_scope.h"
19#include "fake_scope.h"
20
20
21+#include <QDebug>
21#include <QTimer>
22#include <QTimer>
22
23
23−Department::Department(const QString& departmentId, const QString& label, const QString& allLabel, const QString& parentId, const QString& parentLabel, Scope* scope)
24+Navigation::Navigation(const QString& navigationId, const QString& label, const QString& allLabel, const QString& parentId, const QString& parentLabel, Scope* scope)
24− : m_departmentId(departmentId)
25+ : m_navigationId(navigationId)
25 , m_label(label)
26 , m_label(label)
26 , m_allLabel(allLabel)
27 , m_allLabel(allLabel)
27 , m_parentId(parentId)
28 , m_parentId(parentId)
@@ -30,96 +31,87 @@ Department::Department(const QString& departmentId, const QString& label, const
30 , m_scope(scope)
31 , m_scope(scope)
31{
32{
32 QTimer::singleShot(1500, this, SLOT(slotLoaded()));
33 QTimer::singleShot(1500, this, SLOT(slotLoaded()));
33− connect(scope, SIGNAL(currentDepartmentIdChanged()), this, SLOT(slotCurrentDepartmentChanged()));
34+ connect(scope, SIGNAL(currentNavigationIdChanged()), this, SLOT(slotCurrentNavigationChanged()));
34}
35}
35
36
36−QString Department::departmentId() const
37+QString Navigation::navigationId() const
37{
38{
38− return m_departmentId;
39+ return m_navigationId;
39}
40}
40
41
41−QString Department::label() const
42+QString Navigation::label() const
42{
43{
43 return m_label;
44 return m_label;
44}
45}
45
46
46−QString Department::allLabel() const
47+QString Navigation::allLabel() const
47{
48{
48 return m_allLabel;
49 return m_allLabel;
49}
50}
50
51
51−QString Department::parentDepartmentId() const
52+QString Navigation::parentNavigationId() const
52{
53{
53 return m_parentId;
54 return m_parentId;
54}
55}
55
56
56−QString Department::parentLabel() const
57+QString Navigation::parentLabel() const
57{
58{
58 return m_parentLabel;
59 return m_parentLabel;
59}
60}
60
61
61−void Department::slotLoaded()
62+void Navigation::slotLoaded()
62{
63{
63 m_loaded = true;
64 m_loaded = true;
64 Q_EMIT loadedChanged();
65 Q_EMIT loadedChanged();
65}
66}
66
67
67−bool Department::loaded() const
68+bool Navigation::loaded() const
68{
69{
69 return m_loaded;
70 return m_loaded;
70}
71}
71
72
72−int Department::count() const
73+int Navigation::count() const
73{
74{
74 return rowCount();
75 return rowCount();
75}
76}
76
77
77−bool Department::isRoot() const
78+bool Navigation::isRoot() const
78{
79{
79− return m_departmentId == "root";
80+ return m_navigationId == "root" || m_navigationId == "altroot";
80}
81}
81
82
82−int Department::rowCount(const QModelIndex & /*parent*/) const
83+bool Navigation::hidden() const
83{
84{
84− if (!m_loaded || m_departmentId.startsWith("child") || m_departmentId == "middle3")
85+ return m_navigationId == "altroot";
85− return 0;
86− else
87− return 8;
88}
86}
89
87
90−QHash<int, QByteArray> Department::roleNames() const
88+int Navigation::rowCount(const QModelIndex & /*parent*/) const
91{
89{
92− QHash<int, QByteArray> res;
90+ if (!m_loaded || m_navigationId.startsWith("child") || m_navigationId == "middle3")
93− res[RoleDepartmentId] = "departmentId";
91+ return 0;
94− res[RoleLabel] = "label";
92+ else
95− res[RoleHasChildren] = "hasChildren";
96− res[RoleIsActive] = "isActive";
97− return res;
93+ return 8;
98}
94}
99
95
100−QVariant Department::data(const QModelIndex &index, int role) const
96+QVariant Navigation::data(const QModelIndex &index, int role) const
101{
97{
102 switch (role) {
98 switch (role) {
103− case RoleDepartmentId:
99+ case RoleNavigationId:
104− if (m_departmentId == "root")
100+ if (m_navigationId == "root")
105 return QString("middle%1").arg(index.row());
101 return QString("middle%1").arg(index.row());
106− else if (m_departmentId.startsWith("middle"))
102+ else if (m_navigationId.startsWith("middle"))
107− return QString("child%1%2").arg(m_departmentId).arg(index.row());
103+ return QString("child%1%2").arg(m_navigationId).arg(index.row());
108− break;
109 case RoleLabel:
104 case RoleLabel:
110− return QString("%1Child%2").arg(m_departmentId).arg(index.row());
105+ return QString("%1Child%2").arg(m_navigationId).arg(index.row());
111− break;
112 case RoleHasChildren:
106 case RoleHasChildren:
113− return m_departmentId == "root" && index.row() != 3;
107+ return m_navigationId == "root" && index.row() != 3;
114− break;
115 case RoleIsActive:
108 case RoleIsActive:
116− return m_scope->currentDepartmentId() == data(index, RoleDepartmentId);
109+ return m_scope->currentNavigationId() == data(index, RoleNavigationId);
117− break;
118 }
110 }
119 return QVariant();
111 return QVariant();
120}
112}
121
113
122−void Department::slotCurrentDepartmentChanged()
114+void Navigation::slotCurrentNavigationChanged()
123{
115{
124 // This is wasteful, should only emit it if really something changed in this
116 // This is wasteful, should only emit it if really something changed in this
125 // deparment, but this is a mock, so no need to optimize
117 // deparment, but this is a mock, so no need to optimize
tests/mocks/Unity/fake_department.h → tests/mocks/Unity/fake_navigation.hrenamed+13−13
@@ -14,48 +14,48 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
15 */
16
16
17−#ifndef FAKE_DEPARTMENT_H
17+#ifndef FAKE_NAVIGATION_H
18−#define FAKE_DEPARTMENT_H
18+#define FAKE_NAVIGATION_H
19
19
20−#include <unity/shell/scopes/DepartmentInterface.h>
20+#include <unity/shell/scopes/NavigationInterface.h>
21
21
22class Scope;
22class Scope;
23
23
24−class Department : public unity::shell::scopes::DepartmentInterface
24+class Navigation : public unity::shell::scopes::NavigationInterface
25{
25{
26 Q_OBJECT
26 Q_OBJECT
27
27
28public:
28public:
29− Department(const QString& departmentId, const QString& label, const QString& allLabel, const QString& parentId, const QString& parentLabel, Scope* scope);
29+ Navigation(const QString& navigationId, const QString& label, const QString& allLabel, const QString& parentId, const QString& parentLabel, Scope* scope);
30
30
31− QString departmentId() const override;
31+ QString navigationId() const override;
32 QString label() const override;
32 QString label() const override;
33 QString allLabel() const override;
33 QString allLabel() const override;
34− QString parentDepartmentId() const override;
34+ QString parentNavigationId() const override;
35 QString parentLabel() const override;
35 QString parentLabel() const override;
36 bool loaded() const override;
36 bool loaded() const override;
37− int count() const override;
38 bool isRoot() const override;
37 bool isRoot() const override;
38+ bool hidden() const override;
39+ int count() const override;
39
40
40 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
41 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
41− QHash<int, QByteArray> roleNames() const;
42 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
42 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
43
43
44public Q_SLOTS:
44public Q_SLOTS:
45− void slotCurrentDepartmentChanged();
45+ void slotCurrentNavigationChanged();
46
46
47private Q_SLOTS:
47private Q_SLOTS:
48 void slotLoaded();
48 void slotLoaded();
49
49
50private:
50private:
51− QString m_departmentId;
51+ QString m_navigationId;
52 QString m_label;
52 QString m_label;
53 QString m_allLabel;
53 QString m_allLabel;
54 QString m_parentId;
54 QString m_parentId;
55 QString m_parentLabel;
55 QString m_parentLabel;
56 bool m_loaded;
56 bool m_loaded;
57− QString m_currentDepartment;
57+ QString m_currentNavigation;
58 Scope *m_scope;
58 Scope *m_scope;
59};
59};
60
60
61−#endif // FAKE_DEPARTMENT_H
61+#endif // FAKE_NAVIGATION_H
tests/mocks/Unity/fake_scope.cpp+65−17
@@ -14,24 +14,26 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
15 */
16
16
17+#include <QDebug>
17#include <QUrl>
18#include <QUrl>
18
19
19#include "fake_scope.h"
20#include "fake_scope.h"
20−#include "fake_department.h"
21+#include "fake_navigation.h"
21#include "fake_resultsmodel.h"
22#include "fake_resultsmodel.h"
22
23
23Scope::Scope(QObject* parent) : Scope(QString(), QString(), false, parent)
24Scope::Scope(QObject* parent) : Scope(QString(), QString(), false, parent)
24{
25{
25}
26}
26
27
27−Scope::Scope(QString const& id, QString const& name, bool visible, QObject* parent, int categories)
28+Scope::Scope(QString const& id, QString const& name, bool favorite, QObject* parent, int categories)
28 : unity::shell::scopes::ScopeInterface(parent)
29 : unity::shell::scopes::ScopeInterface(parent)
29 , m_id(id)
30 , m_id(id)
30 , m_name(name)
31 , m_name(name)
31− , m_visible(visible)
32 , m_searching(false)
32 , m_searching(false)
33+ , m_favorite(favorite)
33 , m_isActive(false)
34 , m_isActive(false)
34− , m_currentDeparment("root")
35+ , m_currentNavigationId("root")
36+ , m_currentAltNavigationId("altroot")
35 , m_previewRendererName("preview-generic")
37 , m_previewRendererName("preview-generic")
36 , m_categories(new Categories(categories, this))
38 , m_categories(new Categories(categories, this))
37{
39{
@@ -77,6 +79,11 @@ bool Scope::searchInProgress() const
77 return m_searching;
79 return m_searching;
78}
80}
79
81
82+bool Scope::favorite() const
83+{
84+ return m_favorite;
85+}
86+
80unity::shell::scopes::CategoriesInterface* Scope::categories() const
87unity::shell::scopes::CategoriesInterface* Scope::categories() const
81{
88{
82 return m_categories;
89 return m_categories;
@@ -97,11 +104,6 @@ QString Scope::formFactor() const
97 return m_formFactor;
104 return m_formFactor;
98}
105}
99
106
100−bool Scope::visible() const
101−{
102− return m_visible;
103−}
104−
105bool Scope::isActive() const
107bool Scope::isActive() const
106{
108{
107 return m_isActive;
109 return m_isActive;
@@ -131,6 +133,13 @@ void Scope::setActive(const bool active)
131 }
133 }
132}
134}
133
135
136+void Scope::setFavorite(const bool favorite)
137+{
138+ if (favorite != m_favorite) {
139+ m_favorite = favorite;
140+ Q_EMIT favoriteChanged();
141+ }
142+}
134void Scope::setSearchInProgress(const bool inProg)
143void Scope::setSearchInProgress(const bool inProg)
135{
144{
136 if (inProg != m_searching) {
145 if (inProg != m_searching) {
@@ -170,16 +179,31 @@ void Scope::closeScope(unity::shell::scopes::ScopeInterface* /*scope*/)
170 qFatal("Scope::closeScope is not implemented");
179 qFatal("Scope::closeScope is not implemented");
171}
180}
172
181
173−QString Scope::currentDepartmentId() const
182+QString Scope::currentNavigationId() const
183+{
184+ return m_currentNavigationId;
185+}
186+
187+bool Scope::hasNavigation() const
188+{
189+ return true;
190+}
191+
192+QString Scope::currentAltNavigationId() const
174{
193{
175− return m_currentDeparment;
194+ return m_currentAltNavigationId;
176}
195}
177
196
178−bool Scope::hasDepartments() const
197+bool Scope::hasAltNavigation() const
179{
198{
180 return true;
199 return true;
181}
200}
182
201
202+Scope::Status Scope::status() const
203+{
204+ return Status::Okay;
205+}
206+
183QVariantMap Scope::customizations() const
207QVariantMap Scope::customizations() const
184{
208{
185 QVariantMap m, h;
209 QVariantMap m, h;
@@ -196,7 +220,12 @@ QVariantMap Scope::customizations() const
196 return m;
220 return m;
197}
221}
198
222
223+void Scope::refresh()
224+{
225+ qDebug() << "Scope::refresh is currently not implmented in the fake scopes plugin";
226+}
227+
199−unity::shell::scopes::DepartmentInterface* Scope::getDepartment(const QString& id)
228+unity::shell::scopes::NavigationInterface* Scope::getNavigation(const QString& id)
200{
229{
201 if (id.isEmpty())
230 if (id.isEmpty())
202 return nullptr;
231 return nullptr;
@@ -210,11 +239,30 @@ unity::shell::scopes::DepartmentInterface* Scope::getDepartment(const QString& i
210 parentId = id.mid(5, 7);
239 parentId = id.mid(5, 7);
211 parentLabel = parentId;
240 parentLabel = parentId;
212 }
241 }
242+ return new Navigation(id, id, "all"+id, parentId, parentLabel, this);
243+}
244+
245+unity::shell::scopes::NavigationInterface* Scope::getAltNavigation(QString const& id)
246+{
247+ if (id.isEmpty())
248+ return nullptr;
249+
250+ QString parentId;
251+ QString parentLabel;
252+ if (id.startsWith("altmiddle")) {
253+ parentId = "altroot";
254+ parentLabel = "altroot";
255+ }
213− return new Department(id, id, "all"+id, parentId, parentLabel, this);
256+ return new Navigation(id, id, "all"+id, parentId, parentLabel, this);
214}
257}
215
258
216−void Scope::loadDepartment(const QString& id)
259+void Scope::setNavigationState(const QString &navigationId, bool isAltNavigation)
217{
260{
218− m_currentDeparment = id;
261+ if (isAltNavigation) {
219− Q_EMIT currentDepartmentIdChanged();
262+ m_currentAltNavigationId = navigationId;
263+ Q_EMIT currentAltNavigationIdChanged();
264+ } else {
265+ m_currentNavigationId = navigationId;
266+ Q_EMIT currentNavigationIdChanged();
267+ }
220}
268}
tests/mocks/Unity/fake_scope.h+16−8
@@ -30,7 +30,7 @@ class Scope : public unity::shell::scopes::ScopeInterface
30
30
31public:
31public:
32 Scope(QObject* parent = 0);
32 Scope(QObject* parent = 0);
33− Scope(QString const& id, QString const& name, bool visible, QObject* parent = 0, int categories = 20);
33+ Scope(QString const& id, QString const& name, bool favorite, QObject* parent = 0, int categories = 20);
34
34
35 /* getters */
35 /* getters */
36 QString id() const override;
36 QString id() const override;
@@ -38,9 +38,9 @@ public:
38 QString iconHint() const override;
38 QString iconHint() const override;
39 QString description() const override;
39 QString description() const override;
40 QString searchHint() const override;
40 QString searchHint() const override;
41− bool visible() const override;
42 QString shortcut() const override;
41 QString shortcut() const override;
43 bool searchInProgress() const override;
42 bool searchInProgress() const override;
43+ bool favorite() const override;
44 unity::shell::scopes::CategoriesInterface* categories() const override;
44 unity::shell::scopes::CategoriesInterface* categories() const override;
45 QString searchQuery() const override;
45 QString searchQuery() const override;
46 QString noResultsHint() const override;
46 QString noResultsHint() const override;
@@ -53,6 +53,7 @@ public:
53 void setNoResultsHint(const QString& hint) override;
53 void setNoResultsHint(const QString& hint) override;
54 void setFormFactor(const QString& form_factor) override;
54 void setFormFactor(const QString& form_factor) override;
55 void setActive(const bool) override;
55 void setActive(const bool) override;
56+ void setFavorite(const bool) override;
56 Q_INVOKABLE void setSearchInProgress(const bool inProg); // This is not invokable in the Interface, here for testing benefits
57 Q_INVOKABLE void setSearchInProgress(const bool inProg); // This is not invokable in the Interface, here for testing benefits
57
58
58 Q_INVOKABLE void activate(QVariant const& result) override;
59 Q_INVOKABLE void activate(QVariant const& result) override;
@@ -60,14 +61,20 @@ public:
60 Q_INVOKABLE void cancelActivation() override;
61 Q_INVOKABLE void cancelActivation() override;
61 Q_INVOKABLE void closeScope(unity::shell::scopes::ScopeInterface* scope) override;
62 Q_INVOKABLE void closeScope(unity::shell::scopes::ScopeInterface* scope) override;
62
63
63− QString currentDepartmentId() const override;
64+ QString currentNavigationId() const override;
64− bool hasDepartments() const override;
65+ bool hasNavigation() const override;
65− Q_INVOKABLE unity::shell::scopes::DepartmentInterface* getDepartment(const QString& id) override;
66+ QString currentAltNavigationId() const override;
67+ bool hasAltNavigation() const override;
68+ Q_INVOKABLE unity::shell::scopes::NavigationInterface* getNavigation(QString const& navigationId) override;
69+ Q_INVOKABLE unity::shell::scopes::NavigationInterface* getAltNavigation(QString const& altNavigationId) override;
66− Q_INVOKABLE void loadDepartment(const QString& id) override;
70+ Q_INVOKABLE void setNavigationState(const QString &navigationId, bool isAltNavigation) override;
67 Q_SIGNAL void performQuery(const QString& query) override;
71 Q_SIGNAL void performQuery(const QString& query) override;
68
72
73+ Status status() const override;
69 QVariantMap customizations() const override;
74 QVariantMap customizations() const override;
70
75
76+ Q_INVOKABLE void refresh() override;
77+
71protected:
78protected:
72
79
73 QString m_id;
80 QString m_id;
@@ -77,10 +84,11 @@ protected:
77 QString m_searchQuery;
84 QString m_searchQuery;
78 QString m_noResultsHint;
85 QString m_noResultsHint;
79 QString m_formFactor;
86 QString m_formFactor;
80− bool m_visible;
81 bool m_searching;
87 bool m_searching;
88+ bool m_favorite;
82 bool m_isActive;
89 bool m_isActive;
83− QString m_currentDeparment;
90+ QString m_currentNavigationId;
91+ QString m_currentAltNavigationId;
84
92
85 QString m_previewRendererName;
93 QString m_previewRendererName;
86
94
tests/mocks/Unity/fake_scopes.cpp+10−2
@@ -32,6 +32,11 @@ Scopes::Scopes(QObject *parent)
32 timer.setSingleShot(true);
32 timer.setSingleShot(true);
33 timer.setInterval(100);
33 timer.setInterval(100);
34 QObject::connect(&timer, SIGNAL(timeout()), this, SLOT(updateScopes()));
34 QObject::connect(&timer, SIGNAL(timeout()), this, SLOT(updateScopes()));
35+
36+ QObject::connect(this, SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SIGNAL(countChanged()));
37+ QObject::connect(this, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), this, SIGNAL(countChanged()));
38+ QObject::connect(this, SIGNAL(modelReset()), this, SIGNAL(countChanged()));
39+
35 load();
40 load();
36}
41}
37
42
@@ -92,8 +97,6 @@ QVariant Scopes::data(const QModelIndex& index, int role) const
92 return QVariant::fromValue(scope);
97 return QVariant::fromValue(scope);
93 } else if (role == Scopes::RoleId) {
98 } else if (role == Scopes::RoleId) {
94 return QVariant::fromValue(scope->id());
99 return QVariant::fromValue(scope->id());
95− } else if (role == Scopes::RoleVisible) {
96− return QVariant::fromValue(scope->visible());
97 } else if (role == Scopes::RoleTitle) {
100 } else if (role == Scopes::RoleTitle) {
98 return QVariant::fromValue(scope->name());
101 return QVariant::fromValue(scope->name());
99 } else {
102 } else {
@@ -125,6 +128,11 @@ bool Scopes::loaded() const
125 return m_loaded;
128 return m_loaded;
126}
129}
127
130
131+int Scopes::count() const
132+{
133+ return rowCount();
134+}
135+
128unity::shell::scopes::ScopeInterface* Scopes::overviewScope() const
136unity::shell::scopes::ScopeInterface* Scopes::overviewScope() const
129{
137{
130 return nullptr;
138 return nullptr;
tests/mocks/Unity/fake_scopes.h+1
@@ -50,6 +50,7 @@ public:
50 QModelIndex parent ( const QModelIndex & index ) const;
50 QModelIndex parent ( const QModelIndex & index ) const;
51
51
52 bool loaded() const override;
52 bool loaded() const override;
53+ int count() const override;
53 unity::shell::scopes::ScopeInterface* overviewScope() const override;
54 unity::shell::scopes::ScopeInterface* overviewScope() const override;
54
55
55private Q_SLOTS:
56private Q_SLOTS:
tests/mocks/Unity/fake_unity_plugin.cpp+2−2
@@ -22,7 +22,7 @@
22// local
22// local
23#include "fake_scopes.h"
23#include "fake_scopes.h"
24#include "fake_categories.h"
24#include "fake_categories.h"
25−#include "fake_department.h"
25+#include "fake_navigation.h"
26#include "fake_previewmodel.h"
26#include "fake_previewmodel.h"
27#include "fake_previewwidgetmodel.h"
27#include "fake_previewwidgetmodel.h"
28#include "fake_resultsmodel.h"
28#include "fake_resultsmodel.h"
@@ -43,7 +43,7 @@ void FakeUnityPlugin::registerTypes(const char *uri)
43 qmlRegisterType<Scopes>(uri, 0, 2, "Scopes");
43 qmlRegisterType<Scopes>(uri, 0, 2, "Scopes");
44 qmlRegisterType<Scope>(uri, 0, 2, "MockScope");
44 qmlRegisterType<Scope>(uri, 0, 2, "MockScope");
45 qmlRegisterUncreatableType<unity::shell::scopes::ScopeInterface>(uri, 0, 2, "Scope", "Can't create Scope object in QML.");
45 qmlRegisterUncreatableType<unity::shell::scopes::ScopeInterface>(uri, 0, 2, "Scope", "Can't create Scope object in QML.");
46− qmlRegisterUncreatableType<unity::shell::scopes::DepartmentInterface>(uri, 0, 2, "Department", "Can't create Department object in QML.");
46+ qmlRegisterUncreatableType<unity::shell::scopes::NavigationInterface>(uri, 0, 2, "Navigation", "Can't create Navigation object in QML.");
47 qmlRegisterUncreatableType<unity::shell::scopes::CategoriesInterface>(uri, 0, 2, "Categories", "Can't create Categories object in QML.");
47 qmlRegisterUncreatableType<unity::shell::scopes::CategoriesInterface>(uri, 0, 2, "Categories", "Can't create Categories object in QML.");
48 qmlRegisterUncreatableType<unity::shell::scopes::PreviewModelInterface>(uri, 0, 2, "PreviewModel", "Can't create new PreviewModel in QML. Get them from PreviewStack instance.");
48 qmlRegisterUncreatableType<unity::shell::scopes::PreviewModelInterface>(uri, 0, 2, "PreviewModel", "Can't create new PreviewModel in QML. Get them from PreviewStack instance.");
49 qmlRegisterUncreatableType<ResultsModel>(uri, 0, 2, "ResultsModel", "Can't create ResultsModel object in QML.");
49 qmlRegisterUncreatableType<ResultsModel>(uri, 0, 2, "ResultsModel", "Can't create ResultsModel object in QML.");
tests/plugins/Dash/cardcreator/1.res+12−10
@@ -33,20 +33,15 @@ Item {
33 visible: image.status == Image.Ready;
33 visible: image.status == Image.Ready;
34 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
34 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
35 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1;
35 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1;
36− readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect;
37− Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
36+ Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
38− onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings();
39 Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
37 Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
40 function updateWidthHeightBindings() {
38 function updateWidthHeightBindings() {
41 if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) {
39 if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) {
42 width = root.fixedArtShapeSize.width;
40 width = root.fixedArtShapeSize.width;
43 height = root.fixedArtShapeSize.height;
41 height = root.fixedArtShapeSize.height;
44− } else if (aspectSmallerThanImageAspect) {
45− width = Qt.binding(function() { return !visible ? 0 : image.width });
46− height = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.height : width / image.aspect });
47 } else {
42 } else {
48− width = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.width : height * image.aspect });
43+ width = Qt.binding(function() { return !visible ? 0 : image.width });
49− height = Qt.binding(function() { return !visible ? 0 : image.height });
44+ height = Qt.binding(function() { return !visible ? 0 : image.height });
50 }
45 }
51 }
46 }
52 image: Image {
47 image: Image {
@@ -54,8 +49,7 @@ Item {
54 source: cardData && cardData["art"] || "";
49 source: cardData && cardData["art"] || "";
55 cache: true;
50 cache: true;
56 asynchronous: root.asynchronous;
51 asynchronous: root.asynchronous;
57− fillMode: components && components["art"]["fill-mode"] === "fit" ? Image.PreserveAspectFit: Image.PreserveAspectCrop;
52+ fillMode: Image.PreserveAspectCrop;
58− readonly property real aspect: implicitWidth / implicitHeight;
59 width: root.width;
53 width: root.width;
60 height: width / artShape.aspect;
54 height: width / artShape.aspect;
61 }
55 }
@@ -84,5 +78,13 @@ leftMargin: units.gu(1);
84 font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
78 font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
85 horizontalAlignment: root.headerAlignment;
79 horizontalAlignment: root.headerAlignment;
86 }
80 }
81+UbuntuShape {
82+ id: touchdown;
83+ objectName: "touchdown";
84+ anchors { fill: artShapeHolder }
85+ visible: root.pressed;
86+ radius: "medium";
87+ borderSource: "radius_pressed.sci"
88+}
87implicitHeight: titleLabel.y + titleLabel.height + units.gu(1);
89implicitHeight: titleLabel.y + titleLabel.height + units.gu(1);
88}
90}
tests/plugins/Dash/cardcreator/1.tst+1−1
@@ -1,3 +1,3 @@
1template: {"card-layout":"vertical","card-size":"small","category-layout":"grid","collapsed-rows":2}
1template: {"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"}}
2+components: {"art":{"aspect-ratio":1.6,"field":"art"},"title":{"field":"title"}}
3result: 1.res
3result: 1.res
tests/plugins/Dash/cardcreator/2.res+8
@@ -116,5 +116,13 @@ left: parent.left;
116
116
117 ]
117 ]
118 }
118 }
119+UbuntuShape {
120+ id: touchdown;
121+ objectName: "touchdown";
122+ anchors { fill: backgroundLoader }
123+ visible: root.pressed;
124+ radius: "medium";
125+ borderSource: "radius_pressed.sci"
126+}
119implicitHeight: row.y + row.height + units.gu(1);
127implicitHeight: row.y + row.height + units.gu(1);
120}
128}
tests/plugins/Dash/cardcreator/2.tst+1−1
@@ -1,3 +1,3 @@
1template: {"card-background":{"elements":["#E9E9E9"],"type":"color"},"card-layout":"vertical","card-size":"medium","category-layout":"grid","collapsed-rows":2}
1template: {"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"}}
2+components: {"art":{"aspect-ratio":1},"background":{"field":"background"},"mascot":{"field":"icon"},"subtitle":{"field":"author"},"title":{"field":"title"}}
3result: 2.res
3result: 2.res
tests/plugins/Dash/cardcreator/3.res+12−10
@@ -25,7 +25,7 @@ Item {
25 objectName: "artShapeLoader";
25 objectName: "artShapeLoader";
26 active: cardData && cardData["art"] || false;
26 active: cardData && cardData["art"] || false;
27 asynchronous: root.asynchronous;
27 asynchronous: root.asynchronous;
28− visible: status == Loader.Ready;
28+ visible: status == Loader.Ready;
29 sourceComponent: UbuntuShape {
29 sourceComponent: UbuntuShape {
30 id: artShape;
30 id: artShape;
31 objectName: "artShape";
31 objectName: "artShape";
@@ -33,20 +33,15 @@ Item {
33 visible: image.status == Image.Ready;
33 visible: image.status == Image.Ready;
34 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
34 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
35 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1;
35 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1;
36− readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect;
37 Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
36 Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
38− onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings();
39 Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
37 Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
40 function updateWidthHeightBindings() {
38 function updateWidthHeightBindings() {
41 if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) {
39 if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) {
42 width = root.fixedArtShapeSize.width;
40 width = root.fixedArtShapeSize.width;
43 height = root.fixedArtShapeSize.height;
41 height = root.fixedArtShapeSize.height;
44− } else if (aspectSmallerThanImageAspect) {
45− width = Qt.binding(function() { return !visible ? 0 : image.width });
46− height = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.height : width / image.aspect });
47 } else {
42 } else {
48− width = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.width : height * image.aspect });
43+ width = Qt.binding(function() { return !visible ? 0 : image.width });
49− height = Qt.binding(function() { return !visible ? 0 : image.height });
44+ height = Qt.binding(function() { return !visible ? 0 : image.height });
50 }
45 }
51 }
46 }
52 image: Image {
47 image: Image {
@@ -54,8 +49,7 @@ Item {
54 source: cardData && cardData["art"] || "";
49 source: cardData && cardData["art"] || "";
55 cache: true;
50 cache: true;
56 asynchronous: root.asynchronous;
51 asynchronous: root.asynchronous;
57− fillMode: components && components["art"]["fill-mode"] === "fit" ? Image.PreserveAspectFit: Image.PreserveAspectCrop;
52+ fillMode: Image.PreserveAspectCrop;
58− readonly property real aspect: implicitWidth / implicitHeight;
59 width: root.width;
53 width: root.width;
60 height: width / artShape.aspect;
54 height: width / artShape.aspect;
61 }
55 }
@@ -103,5 +97,13 @@ Label {
103 font.weight: Font.Light;
97 font.weight: Font.Light;
104 horizontalAlignment: root.headerAlignment;
98 horizontalAlignment: root.headerAlignment;
105 }
99 }
100+UbuntuShape {
101+ id: touchdown;
102+ objectName: "touchdown";
103+ anchors { fill: artShapeHolder }
104+ visible: root.pressed;
105+ radius: "medium";
106+ borderSource: "radius_pressed.sci"
107+}
106implicitHeight: subtitleLabel.y + subtitleLabel.height + units.gu(1);
108implicitHeight: subtitleLabel.y + subtitleLabel.height + units.gu(1);
107}
109}
tests/plugins/Dash/cardcreator/3.tst+1−1
@@ -1,3 +1,3 @@
1template: {"card-layout":"vertical","card-size":"small","category-layout":"grid","collapsed-rows":2}
1template: {"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"}}
2+components: {"art":{"aspect-ratio":0.75,"field":"art"},"subtitle":{"field":"price"},"title":{"field":"title"}}
3result: 3.res
3result: 3.res
tests/plugins/Dash/cardcreator/4.res+8
@@ -94,5 +94,13 @@ Label {
94}
94}
95]
95]
96}
96}
97+UbuntuShape {
98+ id: touchdown;
99+ objectName: "touchdown";
100+ anchors { fill: root }
101+ visible: root.pressed;
102+ radius: "medium";
103+ borderSource: "radius_pressed.sci"
104+}
97implicitHeight: row.y + row.height + units.gu(1);
105implicitHeight: row.y + row.height + units.gu(1);
98}
106}
tests/plugins/Dash/cardcreator/4.tst+1−1
@@ -1,3 +1,3 @@
1template: {"card-layout":"horizontal","card-size":"large","category-layout":"grid","collapsed-rows":2}
1template: {"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"}}
2+components: {"art":{"aspect-ratio":1},"mascot":{"field":"mascot"},"subtitle":{"field":"domain"},"title":{"field":"title"}}
3result: 4.res
3result: 4.res
tests/plugins/Dash/cardcreator/5.res+14−12
@@ -25,7 +25,7 @@ Item {
25 objectName: "artShapeLoader";
25 objectName: "artShapeLoader";
26 active: cardData && cardData["art"] || false;
26 active: cardData && cardData["art"] || false;
27 asynchronous: root.asynchronous;
27 asynchronous: root.asynchronous;
28− visible: status == Loader.Ready;
28+ visible: status == Loader.Ready;
29 sourceComponent: UbuntuShape {
29 sourceComponent: UbuntuShape {
30 id: artShape;
30 id: artShape;
31 objectName: "artShape";
31 objectName: "artShape";
@@ -33,20 +33,15 @@ Item {
33 visible: image.status == Image.Ready;
33 visible: image.status == Image.Ready;
34 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
34 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
35 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1;
35 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1;
36− readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect;
37 Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
36 Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
38− onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings();
39 Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
37 Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
40 function updateWidthHeightBindings() {
38 function updateWidthHeightBindings() {
41 if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) {
39 if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) {
42 width = root.fixedArtShapeSize.width;
40 width = root.fixedArtShapeSize.width;
43 height = root.fixedArtShapeSize.height;
41 height = root.fixedArtShapeSize.height;
44− } else if (aspectSmallerThanImageAspect) {
45− width = Qt.binding(function() { return !visible ? 0 : image.width });
46− height = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.height : width / image.aspect });
47 } else {
42 } else {
48− width = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.width : height * image.aspect });
43+ width = Qt.binding(function() { return !visible ? 0 : image.width });
49− height = Qt.binding(function() { return !visible ? 0 : image.height });
44+ height = Qt.binding(function() { return !visible ? 0 : image.height });
50 }
45 }
51 }
46 }
52 image: Image {
47 image: Image {
@@ -54,13 +49,12 @@ Item {
54 source: cardData && cardData["art"] || "";
49 source: cardData && cardData["art"] || "";
55 cache: true;
50 cache: true;
56 asynchronous: root.asynchronous;
51 asynchronous: root.asynchronous;
57− fillMode: components && components["art"]["fill-mode"] === "fit" ? Image.PreserveAspectFit: Image.PreserveAspectCrop;
52+ fillMode: Image.PreserveAspectCrop;
58− readonly property real aspect: implicitWidth / implicitHeight;
59 width: root.width;
53 width: root.width;
60 height: width / artShape.aspect;
54 height: width / artShape.aspect;
61 }
55 }
62 }
56 }
63− }
57+ }
64 }
58 }
65Loader {
59Loader {
66 id: overlayLoader;
60 id: overlayLoader;
@@ -69,7 +63,7 @@ Loader {
69 right: artShapeHolder.right;
63 right: artShapeHolder.right;
70 bottom: artShapeHolder.bottom;
64 bottom: artShapeHolder.bottom;
71 }
65 }
72− active: artShapeLoader.active && artShapeLoader.item && artShapeLoader.item.image.status === Image.Ready || false;
66+ active: artShapeLoader.active && artShapeLoader.item && artShapeLoader.item.image.status === Image.Ready || false;
73 asynchronous: root.asynchronous;
67 asynchronous: root.asynchronous;
74 visible: showHeader && status == Loader.Ready;
68 visible: showHeader && status == Loader.Ready;
75 sourceComponent: ShaderEffect {
69 sourceComponent: ShaderEffect {
@@ -143,5 +137,13 @@ Label {
143 font.weight: Font.Light;
137 font.weight: Font.Light;
144 horizontalAlignment: root.headerAlignment;
138 horizontalAlignment: root.headerAlignment;
145 }
139 }
140+UbuntuShape {
141+ id: touchdown;
142+ objectName: "touchdown";
143+ anchors { fill: artShapeHolder }
144+ visible: root.pressed;
145+ radius: "medium";
146+ borderSource: "radius_pressed.sci"
147+}
146implicitHeight: subtitleLabel.y + subtitleLabel.height + units.gu(1);
148implicitHeight: subtitleLabel.y + subtitleLabel.height + units.gu(1);
147}
149}
tests/plugins/Dash/cardcreator/5.tst+1−1
@@ -1,3 +1,3 @@
1template: {"card-layout":"vertical","card-size":"medium","category-layout":"carousel","collapsed-rows":2,"overlay":true}
1template: {"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"}}
2+components: {"art":{"aspect-ratio":1,"field":"art"},"subtitle":{"field":"artist"},"title":{"field":"title"}}
3result: 5.res
3result: 5.res
tests/plugins/Dash/cardcreator/6.res+10−8
@@ -33,19 +33,14 @@ Item {
33 visible: image.status == Image.Ready;
33 visible: image.status == Image.Ready;
34 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
34 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
35 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1;
35 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1;
36− readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect;
37 Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
36 Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
38− onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings();
39 Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
37 Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
40 function updateWidthHeightBindings() {
38 function updateWidthHeightBindings() {
41 if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) {
39 if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) {
42 width = root.fixedArtShapeSize.width;
40 width = root.fixedArtShapeSize.width;
43 height = root.fixedArtShapeSize.height;
41 height = root.fixedArtShapeSize.height;
44− } else if (aspectSmallerThanImageAspect) {
45− width = Qt.binding(function() { return !visible ? 0 : image.width });
46− height = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.height : width / image.aspect });
47 } else {
42 } else {
48− width = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.width : height * image.aspect });
43+ width = Qt.binding(function() { return !visible ? 0 : image.width });
49 height = Qt.binding(function() { return !visible ? 0 : image.height });
44 height = Qt.binding(function() { return !visible ? 0 : image.height });
50 }
45 }
51 }
46 }
@@ -54,8 +49,7 @@ Item {
54 source: cardData && cardData["art"] || "";
49 source: cardData && cardData["art"] || "";
55 cache: true;
50 cache: true;
56 asynchronous: root.asynchronous;
51 asynchronous: root.asynchronous;
57− fillMode: components && components["art"]["fill-mode"] === "fit" ? Image.PreserveAspectFit: Image.PreserveAspectCrop;
52+ fillMode: Image.PreserveAspectCrop;
58− readonly property real aspect: implicitWidth / implicitHeight;
59 width: root.width;
53 width: root.width;
60 height: width / artShape.aspect;
54 height: width / artShape.aspect;
61 }
55 }
@@ -63,5 +57,13 @@ Item {
63 }
57 }
64 }
58 }
65readonly property int headerHeight: 0;
59readonly property int headerHeight: 0;
60+UbuntuShape {
61+ id: touchdown;
62+ objectName: "touchdown";
63+ anchors { fill: artShapeHolder }
64+ visible: root.pressed;
65+ radius: "medium";
66+ borderSource: "radius_pressed.sci"
67+}
66implicitHeight: artShapeHolder.height;
68implicitHeight: artShapeHolder.height;
67}
69}
tests/plugins/Dash/cardcreator/6.tst+1−1
@@ -1,3 +1,3 @@
1template: {"card-layout":"vertical","card-size":"small","category-layout":"grid","collapsed-rows":2}
1template: {"card-layout":"vertical","card-size":"small","category-layout":"grid","collapsed-rows":2}
2−components: {"art":{"aspect-ratio":1.6,"field":"art","fill-mode":"fit"}}
2+components: {"art":{"aspect-ratio":1.6,"field":"art"}}
3result: 6.res
3result: 6.res
tests/plugins/Dash/cardcreator/7.res+9−1
@@ -116,7 +116,7 @@ CardAttributes {
116 objectName: "attributesRow";
116 objectName: "attributesRow";
117 anchors { left: parent.left; right: parent.right }
117 anchors { left: parent.left; right: parent.right }
118 color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < 0.7 ? "white" : (root.scopeStyle ? root.scopeStyle.foreground : "grey");
118 color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < 0.7 ? "white" : (root.scopeStyle ? root.scopeStyle.foreground : "grey");
119− model: cardData["attributes"]
119+ model: cardData["attributes"];
120 }
120 }
121
121
122 ]
122 ]
@@ -124,5 +124,13 @@ CardAttributes {
124
124
125 ]
125 ]
126 }
126 }
127+UbuntuShape {
128+ id: touchdown;
129+ objectName: "touchdown";
130+ anchors { fill: backgroundLoader }
131+ visible: root.pressed;
132+ radius: "medium";
133+ borderSource: "radius_pressed.sci"
134+}
127implicitHeight: row.y + row.height + units.gu(1);
135implicitHeight: row.y + row.height + units.gu(1);
128}
136}
tests/plugins/Dash/cardcreator/7.tst+1−1
@@ -1,3 +1,3 @@
1template: {"card-background":{"elements":["#E9E9E9"],"type":"color"},"card-layout":"vertical","card-size":"medium","category-layout":"grid","collapsed-rows":2}
1template: {"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"},"attributes":{"field":"attributes","max-count":2}}
2+components: {"art":{"aspect-ratio":1},"background":{"field":"background"},"mascot":{"field":"icon"},"subtitle":{"field":"author"},"title":{"field":"title"},"attributes":{"field":"attributes","max-count":2}}
3result: 7.res
3result: 7.res
tests/plugins/Dash/cardcreatortest.cpp+13−4
@@ -19,6 +19,7 @@
19#include <QQuickItem>
19#include <QQuickItem>
20#include <QQuickView>
20#include <QQuickView>
21#include <QtTestGui>
21#include <QtTestGui>
22+#include <QDebug>
22#include <QTemporaryFile>
23#include <QTemporaryFile>
23
24
24class CardCreatorTest : public QObject
25class CardCreatorTest : public QObject
@@ -74,15 +75,23 @@ private Q_SLOTS:
74 QFile testResultFile(testDirPath + resultFileName);
75 QFile testResultFile(testDirPath + resultFileName);
75 QVERIFY(testResultFile.open(QIODevice::ReadOnly));
76 QVERIFY(testResultFile.open(QIODevice::ReadOnly));
76 QTextStream ts2(&testResultFile);
77 QTextStream ts2(&testResultFile);
77− const QString expectedResult = ts2.readAll();
78+
78− const QString executedResult = cardStringResult.toString();
79 // Record failed results to /tmp
79 // Record failed results to /tmp
80+ const QString executedResult = cardStringResult.toString();
80 QTemporaryFile tmpFile(QDir::tempPath() + QDir::separator() + "testCardCreatorFailedResultXXXXXX");
81 QTemporaryFile tmpFile(QDir::tempPath() + QDir::separator() + "testCardCreatorFailedResultXXXXXX");
81 tmpFile.open();
82 tmpFile.open();
82 tmpFile.setAutoRemove(false);
83 tmpFile.setAutoRemove(false);
83 tmpFile.write(executedResult.toUtf8().constData());
84 tmpFile.write(executedResult.toUtf8().constData());
85+
86+ // Line by line comparison
87+ const QStringList expectedLines = ts2.readAll().trimmed().replace(QRegExp("\n\\s*\n"),"\n").split("\n");
88+ const QStringList cardStringResultLines = cardStringResult.toString().trimmed().replace(QRegExp("\n\\s*\n"),"\n").split("\n");
89+ for (int i = 0; i < expectedLines.size(); ++i) {
84− QCOMPARE(executedResult.simplified(), expectedResult.simplified());
90+ QCOMPARE(cardStringResultLines[i].simplified(), expectedLines[i].simplified());
91+ }
92+
85− tmpFile.setAutoRemove(true); // Remove the result if it passed
93+ // Remove the result if it passed
94+ tmpFile.setAutoRemove(true);
86
95
87 QVariant createCardComponentResult;
96 QVariant createCardComponentResult;
88 QMetaObject::invokeMethod(view->rootObject(), "createCardComponent", Q_RETURN_ARG(QVariant, createCardComponentResult), Q_ARG(QVariant, templateJSON), Q_ARG(QVariant, componentsJSON));
97 QMetaObject::invokeMethod(view->rootObject(), "createCardComponent", Q_RETURN_ARG(QVariant, createCardComponentResult), Q_ARG(QVariant, templateJSON), Q_ARG(QVariant, componentsJSON));
tests/plugins/Dash/tst_ScopeStyle.qml+14−7
@@ -54,6 +54,9 @@ Rectangle {
54 { tag: "lightgrey", luminance: 0.8275 },
54 { tag: "lightgrey", luminance: 0.8275 },
55 { tag: "grey", luminance: 0.5020 },
55 { tag: "grey", luminance: 0.5020 },
56 { tag: "darkgrey", luminance: 0.6627 },
56 { tag: "darkgrey", luminance: 0.6627 },
57+ { tag: "red", luminance: 0.2126 },
58+ { tag: "green", luminance: 0.3590 },
59+ { tag: "blue", luminance: 0.0722 },
57 ];
60 ];
58 }
61 }
59
62
@@ -64,10 +67,10 @@ Rectangle {
64
67
65 function test_foreground_data() {
68 function test_foreground_data() {
66 return [
69 return [
67− { tag: "default", index: 0, foreground: "grey" },
70+ { tag: "default", index: 0, foreground: "grey", luminance: 0.5020 },
68− { tag: "red on black", index: 1, foreground: "red" },
71+ { tag: "red on black", index: 1, foreground: "red", luminance: 0.2126 },
69− { tag: "green on white", index: 2, foreground: "green" },
72+ { tag: "green on white", index: 2, foreground: "green", luminance: 0.3590 },
70− { tag: "blue on darkgrey", index: 3, foreground: "blue" },
73+ { tag: "blue on darkgrey", index: 3, foreground: "blue", luminance: 0.0722 },
71 ];
74 ];
72 }
75 }
73
76
@@ -75,14 +78,15 @@ Rectangle {
75 tool.style = testCase.styles[data.index];
78 tool.style = testCase.styles[data.index];
76 verify(Qt.colorEqual(tool.foreground, data.foreground),
79 verify(Qt.colorEqual(tool.foreground, data.foreground),
77 "Foreground color not equal: %1 != %2".arg(tool.foreground).arg(data.foreground));
80 "Foreground color not equal: %1 != %2".arg(tool.foreground).arg(data.foreground));
81+ compare(tool.foregroundLuminance.toFixed(4), data.luminance.toFixed(4));
78 }
82 }
79
83
80 function test_background_data() {
84 function test_background_data() {
81 return [
85 return [
82 { tag: "default", index: 0, background: "transparent" },
86 { tag: "default", index: 0, background: "transparent" },
83− { tag: "red on black", index: 1, background: "black" },
87+ { tag: "red on black", index: 1, background: "black", luminance: 0 },
84− { tag: "green on white", index: 2, background: "white" },
88+ { tag: "green on white", index: 2, background: "white", luminance: 1 },
85− { tag: "blue on darkgrey", index: 3, background: "darkgrey" },
89+ { tag: "blue on darkgrey", index: 3, background: "darkgrey", luminance: 0.6627 },
86 ];
90 ];
87 }
91 }
88
92
@@ -90,6 +94,9 @@ Rectangle {
90 tool.style = testCase.styles[data.index];
94 tool.style = testCase.styles[data.index];
91 verify(Qt.colorEqual(tool.background, data.background),
95 verify(Qt.colorEqual(tool.background, data.background),
92 "Background color not equal: %1 != %2".arg(tool.background).arg(data.background));
96 "Background color not equal: %1 != %2".arg(tool.background).arg(data.background));
97+ if (data.hasOwnProperty("luminance")) {
98+ compare(tool.backgroundLuminance.toFixed(4), data.luminance.toFixed(4));
99+ }
93 }
100 }
94
101
95 function test_threshold_data() {
102 function test_threshold_data() {
tests/qmltests/CMakeLists.txt+1−1
@@ -30,7 +30,6 @@ add_qml_test(Components Rating)
30add_qml_test(Components ResponsiveFlowView)
30add_qml_test(Components ResponsiveFlowView)
31add_qml_test(Components ResponsiveGridView)
31add_qml_test(Components ResponsiveGridView)
32add_qml_test(Components ResponsiveVerticalJournal IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins)
32add_qml_test(Components ResponsiveVerticalJournal IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins)
33−add_qml_test(Components SeeMore)
34add_qml_test(Components Showable)
33add_qml_test(Components Showable)
35add_qml_test(Components PageHeader)
34add_qml_test(Components PageHeader)
36add_qml_test(Components ZoomableImage)
35add_qml_test(Components ZoomableImage)
@@ -43,6 +42,7 @@ add_qml_test(Dash GenericScopeView)
43add_qml_test(Dash/Previews Preview)
42add_qml_test(Dash/Previews Preview)
44add_qml_test(Dash/Previews PreviewActions)
43add_qml_test(Dash/Previews PreviewActions)
45add_qml_test(Dash/Previews PreviewAudioPlayback)
44add_qml_test(Dash/Previews PreviewAudioPlayback)
45+add_qml_test(Dash/Previews PreviewExpandable)
46add_qml_test(Dash/Previews PreviewHeader)
46add_qml_test(Dash/Previews PreviewHeader)
47add_qml_test(Dash/Previews PreviewImageGallery)
47add_qml_test(Dash/Previews PreviewImageGallery)
48add_qml_test(Dash/Previews PreviewPayments)
48add_qml_test(Dash/Previews PreviewPayments)
tests/qmltests/Components/tst_PageHeader.qml+21−23
@@ -119,29 +119,6 @@ Item {
119 compare(pageHeader.searchHistory.get(0).query, "humppa4")
119 compare(pageHeader.searchHistory.get(0).query, "humppa4")
120 }
120 }
121
121
122− function test_search_indicator() {
123− var searchIndicator = findChild(pageHeader, "searchIndicator")
124− var clearIcon = findChild(pageHeader, "clearIcon")
125−
126− pageHeader.triggerSearch()
127−
128− tryCompare(clearIcon, "visible", false)
129− pageHeader.searchQuery = "ubuntu"
130− tryCompare(clearIcon, "visible", true)
131−
132− pageHeader.searchInProgress = false
133− compare(searchIndicator.running, false, "Search indicator is running.")
134− tryCompare(clearIcon, "visible", true)
135−
136− pageHeader.searchInProgress = true
137− compare(searchIndicator.running, true, "Search indicator isn't running.")
138− tryCompare(clearIcon, "visible", false)
139−
140− pageHeader.searchInProgress = false;
141− compare(searchIndicator.running, false, "Search indicator is running.")
142− tryCompare(clearIcon, "visible", true)
143− }
144−
145 function test_titleImage() {
122 function test_titleImage() {
146
123
147 var titleImage = findChild(pageHeader, "titleImage");
124 var titleImage = findChild(pageHeader, "titleImage");
@@ -192,6 +169,27 @@ Item {
192 ];
169 ];
193 }
170 }
194
171
172+ function test_pagination() {
173+ var paginationRepeater = findChild(pageHeader, "paginationRepeater");
174+ tryCompare(paginationRepeater, "count", 0);
175+ pageHeader.paginationCount = 5;
176+ tryCompare(paginationRepeater, "count", 5);
177+ for (var i=0; i<pageHeader.paginationCount; i++) {
178+ pageHeader.paginationIndex = i;
179+ for (var j=0; j<paginationRepeater.count; j++) {
180+ var paginationDot = findChild(pageHeader, "paginationDots_"+j);
181+ if (i==j) {
182+ compare(paginationDot.source.toString().indexOf("pagination_dot_on") > -1, true);
183+ } else {
184+ compare(paginationDot.source.toString().indexOf("pagination_dot_off") > -1, true);
185+ }
186+ }
187+ }
188+ pageHeader.paginationIndex = -1;
189+ pageHeader.paginationCount = 0;
190+ tryCompare(paginationRepeater, "count", 0);
191+ }
192+
195 function test_popup_closing(data) {
193 function test_popup_closing(data) {
196 searchEnabled = true;
194 searchEnabled = true;
197 pageHeader.searchHistory.clear();
195 pageHeader.searchHistory.clear();
tests/qmltests/Components/tst_SeeMore.qmldeleted−52
@@ -1,52 +0,0 @@
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 Ubuntu.Components 0.1
20−import "../../../qml/Components"
21−import Unity.Test 0.1 as UT
22−
23−Rectangle {
24− id: root
25− width: units.gu(40)
26− height: units.gu(10)
27− color: Theme.palette.selected.background
28−
29− SeeMore {
30− id: seeMore
31− anchors.fill: parent
32− more: false
33− }
34−
35− UT.UnityTestCase {
36− name: "SeeMoreTest"
37− when: windowShown
38−
39− function test_interaction() {
40− var seeMoreLabel = findChild(seeMore, "seeMoreLabel")
41− var seeLessLabel = findChild(seeMore, "seeLessLabel")
42−
43− compare(seeMore.more, false)
44−
45− mouseClick(seeMoreLabel, seeMoreLabel.width / 2, seeMoreLabel.height / 2)
46− compare(seeMore.more, true)
47−
48− mouseClick(seeLessLabel, seeLessLabel.width / 2, seeLessLabel.height / 2)
49− compare(seeMore.more, false)
50− }
51− }
52−}
tests/qmltests/Dash/CardHelpers.js+4−3
@@ -16,7 +16,7 @@
16
16
17.pragma library
17.pragma library
18
18
19−var components = ["title", "art", "subtitle", "mascot", "emblem", "old-price", "price", "alt-price", "rating", "alt-rating", "summary", "attributes"]
19+var components = ["title", "art", "subtitle", "mascot", "emblem", "old-price", "price", "alt-price", "rating", "alt-rating", "summary", "attributes", "overlayColor"]
20
20
21var defaultLayout = ' \
21var defaultLayout = ' \
22{ \
22{ \
@@ -31,10 +31,10 @@ var defaultLayout = ' \
31 "components": { \
31 "components": { \
32 "title": null, \
32 "title": null, \
33 "art": { \
33 "art": { \
34− "aspect-ratio": 1.0, \
34+ "aspect-ratio": 1.0 \
35− "fill-mode": "crop" \
36 }, \
35 }, \
37 "subtitle": null, \
36 "subtitle": null, \
37+ "overlayColor": null, \
38 "mascot": null, \
38 "mascot": null, \
39 "emblem": null, \
39 "emblem": null, \
40 "old-price": null, \
40 "old-price": null, \
@@ -60,6 +60,7 @@ var fullMapping = ' \
60 "art": "art", \
60 "art": "art", \
61 "subtitle": "subtitle", \
61 "subtitle": "subtitle", \
62 "mascot": "mascot", \
62 "mascot": "mascot", \
63+ "overlayColor": "overlayColor", \
63 "summary": "summary", \
64 "summary": "summary", \
64 "attributes": "attributes" \
65 "attributes": "attributes" \
65}'
66}'
tests/qmltests/Dash/Previews/tst_PreviewExpandable.qmlnew file+97
@@ -0,0 +1,97 @@
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 Ubuntu.Components 0.1
20+import "../../../../qml/Dash/Previews"
21+import Unity.Test 0.1 as UT
22+
23+Rectangle {
24+ id: root
25+ width: units.gu(40)
26+ height: units.gu(80)
27+ color: Theme.palette.selected.background
28+
29+ property string longText: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.\nPhasellus a mi vitae augue rhoncus lobortis ut rutrum metus.\nCurabitur tortor leo, tristique sed mollis quis, condimentum venenatis nibh.\nLorem ipsum dolor sit amet, consectetur adipiscing elit.\nPhasellus a mi vitae augue rhoncus lobortis ut rutrum metus.\nCurabitur tortor leo, tristique sed mollis quis, condimentum venenatis nibh."
30+ property string longText2: "This is a very very very long text. 1 This is a very very very long text. 2 This is a very very very long text. 3 This is a very very very long text. 4 This is a very very very long text. 5 This is a very very very long text. 6 This is a very very very long text. 7 This is a very very very long text. 8 This is a very very very long text. 9 This is a very very very long text. 10 This is a very very very long text. 11 This is a very very very long text."
31+ property string shortText: "This is a short text :)"
32+
33+ property var widgetData: {
34+ "title": "Title here",
35+ "collapsed-widgets": 2,
36+ "widgets": [
37+ { "type": "text", "widgetId" : "text1", "properties" : { "text": longText } },
38+ { "type": "text", "widgetId" : "text2", "properties" : { "text": longText2 } },
39+ { "type": "text", "widgetId" : "text3", "properties" : { "text": shortText } },
40+ { "type": "text", "widgetId" : "text4", "properties" : { "text": longText } }
41+ ]
42+ }
43+
44+ PreviewExpandable {
45+ id: previewExpandable
46+ anchors { left: parent.left; right: parent.right }
47+ widgetData: root.widgetData
48+ }
49+
50+ UT.UnityTestCase {
51+ name: "PreviewExpandableTest"
52+ when: windowShown
53+
54+ function checkInitialState()
55+ {
56+ compare(previewExpandable.expanded, false);
57+
58+ var repeater = findChild(previewExpandable, "repeater")
59+ compare(repeater.count, 4)
60+
61+ compare (repeater.itemAt(0).visible, true);
62+ compare (repeater.itemAt(1).visible, true);
63+ compare (repeater.itemAt(2).visible, false);
64+ compare (repeater.itemAt(3).visible, false);
65+ compare (repeater.itemAt(0).expanded, false);
66+ compare (repeater.itemAt(1).expanded, false);
67+ }
68+
69+ function init() {
70+ }
71+
72+ function test_collapsed_by_default() {
73+ // Nothing init does this already
74+ }
75+
76+ function test_expand_collapse() {
77+ var expandButton = findChild(previewExpandable, "expandButton")
78+ mouseClick(expandButton, expandButton.width / 2, expandButton.height / 2);
79+
80+ var repeater = findChild(previewExpandable, "repeater")
81+ compare(repeater.count, 4)
82+
83+ compare (repeater.itemAt(0).visible, true);
84+ compare (repeater.itemAt(1).visible, true);
85+ compare (repeater.itemAt(2).visible, true);
86+ compare (repeater.itemAt(3).visible, true);
87+ compare (repeater.itemAt(0).expanded, true);
88+ compare (repeater.itemAt(1).expanded, true);
89+ compare (repeater.itemAt(2).expanded, true);
90+ compare (repeater.itemAt(3).expanded, true);
91+
92+ mouseClick(expandButton, expandButton.width / 2, expandButton.height / 2);
93+
94+ checkInitialState();
95+ }
96+ }
97+}
tests/qmltests/Dash/Previews/tst_PreviewTextSummary.qml+4−18
@@ -37,7 +37,7 @@ Rectangle {
37
37
38 property var widgetDataShortText: {
38 property var widgetDataShortText: {
39 "title": "Title here",
39 "title": "Title here",
40− "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.\nPhasellus a mi vitae augue rhoncus lobortis ut rutrum metus.\nCurabitur tortor leo, tristique sed mollis quis, condimentum venenatis nibh."
40+ "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus a mi vitae augue rhoncus lobortis ut rutrum metus."
41 }
41 }
42
42
43 PreviewTextSummary {
43 PreviewTextSummary {
@@ -72,28 +72,14 @@ Rectangle {
72 tryCompare(textLabel, "y", 0)
72 tryCompare(textLabel, "y", 0)
73 }
73 }
74
74
75− function test_see_more() {
75+ function test_show_collapsed() {
76− var seeMore = findChild(previewTextSummary, "seeMore")
77−
78− // when it's more than textLabel.maximumCollapsedLineCount lines of text, show SeeMore component
79 verify(textLabel.lineCount > textLabel.maximumCollapsedLineCount)
76 verify(textLabel.lineCount > textLabel.maximumCollapsedLineCount)
80− compare(seeMore.visible, true)
81− verify(seeMore.more === false)
82− verify(textLabel.height < textLabel.contentHeight)
83
77
84− // test interactions with SeeMore
78+ previewTextSummary.expanded = false;
85− var seeMoreLabel = findChild(seeMore, "seeMoreLabel")
79+ tryCompareFunction(function() { return textLabel.height < textLabel.contentHeight; }, true)
86− var seeLessLabel = findChild(seeMore, "seeLessLabel")
87− var initialTextLabelHeight = textLabel.height
88− mouseClick(seeMoreLabel, seeMoreLabel.width / 2, seeMoreLabel.height / 2)
89− tryCompare(textLabel, "height", textLabel.contentHeight)
90− mouseClick(seeLessLabel, seeLessLabel.width / 2, seeLessLabel.height / 2)
91− tryCompare(textLabel, "height", initialTextLabelHeight)
92
80
93− // text SeeMore automatic hiding
94 previewTextSummary.widgetData = widgetDataShortText
81 previewTextSummary.widgetData = widgetDataShortText
95 verify(textLabel.lineCount <= textLabel.maximumCollapsedLineCount)
82 verify(textLabel.lineCount <= textLabel.maximumCollapsedLineCount)
96− compare(seeMore.visible, false)
97 tryCompare(textLabel, "height", textLabel.contentHeight)
83 tryCompare(textLabel, "height", textLabel.contentHeight)
98 tryCompare(previewTextSummary, "height", titleLabel.height + textLabel.height)
84 tryCompare(previewTextSummary, "height", titleLabel.height + textLabel.height)
99 }
85 }
tests/qmltests/Dash/Previews/tst_PreviewWidgetFactory.qml+1
@@ -77,6 +77,7 @@ Rectangle {
77 return [
77 return [
78 { tag: "Actions", type: "actions", source: "PreviewActions.qml" },
78 { tag: "Actions", type: "actions", source: "PreviewActions.qml" },
79 { tag: "Audio", type: "audio", source: "PreviewAudioPlayback.qml" },
79 { tag: "Audio", type: "audio", source: "PreviewAudioPlayback.qml" },
80+ { tag: "Expandable", type: "expandable", source: "PreviewExpandable.qml" },
80 { tag: "Gallery", type: "gallery", source: "PreviewImageGallery.qml" },
81 { tag: "Gallery", type: "gallery", source: "PreviewImageGallery.qml" },
81 { tag: "Header", type: "header", source: "PreviewHeader.qml" },
82 { tag: "Header", type: "header", source: "PreviewHeader.qml" },
82 { tag: "Image", type: "image", source: "PreviewZoomableImage.qml" },
83 { tag: "Image", type: "image", source: "PreviewZoomableImage.qml" },
tests/qmltests/Dash/tst_Card.qml+15−3
@@ -55,8 +55,8 @@ Rectangle {
55 "layout": { "components": Helpers.update(JSON.parse(Helpers.fullMapping), { "art": { "aspect-ratio": 2 } }) }
55 "layout": { "components": Helpers.update(JSON.parse(Helpers.fullMapping), { "art": { "aspect-ratio": 2 } }) }
56 },
56 },
57 {
57 {
58− "name": "Art, title - fitted",
58+ "name": "Art, title - tall",
59− "layout": { "components": Helpers.update(JSON.parse(Helpers.fullMapping), { "art": { "fill-mode": "fit" } }) }
59+ "layout": { "components": Helpers.update(JSON.parse(Helpers.fullMapping), { "art": { "aspect-ratio": 0.7 } }) }
60 },
60 },
61 {
61 {
62 "name": "Art, header, summary - horizontal",
62 "name": "Art, header, summary - horizontal",
@@ -269,7 +269,7 @@ Rectangle {
269 { tag: "Small", width: units.gu(12), index: 1 },
269 { tag: "Small", width: units.gu(12), index: 1 },
270 { tag: "Large", width: units.gu(38), index: 2 },
270 { tag: "Large", width: units.gu(38), index: 2 },
271 { tag: "Wide", height: units.gu(19), size: "large", index: 3 },
271 { tag: "Wide", height: units.gu(19), size: "large", index: 3 },
272− { tag: "Fit", height: units.gu(38), size: "large", width: units.gu(19), index: 4 },
272+ { tag: "Tall", height: units.gu(38) / 0.7, size: "large", width: units.gu(38), index: 4 },
273 { tag: "VerticalWidth", width: function() { return headerRow.width + units.gu(1) * 2 }, index: 0 },
273 { tag: "VerticalWidth", width: function() { return headerRow.width + units.gu(1) * 2 }, index: 0 },
274 { tag: "HorizontalHeight", height: function() { return headerRow.height + units.gu(1) * 2 }, index: 5 },
274 { tag: "HorizontalHeight", height: function() { return headerRow.height + units.gu(1) * 2 }, index: 5 },
275 { tag: "HorizontalWidth", width: function() { return headerRow.x - units.gu(1) }, index: 5 },
275 { tag: "HorizontalWidth", width: function() { return headerRow.x - units.gu(1) }, index: 5 },
@@ -475,5 +475,17 @@ Rectangle {
475 compare(shape !== null, data.shape);
475 compare(shape !== null, data.shape);
476 tryCompare(mascotImage, "visible", !data.shape);
476 tryCompare(mascotImage, "visible", !data.shape);
477 }
477 }
478+
479+ function test_touchdown_visibility() {
480+ selector.selectedIndex = 0;
481+
482+ var touchdown = findChild(card, "touchdown");
483+
484+ compare(touchdown.visible, false);
485+ mousePress(card, card.width/2, card.height/2);
486+ compare(touchdown.visible, true);
487+ mouseRelease(card, card.width/2, card.height/2);
488+ compare(touchdown.visible, false);
489+ }
478 }
490 }
479}
491}
tests/qmltests/Dash/tst_Dash.qml+47−15
@@ -45,12 +45,8 @@ Item {
45 name: "Dash"
45 name: "Dash"
46 when: windowShown
46 when: windowShown
47
47
48− property var scopes
49−
50− Component.onCompleted: {
51− var dashContent = findChild(dash, "dashContent");
48+ readonly property Item dashContent: findChild(dash, "dashContent");
52− scopes = dashContent.scopes;
49+ readonly property var scopes: dashContent.scopes
53− }
54
50
55 function init() {
51 function init() {
56 // clear and reload the scopes.
52 // clear and reload the scopes.
@@ -59,14 +55,15 @@ Item {
59 verify(dashContentList != undefined);
55 verify(dashContentList != undefined);
60 tryCompare(dashContentList, "count", 0);
56 tryCompare(dashContentList, "count", 0);
61 scopes.load();
57 scopes.load();
58+ tryCompare(dashContentList, "currentIndex", 0);
62 }
59 }
63
60
64 function get_scope_data() {
61 function get_scope_data() {
65 return [
62 return [
66− { tag: "MockScope1", visualIndex: 0, shouldBeVisible: true },
63+ { tag: "MockScope1", visualIndex: 0 },
67− { tag: "MockScope2", visualIndex: -1, shouldBeVisible: false },
64+ { tag: "MockScope2", visualIndex: 1 },
68− { tag: "clickscope", visualIndex: 1, shouldBeVisible: true },
65+ { tag: "clickscope", visualIndex: 2 },
69− { tag: "MockScope5", visualIndex: 2, shouldBeVisible: true },
66+ { tag: "MockScope5", visualIndex: 3 },
70 ]
67 ]
71 }
68 }
72
69
@@ -75,10 +72,6 @@ Item {
75 }
72 }
76
73
77 function test_show_scope_on_load(data) {
74 function test_show_scope_on_load(data) {
78− if (data.shouldBeVisible == false) {
79− console.log("Not testing " + data.tag + ": not visible");
80− return;
81− }
82 var dashContentList = findChild(dash, "dashContentList");
75 var dashContentList = findChild(dash, "dashContentList");
83
76
84 dash.showScopeOnLoaded = data.tag
77 dash.showScopeOnLoaded = data.tag
@@ -86,10 +79,49 @@ Item {
86 tryCompare(dashContentList, "count", 0);
79 tryCompare(dashContentList, "count", 0);
87 scopes.load();
80 scopes.load();
88 tryCompare(scopes, "loaded", true);
81 tryCompare(scopes, "loaded", true);
89− tryCompare(dashContentList, "count", 4);
82+ tryCompare(dashContentList, "count", 5);
90
83
91 verify(dashContentList != undefined);
84 verify(dashContentList != undefined);
92 tryCompare(dashContentList, "currentIndex", data.visualIndex);
85 tryCompare(dashContentList, "currentIndex", data.visualIndex);
93 }
86 }
87+
88+ function test_setCurrentScope() {
89+ var dashContentList = findChild(dash, "dashContentList");
90+ var startX = dash.width - units.gu(1);
91+ var startY = dash.height / 2;
92+ var stopX = units.gu(1)
93+ var stopY = startY;
94+ var retry = 0;
95+ while (dashContentList.currentIndex != 2 && retry <= 5) {
96+ mouseFlick(dash, startX, startY, stopX, stopY)
97+ waitForRendering(dashContentList)
98+ retry++;
99+ }
100+ compare(dashContentList.currentIndex, 2);
101+ var dashCommunicatorService = findInvisibleChild(dash, "dashCommunicatorService");
102+ dashCommunicatorService.mockSetCurrentScope("clickscope", true, true);
103+ tryCompare(dashContentList, "currentIndex", 1)
104+ }
105+
106+ function test_processing_indicator() {
107+ tryCompare(scopes, "loaded", true);
108+
109+ var processingIndicator = findChild(dash, "processingIndicator");
110+ verify(processingIndicator, "Can't find the processing indicator.");
111+
112+ verify(!processingIndicator.visible, "Processing indicator should be visible.");
113+
114+ tryCompareFunction(function() {
115+ return scopes.getScope(dashContent.currentIndex) != null;
116+ }, true);
117+ var currentScope = scopes.getScope(dashContent.currentIndex);
118+ verify(currentScope, "Can't find the current scope.");
119+
120+ currentScope.setSearchInProgress(true);
121+ tryCompare(processingIndicator, "visible", true);
122+
123+ currentScope.setSearchInProgress(false);
124+ tryCompare(processingIndicator, "visible", false);
125+ }
94 }
126 }
95}
127}
tests/qmltests/Dash/tst_DashContent.qml+94−95
@@ -43,9 +43,6 @@ Item {
43 id: dashContent
43 id: dashContent
44 anchors.fill: parent
44 anchors.fill: parent
45
45
46− model: SortFilterProxyModel {
47− model: scopesModel
48− }
49 scopes : scopesModel
46 scopes : scopesModel
50 }
47 }
51
48
@@ -268,117 +265,119 @@ Item {
268 verify(carouselLV.tileWidth / carouselLV.tileHeight == cardTool.components["art"]["aspect-ratio"]);
265 verify(carouselLV.tileWidth / carouselLV.tileHeight == cardTool.components["art"]["aspect-ratio"]);
269 }
266 }
270
267
271− function test_departments() {
268+ function test_navigations() {
272− var dashDepartments = findChild(dashContent, "dashDepartments");
269+ var dashContentList = findChild(dashContent, "dashContentList");
273− compare(dashDepartments.visible, true);
270+ tryCompareFunction(function() { return findChild(dashContentList.currentItem, "dashNavigation") != null; }, true);
271+ var dashNavigation = findChild(dashContentList.currentItem, "dashNavigation");
272+ tryCompare(dashNavigation, "visible", true);
274− compare(dashDepartments.showList, false);
273+ compare(dashNavigation.showList, false);
275− waitForRendering(dashDepartments);
274+ waitForRendering(dashNavigation);
276− mouseClick(dashDepartments, 0, 0);
275+ mouseClick(dashNavigation, 0, 0);
277− compare(dashDepartments.showList, true);
276+ compare(dashNavigation.showList, true);
278−
277+
279− var departmentListView = findChild(dashDepartments, "departmentListView");
278+ var navigationListView = findChild(dashNavigation, "navigationListView");
280− compare(departmentListView.count, 1);
279+ compare(navigationListView.count, 1);
281− tryCompare(departmentListView.currentItem.department, "loaded", true);
280+ tryCompare(navigationListView.currentItem.navigation, "loaded", true);
282−
281+
283− waitForRendering(departmentListView);
282+ waitForRendering(navigationListView);
284− waitForRendering(departmentListView.currentItem);
283+ waitForRendering(navigationListView.currentItem);
285−
284+
286− var allButton = findChild(dashDepartments, "allButton");
285+ var allButton = findChild(dashNavigation, "allButton");
287 compare(allButton.visible, false);
286 compare(allButton.visible, false);
288
287
289− var department = findChild(dashDepartments, "department0child3");
288+ var navigation = findChild(dashNavigation, "navigation0child3");
290− mouseClick(department, 0, 0);
289+ mouseClick(navigation, 0, 0);
291− compare(dashDepartments.showList, false);
290+ compare(dashNavigation.showList, false);
292− tryCompare(dashDepartments.currentDepartment, "departmentId", "middle3");
291+ tryCompare(dashNavigation.currentNavigation, "navigationId", "middle3");
293− tryCompare(departmentListView.currentItem.department, "departmentId", "root");
292+ tryCompare(navigationListView.currentItem.navigation, "navigationId", "root");
294
293
295− mouseClick(dashDepartments, 0, 0);
294+ mouseClick(dashNavigation, 0, 0);
296− compare(dashDepartments.showList, true);
295+ compare(dashNavigation.showList, true);
297− waitForRendering(departmentListView);
296+ waitForRendering(navigationListView);
298− waitForRendering(departmentListView.currentItem);
297+ waitForRendering(navigationListView.currentItem);
299 compare(allButton.visible, true);
298 compare(allButton.visible, true);
300
299
301 mouseClick(allButton, 0, 0);
300 mouseClick(allButton, 0, 0);
302− compare(dashDepartments.showList, false);
301+ compare(dashNavigation.showList, false);
303− tryCompare(dashDepartments.currentDepartment, "departmentId", "root");
302+ tryCompare(dashNavigation.currentNavigation, "navigationId", "root");
304− tryCompare(departmentListView.currentItem.department, "departmentId", "root");
303+ tryCompare(navigationListView.currentItem.navigation, "navigationId", "root");
305−
304+
306− mouseClick(dashDepartments, 0, 0);
305+ mouseClick(dashNavigation, 0, 0);
307− compare(dashDepartments.showList, true);
306+ compare(dashNavigation.showList, true);
308− waitForRendering(departmentListView);
307+ waitForRendering(navigationListView);
309− waitForRendering(departmentListView.currentItem);
308+ waitForRendering(navigationListView.currentItem);
310 compare(allButton.visible, false);
309 compare(allButton.visible, false);
311
310
312− department = findChild(dashDepartments, "department0child2");
311+ navigation = findChild(dashNavigation, "navigation0child2");
313− mouseClick(department, 0, 0);
312+ mouseClick(navigation, 0, 0);
314− compare(dashDepartments.showList, true);
313+ compare(dashNavigation.showList, true);
315− tryCompare(dashDepartments.currentDepartment, "departmentId", "middle2");
314+ tryCompare(dashNavigation.currentNavigation, "navigationId", "middle2");
316− tryCompare(departmentListView.currentItem.department, "departmentId", "middle2");
315+ tryCompare(navigationListView.currentItem.navigation, "navigationId", "middle2");
317
316
318− var departmentList1 = findChild(dashDepartments, "department1");
317+ var navigationList1 = findChild(dashNavigation, "navigation1");
319− allButton = findChild(departmentList1, "allButton");
318+ allButton = findChild(navigationList1, "allButton");
320− var backButton = findChild(findChild(departmentList1, "department1"), "backButton");
319+ var backButton = findChild(findChild(navigationList1, "navigation1"), "backButton");
321 compare(allButton.visible, true);
320 compare(allButton.visible, true);
322 compare(backButton.visible, true);
321 compare(backButton.visible, true);
323
322
324− tryCompare(departmentListView, "contentX", departmentList1.x);
323+ tryCompare(navigationListView, "contentX", navigationList1.x);
325− waitForRendering(departmentListView);
324+ waitForRendering(navigationListView);
326 mouseClick(allButton, 0, 0);
325 mouseClick(allButton, 0, 0);
327− compare(dashDepartments.showList, false);
326+ compare(dashNavigation.showList, false);
328− tryCompare(dashDepartments.currentDepartment, "departmentId", "middle2");
327+ tryCompare(dashNavigation.currentNavigation, "navigationId", "middle2");
329− tryCompare(departmentListView.currentItem.department, "departmentId", "middle2");
328+ tryCompare(navigationListView.currentItem.navigation, "navigationId", "middle2");
330−
329+
331− mouseClick(dashDepartments, 0, 0);
330+ mouseClick(dashNavigation, 0, 0);
332− compare(dashDepartments.showList, true);
331+ compare(dashNavigation.showList, true);
333− waitForRendering(departmentListView);
332+ waitForRendering(navigationListView);
334− waitForRendering(departmentListView.currentItem);
333+ waitForRendering(navigationListView.currentItem);
335 compare(allButton.visible, true);
334 compare(allButton.visible, true);
336 compare(backButton.visible, true);
335 compare(backButton.visible, true);
337
336
338− tryCompare(departmentList1.department, "loaded", true);
337+ tryCompare(navigationList1.navigation, "loaded", true);
339− department = findChild(dashDepartments, "department1child2");
338+ navigation = findChild(dashNavigation, "navigation1child2");
340− mouseClick(department, 0, 0);
339+ mouseClick(navigation, 0, 0);
341− compare(dashDepartments.showList, false);
340+ compare(dashNavigation.showList, false);
342− tryCompare(dashDepartments.currentDepartment, "departmentId", "childmiddle22");
341+ tryCompare(dashNavigation.currentNavigation, "navigationId", "childmiddle22");
343− tryCompare(departmentListView.currentItem.department, "departmentId", "middle2");
342+ tryCompare(navigationListView.currentItem.navigation, "navigationId", "middle2");
344−
343+
345− mouseClick(dashDepartments, 0, 0);
344+ mouseClick(dashNavigation, 0, 0);
346− compare(dashDepartments.showList, true);
345+ compare(dashNavigation.showList, true);
347− waitForRendering(departmentListView);
346+ waitForRendering(navigationListView);
348− waitForRendering(departmentListView.currentItem);
347+ waitForRendering(navigationListView.currentItem);
349−
348+
350− tryCompare(departmentList1.department, "loaded", true);
349+ tryCompare(navigationList1.navigation, "loaded", true);
351− department = findChild(dashDepartments, "department1child3");
350+ navigation = findChild(dashNavigation, "navigation1child3");
352− mouseClick(department, 0, 0);
351+ mouseClick(navigation, 0, 0);
353− compare(dashDepartments.showList, false);
352+ compare(dashNavigation.showList, false);
354− tryCompare(dashDepartments.currentDepartment, "departmentId", "childmiddle23");
353+ tryCompare(dashNavigation.currentNavigation, "navigationId", "childmiddle23");
355− tryCompare(departmentListView.currentItem.department, "departmentId", "middle2");
354+ tryCompare(navigationListView.currentItem.navigation, "navigationId", "middle2");
356−
355+
357− mouseClick(dashDepartments, 0, 0);
356+ mouseClick(dashNavigation, 0, 0);
358− compare(dashDepartments.showList, true);
357+ compare(dashNavigation.showList, true);
359− waitForRendering(departmentListView);
358+ waitForRendering(navigationListView);
360− waitForRendering(departmentListView.currentItem);
359+ waitForRendering(navigationListView.currentItem);
361 mouseClick(backButton, 0, 0);
360 mouseClick(backButton, 0, 0);
362
361
363− tryCompare(dashDepartments.currentDepartment, "departmentId", "root");
362+ tryCompare(dashNavigation.currentNavigation, "navigationId", "root");
364− tryCompare(departmentListView.currentItem.department, "departmentId", "root");
363+ tryCompare(navigationListView.currentItem.navigation, "navigationId", "root");
365− compare(dashDepartments.showList, true);
364+ compare(dashNavigation.showList, true);
366− mouseClick(dashDepartments, 0, 0);
365+ mouseClick(dashNavigation, 0, 0);
367− compare(dashDepartments.showList, false);
366+ compare(dashNavigation.showList, false);
368−
367+
369− mouseClick(dashDepartments, 0, 0);
368+ mouseClick(dashNavigation, 0, 0);
370− compare(dashDepartments.showList, true);
369+ compare(dashNavigation.showList, true);
371− tryCompare(departmentListView.currentItem.department, "loaded", true);
370+ tryCompare(navigationListView.currentItem.navigation, "loaded", true);
372− department = findChild(dashDepartments, "department0child2");
371+ navigation = findChild(dashNavigation, "navigation0child2");
373− mouseClick(department, 0, 0);
372+ mouseClick(navigation, 0, 0);
374− compare(dashDepartments.showList, true);
373+ compare(dashNavigation.showList, true);
375− departmentList1 = findChild(dashDepartments, "department1");
374+ navigationList1 = findChild(dashNavigation, "navigation1");
376− compare(departmentList1.department.loaded, false);
375+ compare(navigationList1.navigation.loaded, false);
377− tryCompare(dashDepartments.currentDepartment, "departmentId", "middle2");
376+ tryCompare(dashNavigation.currentNavigation, "navigationId", "middle2");
378− allButton = findChild(departmentList1, "allButton");
377+ allButton = findChild(navigationList1, "allButton");
379− tryCompare(dashDepartments.currentDepartment, "departmentId", "middle2");
378+ tryCompare(dashNavigation.currentNavigation, "navigationId", "middle2");
380 mouseClick(allButton, 0, 0);
379 mouseClick(allButton, 0, 0);
381− tryCompare(dashDepartments.currentDepartment, "departmentId", "middle2");
380+ tryCompare(dashNavigation.currentNavigation, "navigationId", "middle2");
382 }
381 }
383 }
382 }
384}
383}
tests/qmltests/Dash/tst_GenericScopeView.qml+3−2
@@ -129,8 +129,9 @@ Item {
129 var initialHeight = category.height;
129 var initialHeight = category.height;
130 mouseClick(seeAll, seeAll.width / 2, seeAll.height / 2);
130 mouseClick(seeAll, seeAll.width / 2, seeAll.height / 2);
131 verify(category.expanded);
131 verify(category.expanded);
132− tryCompareFunction(function() { return category.height > initialHeight; }, true);
132+ tryCompare(category, "height", category.item.expandedHeight + seeAll.height);
133
133
134+ waitForRendering(seeAll);
134 mouseClick(seeAll, seeAll.width / 2, seeAll.height / 2);
135 mouseClick(seeAll, seeAll.width / 2, seeAll.height / 2);
135 verify(!category.expanded);
136 verify(!category.expanded);
136 }
137 }
@@ -319,7 +320,7 @@ Item {
319 units.gu(2),
320 units.gu(2),
320 testCase.previewListView.height / 2);
321 testCase.previewListView.height / 2);
321 tryCompare(previewListViewList, "moving", false);
322 tryCompare(previewListViewList, "moving", false);
322− tryCompare(testCase.previewListView.currentItem, "objectName", "previewItem" + i);
323+ tryCompare(testCase.previewListView.currentItem, "objectName", "preview" + i);
323
324
324 }
325 }
325 closePreview();
326 closePreview();
tests/qmltests/Panel/Indicators/tst_MenuItemFactory.qml+47
@@ -112,6 +112,7 @@ Item {
112
112
113 { tag: 'wifisection', type: "unity.widgets.systemsettings.tablet.wifisection", objectName: "wifiSection" },
113 { tag: 'wifisection', type: "unity.widgets.systemsettings.tablet.wifisection", objectName: "wifiSection" },
114 { tag: 'accesspoint', type: "unity.widgets.systemsettings.tablet.accesspoint", objectName: "accessPoint" },
114 { tag: 'accesspoint', type: "unity.widgets.systemsettings.tablet.accesspoint", objectName: "accessPoint" },
115+ { tag: 'modeminfoitem', type: "com.canonical.indicator.network.modeminfoitem", objectName: "modemInfoItem" },
115
116
116 { tag: 'unknown', type: "", objectName: "standardMenu"}
117 { tag: 'unknown', type: "", objectName: "standardMenu"}
117 ];
118 ];
@@ -542,6 +543,52 @@ Item {
542 compare(loader.item.enabled, data.enabled, "Enabled does not match data");
543 compare(loader.item.enabled, data.enabled, "Enabled does not match data");
543 }
544 }
544
545
546+ function test_create_modemInfoItem_data() {
547+ // ModemInfoItem gets all it's data through the actions.
548+ return [
549+ {
550+ label: "",
551+ enabled: true,
552+ checked: false,
553+ statusLabelAction: "action::statusLabel",
554+ statusIconAction: "action::statusIcon",
555+ connectivityIconAction: "action::connectivityIcon",
556+ simIdentifierLabelAction: "action::simIdentifierLabel",
557+ roamingAction: "action::roaming",
558+ unlockAction: "action::unlock"
559+ }
560+ ];
561+ }
562+
563+ function test_create_modemInfoItem(data) {
564+ menuData.type = "com.canonical.indicator.network.modeminfoitem";
565+ menuData.label = data.label;
566+ menuData.sensitive = data.enabled;
567+ menuData.isToggled = data.checked;
568+ menuData.ext = {
569+ 'xCanonicalModemStatusLabelAction': data.statusLabelAction,
570+ 'xCanonicalModemStatusIconAction': data.statusIconAction,
571+ 'xCanonicalModemConnectivityIconAction': data.connectivityIconAction,
572+ 'xCanonicalModemSimIdentifierLabelAction': data.simIdentifierLabelAction,
573+ 'xCanonicalModemRoamingAction': data.roamingAction,
574+ 'xCanonicalModemLockedAction': data.unlockAction,
575+ };
576+
577+ loader.data = menuData;
578+ loader.sourceComponent = factory.load(menuData);
579+ tryCompareFunction(function() { return loader.item != undefined; }, true);
580+ compare(loader.item.objectName, "modemInfoItem", "Should have created a modem info item.");
581+ compare(loader.item.text, data.label, "Label does not match data");
582+
583+ compare(loader.item.statusLabelAction.name, data.statusLabelAction, "StatusLabel action incorrect");
584+ compare(loader.item.statusIconAction.name, data.statusIconAction, "StatusIcon action incorrect");
585+ compare(loader.item.connectivityIconAction.name, data.connectivityIconAction, "ConnectivityIcon action incorrect");
586+ compare(loader.item.simIdentifierLabelAction.name, data.simIdentifierLabelAction, " action incorrect");
587+ compare(loader.item.roamingAction.name, data.roamingAction, "Roaming action incorrect");
588+ compare(loader.item.unlockAction.name, data.unlockAction, "Unlock action incorrect");
589+ compare(loader.item.enabled, data.enabled, "Enabled does not match data");
590+ }
591+
545 function test_create_messageItem() {
592 function test_create_messageItem() {
546 menuData.type = "com.canonical.indicator.messages.messageitem";
593 menuData.type = "com.canonical.indicator.messages.messageitem";
547
594
tests/qmltests/Stages/tst_PhoneStage.qml+3−2
@@ -231,9 +231,10 @@ Item {
231 }
231 }
232
232
233 function cleanup() {
233 function cleanup() {
234− while (ApplicationManager.count > 0) {
234+ while (ApplicationManager.count > 1) {
235 var oldCount = ApplicationManager.count;
235 var oldCount = ApplicationManager.count;
236+ var closingIndex = ApplicationManager.focusedApplicationId == "unity8-dash" ? 1 : 0
236− ApplicationManager.stopApplication(ApplicationManager.get(0).appId)
237+ ApplicationManager.stopApplication(ApplicationManager.get(closingIndex).appId)
237 tryCompare(ApplicationManager, "count", oldCount - 1)
238 tryCompare(ApplicationManager, "count", oldCount - 1)
238 }
239 }
239 }
240 }
tests/qmltests/tst_Shell.qml+62−275
@@ -56,49 +56,20 @@ Item {
56 signalName: "sessionStarted"
56 signalName: "sessionStarted"
57 }
57 }
58
58
59+ SignalSpy {
60+ id: dashCommunicatorSpy
61+ signalName: "setCurrentScopeCalled"
62+ }
63+
59 UT.UnityTestCase {
64 UT.UnityTestCase {
60 name: "Shell"
65 name: "Shell"
61 when: windowShown
66 when: windowShown
62
67
63 function initTestCase() {
68 function initTestCase() {
64− var ok = false;
65− var attempts = 0;
66− var maxAttempts = 1000;
67−
68− // Qt loads a qml scene asynchronously. So early on, some findChild() calls made in
69− // tests may fail because the desired child item wasn't loaded yet.
70− // Thus here we try to ensure the scene has been fully loaded before proceeding with the tests.
71− // As I couldn't find an API in QQuickView & friends to tell me that the scene is 100% loaded
72− // (all items instantiated, etc), I resort to checking the existence of some key items until
73− // repeatedly until they're all there.
74− do {
75− var dashContentList = findChild(shell, "dashContentList");
76− waitForRendering(dashContentList);
77− var homeLoader = findChild(dashContentList, "clickscope loader");
78− ok = homeLoader !== null
79− && homeLoader.item !== undefined;
80−
81− var greeter = findChild(shell, "greeter");
82− ok &= greeter !== null;
83−
84− var launcherPanel = findChild(shell, "launcherPanel");
85− ok &= launcherPanel !== null;
86−
87− attempts++;
88− if (!ok) {
89− console.log("Attempt " + attempts + " failed. Waiting a bit before trying again.");
90− // wait a bit before retrying
91− wait(100);
92− } else {
93− console.log("All seem fine after " + attempts + " attempts.");
94− }
95− } while (!ok && attempts <= maxAttempts);
96−
97− verify(ok);
98−
99 swipeAwayGreeter();
69 swipeAwayGreeter();
100
70
101 sessionSpy.target = findChild(shell, "greeter")
71 sessionSpy.target = findChild(shell, "greeter")
72+ dashCommunicatorSpy.target = findInvisibleChild(shell, "dashCommunicator");
102 }
73 }
103
74
104 function cleanup() {
75 function cleanup() {
@@ -111,56 +82,16 @@ Item {
111 // kill all (fake) running apps
82 // kill all (fake) running apps
112 killApps(ApplicationManager);
83 killApps(ApplicationManager);
113
84
114− var dashContent = findChild(shell, "dashContent");
85+ waitForUIToSettle();
115− dashContent.closePreview();
116−
117− var dashHome = findChild(shell, "clickscope loader");
118− swipeUntilScopeViewIsReached(dashHome);
119−
120 hideIndicators();
86 hideIndicators();
121 }
87 }
122
88
123− function killApps(apps) {
89+ function killApps() {
124− if (!apps) return;
125− while (apps.count > 0) {
90+ while (ApplicationManager.count > 1) {
91+ var appIndex = ApplicationManager.get(0).appId == "unity8-dash" ? 1 : 0
126− ApplicationManager.stopApplication(apps.get(0).appId);
92+ ApplicationManager.stopApplication(ApplicationManager.get(appIndex).appId);
127 }
93 }
128− compare(ApplicationManager.count, 0)
94+ compare(ApplicationManager.count, 1)
129− }
130−
131− /*
132− Test the effect of a right-edge drag on the dash in 3 situations:
133− 1 - when no application has been launched yet
134− 2 - when there's a minimized application
135− 3 - after the last running application has been closed/stopped
136−
137− The behavior of Dash on 3 should be the same as on 1.
138− */
139− function test_rightEdgeDrag() {
140− checkRightEdgeDragWithNoRunningApps();
141−
142− dragLauncherIntoView();
143−
144− // Launch an app from the launcher
145− tapOnAppIconInLauncher();
146− waitUntilApplicationWindowIsFullyVisible();
147−
148− // Minimize the application we just launched
149− swipeFromLeftEdge(units.gu(27));
150−
151− waitForUIToSettle();
152−
153− checkRightEdgeDragWithMinimizedApp();
154−
155− // Minimize that application once again
156− swipeFromLeftEdge(units.gu(27));
157−
158− // Right edge behavior should now be the same as before that app,
159− // was launched. Manually cleanup beforehand to get to initial
160− // state.
161− cleanup();
162− waitForUIToSettle();
163− checkRightEdgeDragWithNoRunningApps();
164 }
95 }
165
96
166 function test_leftEdgeDrag_data() {
97 function test_leftEdgeDrag_data() {
@@ -183,7 +114,7 @@ Item {
183
114
184 swipeFromLeftEdge(data.swipeLength);
115 swipeFromLeftEdge(data.swipeLength);
185 if (data.appHides)
116 if (data.appHides)
186− waitUntilApplicationWindowIsFullyHidden();
117+ waitUntilDashIsFocused();
187 else
118 else
188 waitUntilApplicationWindowIsFullyVisible();
119 waitUntilApplicationWindowIsFullyVisible();
189 }
120 }
@@ -239,100 +170,18 @@ Item {
239 waitForRendering(greeter);
170 waitForRendering(greeter);
240 }
171 }
241
172
242− /*
243− Perform a right-edge drag when the Dash is being show and there are
244− no running/minimized apps to be restored.
245−
246− The expected behavior is that an animation should be played to hint the
247− user that his right-edge drag gesture has been successfully recognized
248− but there is no application to be brought to foreground.
249− */
250− function checkRightEdgeDragWithNoRunningApps() {
251− var touchX = shell.width - (shell.edgeSize / 2);
252− var touchY = shell.height / 2;
253−
254− var dash = findChild(shell, "dash");
255− // check that dash has normal scale and opacity
256− tryCompare(dash, "contentScale", 1.0);
257− tryCompare(dash, "opacity", 1.0);
258−
259− touchFlick(shell, touchX, touchY, shell.width * 0.1, touchY,
260− true /* beginTouch */, false /* endTouch */, units.gu(10), 50);
261−
262− // check that Dash has been scaled down and had its opacity reduced
263− tryCompareFunction(function() { return dash.contentScale <= 0.9; }, true);
264− tryCompareFunction(function() { return dash.opacity <= 0.5; }, true);
265−
266− touchRelease(shell, shell.width * 0.1, touchY);
267−
268− // and now everything should have gone back to normal
269− tryCompare(dash, "contentScale", 1.0);
270− tryCompare(dash, "opacity", 1.0);
271− }
272−
273− /*
274− Perform a right-edge drag when the Dash is being show and there is
275− a running/minimized app to be restored.
276−
277− The expected behavior is that the dash should fade away and ultimately be
278− made invisible once the gesture is finished as the restored app will now
279− be on foreground.
280− */
281− function checkRightEdgeDragWithMinimizedApp() {
282− var touchX = shell.width - (shell.edgeSize / 2);
283− var touchY = shell.height / 2;
284−
285− var dash = findChild(shell, "dash");
286− // check that dash has normal scale and opacity
287− tryCompare(dash, "contentScale", 1.0);
288− tryCompare(dash, "opacity", 1.0);
289−
290− touchFlick(shell, touchX, touchY, shell.width * 0.1, touchY,
291− true /* beginTouch */, false /* endTouch */, units.gu(10), 50);
292−
293− // check that Dash has been scaled down and had its opacity reduced
294− tryCompareFunction(function() { return dash.contentScale <= 0.9; }, true);
295− tryCompareFunction(function() { return dash.opacity <= 0.5; }, true);
296−
297− touchRelease(shell, shell.width * 0.1, touchY);
298−
299− // dash should have gone away, now that the app is on foreground
300− tryCompare(dash, "visible", false);
301− }
302−
303 /*
173 /*
304 Regression test for bug https://bugs.launchpad.net/touch-preview-images/+bug/1193419
174 Regression test for bug https://bugs.launchpad.net/touch-preview-images/+bug/1193419
305
175
306− When the user minimizes an application (left-edge swipe) he should always end up in the "Running Apps"
176+ When the user minimizes an application (left-edge swipe) he should always end up in the
307− category of the "Applications" scope view.
177+ "Applications" scope view.
308
178
309 Steps:
179 Steps:
310− - go to apps lens
311− - scroll to the bottom
312− - reveal launcher and launch an app
180+ - reveal launcher and launch an app that covers the dash
313 - perform long left edge swipe to go minimize the app and go back to the dash.
181 - perform long left edge swipe to go minimize the app and go back to the dash.
314−
182+ - verify the setCurrentScope() D-Bus call to the dash has been called for the correct scope id.
315− Expected Results
316− - apps lens shown
317 */
183 */
318 function test_minimizingAppTakesToDashApps() {
184 function test_minimizingAppTakesToDashApps() {
319− var dashApps = findChild(shell, "clickscope");
320− swipeUntilScopeViewIsReached(dashApps);
321−
322− // swipe finger up until the running/recent apps section (which we assume
323− // it's the first one) is as far from view as possible.
324− // We also assume that DashApps is tall enough that it's scrollable
325− var appsCategoryListView = findChild(dashApps, "categoryListView");
326− while (!appsCategoryListView.atYEnd) {
327− swipeUpFromCenter();
328− tryCompare(appsCategoryListView, "moving", false);
329− }
330−
331− // Switch away from the Applications scope.
332− swipeRightFromCenter();
333− waitUntilItemStopsMoving(dashApps);
334− verify(!itemIsOnScreen(dashApps));
335−
336 dragLauncherIntoView();
185 dragLauncherIntoView();
337
186
338 // Launch an app from the launcher
187 // Launch an app from the launcher
@@ -340,19 +189,16 @@ Item {
340
189
341 waitUntilApplicationWindowIsFullyVisible();
190 waitUntilApplicationWindowIsFullyVisible();
342
191
343− // Dragging launcher into view with a little bit of gap (units.gu(1)) should switch to Apps scope
192+ verify(ApplicationManager.focusedApplicationId !== "unity8-dash")
344− dragLauncherIntoView();
345− verify(itemIsOnScreen(dashApps));
346
193
194+ dashCommunicatorSpy.clear();
347 // Minimize the application we just launched
195 // Minimize the application we just launched
348 swipeFromLeftEdge(units.gu(27));
196 swipeFromLeftEdge(units.gu(27));
349
197
350− // Wait for the whole UI to settle down
198+ tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
351− waitUntilApplicationWindowIsFullyHidden();
352− waitUntilItemStopsMoving(dashApps);
353− tryCompare(appsCategoryListView, "moving", false);
354
199
355− verify(itemIsOnScreen(dashApps));
200+ compare(dashCommunicatorSpy.count, 1);
201+ compare(dashCommunicatorSpy.signalArguments[0][0], "clickscope");
356 }
202 }
357
203
358 function test_showInputMethod() {
204 function test_showInputMethod() {
@@ -409,9 +255,14 @@ Item {
409
255
410 // Wait for the whole UI to settle down
256 // Wait for the whole UI to settle down
411 function waitForUIToSettle() {
257 function waitForUIToSettle() {
412− waitUntilApplicationWindowIsFullyHidden();
413− var dashContentList = findChild(shell, "dashContentList");
258+ var launcher = findChild(shell, "launcherPanel")
414− tryCompare(dashContentList, "moving", false);
259+ tryCompareFunction(function() {return launcher.x === 0 || launcher.x === -launcher.width;}, true);
260+ if (launcher.x === 0) {
261+ mouseClick(shell, shell.width / 2, shell.height / 2)
262+ }
263+ tryCompare(launcher, "x", -launcher.width)
264+
265+ waitForRendering(shell)
415 }
266 }
416
267
417 function dragToCloseIndicatorsPanel() {
268 function dragToCloseIndicatorsPanel() {
@@ -468,24 +319,13 @@ Item {
468 }
319 }
469
320
470 function waitUntilApplicationWindowIsFullyVisible() {
321 function waitUntilApplicationWindowIsFullyVisible() {
471− var underlay = findChild(shell, "underlay");
322+ var appDelegate = findChild(shell, "appDelegate0")
472− tryCompare(underlay, "visible", false);
323+ var surfaceContainer = findChild(appDelegate, "surfaceContainer");
324+ tryCompareFunction(function() { return surfaceContainer.surface !== null; }, true);
473 }
325 }
474
326
475− function waitUntilApplicationWindowIsFullyHidden() {
327+ function waitUntilDashIsFocused() {
476− var stages = findChild(shell, "stages");
328+ tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
477− tryCompare(stages, "fullyHidden", true);
478− }
479−
480− function swipeUntilScopeViewIsReached(scopeView) {
481− while (!itemIsOnScreen(scopeView)) {
482− if (itemIsToLeftOfScreen(scopeView)) {
483− swipeRightFromCenter();
484− } else {
485− swipeLeftFromCenter();
486− }
487− waitUntilItemStopsMoving(scopeView);
488− }
489 }
329 }
490
330
491 function swipeFromLeftEdge(swipeLength) {
331 function swipeFromLeftEdge(swipeLength) {
@@ -494,24 +334,6 @@ Item {
494 touchFlick(shell, touchStartX, touchStartY, swipeLength, touchStartY);
334 touchFlick(shell, touchStartX, touchStartY, swipeLength, touchStartY);
495 }
335 }
496
336
497− function swipeLeftFromCenter() {
498− var touchStartX = shell.width * 3 / 4;
499− var touchStartY = shell.height / 2;
500− touchFlick(shell, touchStartX, touchStartY, 0, touchStartY);
501− }
502−
503− function swipeRightFromCenter() {
504− var touchStartX = shell.width * 3 / 4;
505− var touchStartY = shell.height / 2;
506− touchFlick(shell, touchStartX, touchStartY, shell.width, touchStartY);
507− }
508−
509− function swipeUpFromCenter() {
510− var touchStartX = shell.width / 2;
511− var touchStartY = shell.height / 2;
512− touchFlick(shell, touchStartX, touchStartY, touchStartX, 0);
513− }
514−
515 function itemIsOnScreen(item) {
337 function itemIsOnScreen(item) {
516 var itemRectInShell = item.mapToItem(shell, 0, 0, item.width, item.height);
338 var itemRectInShell = item.mapToItem(shell, 0, 0, item.width, item.height);
517
339
@@ -521,64 +343,6 @@ Item {
521 && itemRectInShell.y + itemRectInShell.height <= shell.height;
343 && itemRectInShell.y + itemRectInShell.height <= shell.height;
522 }
344 }
523
345
524− function itemIsToLeftOfScreen(item) {
525− var itemRectInShell = item.mapToItem(shell, 0, 0, item.width, item.height);
526− return itemRectInShell.x < 0;
527− }
528−
529− function waitUntilItemStopsMoving(item) {
530− var itemRectInShell = item.mapToItem(shell, 0, 0, item.width, item.height);
531− var previousX = itemRectInShell.x;
532− var previousY = itemRectInShell.y;
533− var isStill = false;
534−
535− do {
536− wait(100);
537− itemRectInShell = item.mapToItem(shell, 0, 0, item.width, item.height);
538− if (itemRectInShell.x == previousX && itemRectInShell.y == previousY) {
539− isStill = true;
540− } else {
541− previousX = itemRectInShell.x;
542− previousY = itemRectInShell.y;
543− }
544− } while (!isStill);
545− }
546−
547− function test_DashShown_data() {
548− return [
549− {tag: "in focus", greeter: false, app: false, launcher: false, indicators: false, expectedShown: true},
550− {tag: "under greeter", greeter: true, app: false, launcher: false, indicators: false, expectedShown: false},
551− {tag: "under app", greeter: false, app: true, launcher: false, indicators: false, expectedShown: false},
552− {tag: "under launcher", greeter: false, app: false, launcher: true, indicators: false, expectedShown: true},
553− {tag: "under indicators", greeter: false, app: false, launcher: false, indicators: true, expectedShown: false},
554− ]
555− }
556−
557− function test_DashShown(data) {
558− if (data.greeter) {
559− // Swipe the greeter in
560− var greeter = findChild(shell, "greeter");
561− Powerd.displayPowerStateChange(Powerd.Off, 0);
562− tryCompare(greeter, "showProgress", 1);
563− }
564−
565− if (data.app) {
566− dragLauncherIntoView();
567− tapOnAppIconInLauncher();
568− }
569−
570− if (data.launcher) {
571− dragLauncherIntoView();
572− }
573−
574− if (data.indicators) {
575− showIndicators();
576− }
577−
578− var dash = findChild(shell, "dash");
579− tryCompare(dash, "shown", data.expectedShown);
580− }
581−
582 function test_focusRequestedHidesGreeter() {
346 function test_focusRequestedHidesGreeter() {
583 var greeter = findChild(shell, "greeter");
347 var greeter = findChild(shell, "greeter");
584
348
@@ -587,10 +351,9 @@ Item {
587 tryCompareFunction(function() { return app.surface != null }, true);
351 tryCompareFunction(function() { return app.surface != null }, true);
588
352
589 // Minimize the application we just launched
353 // Minimize the application we just launched
590− swipeFromLeftEdge(units.gu(27));
354+ swipeFromLeftEdge(units.gu(26) + 1);
591
355
592− // Wait for the whole UI to settle down
356+ waitUntilDashIsFocused();
593− waitUntilApplicationWindowIsFullyHidden();
594
357
595 greeter.show();
358 greeter.show();
596 tryCompare(greeter, "showProgress", 1);
359 tryCompare(greeter, "showProgress", 1);
@@ -606,8 +369,9 @@ Item {
606
369
607 showIndicators();
370 showIndicators();
608
371
372+ var oldCount = ApplicationManager.count;
609 ApplicationManager.startApplication("camera-app");
373 ApplicationManager.startApplication("camera-app");
610− tryCompare(ApplicationManager, "count", 1);
374+ tryCompare(ApplicationManager, "count", oldCount + 1);
611
375
612 tryCompare(indicators, "fullyClosed", true);
376 tryCompare(indicators, "fullyClosed", true);
613 }
377 }
@@ -616,6 +380,7 @@ Item {
616 function test_showGreeterDBusCall() {
380 function test_showGreeterDBusCall() {
617 var greeter = findChild(shell, "greeter")
381 var greeter = findChild(shell, "greeter")
618 tryCompare(greeter, "showProgress", 0)
382 tryCompare(greeter, "showProgress", 0)
383+ waitForRendering(greeter);
619 LightDM.Greeter.showGreeter()
384 LightDM.Greeter.showGreeter()
620 tryCompare(greeter, "showProgress", 1)
385 tryCompare(greeter, "showProgress", 1)
621 }
386 }
@@ -624,6 +389,7 @@ Item {
624 sessionSpy.clear()
389 sessionSpy.clear()
625
390
626 var greeter = findChild(shell, "greeter")
391 var greeter = findChild(shell, "greeter")
392+ waitForRendering(greeter)
627 greeter.show()
393 greeter.show()
628 tryCompare(greeter, "showProgress", 1)
394 tryCompare(greeter, "showProgress", 1)
629
395
@@ -644,5 +410,26 @@ Item {
644 ApplicationManager.requestFocusApplication("gallery-app");
410 ApplicationManager.requestFocusApplication("gallery-app");
645 tryCompare(panel, "fullscreenMode", false);
411 tryCompare(panel, "fullscreenMode", false);
646 }
412 }
413+
414+ function test_leftEdgeDragFullscreen() {
415+ var panel = findChild(shell, "panel");
416+ tryCompare(panel, "fullscreenMode", false)
417+
418+ ApplicationManager.startApplication("camera-app");
419+ tryCompare(panel, "fullscreenMode", true)
420+
421+ var touchStartX = 2;
422+ var touchStartY = shell.height / 2;
423+
424+ touchFlick(shell, touchStartX, touchStartY, units.gu(2), touchStartY, true, false);
425+
426+ compare(panel.fullscreenMode, true);
427+
428+ touchFlick(shell, units.gu(2), touchStartY, units.gu(10), touchStartY, false, false);
429+
430+ tryCompare(panel, "fullscreenMode", false);
431+
432+ touchRelease(shell);
433+ }
647 }
434 }
648}
435}
tests/qmltests/tst_ShellWithPin.qml+4−37
@@ -58,40 +58,6 @@ Item {
58 when: windowShown
58 when: windowShown
59
59
60 function initTestCase() {
60 function initTestCase() {
61− var ok = false;
62− var attempts = 0;
63− var maxAttempts = 1000;
64−
65− // Qt loads a qml scene asynchronously. So early on, some findChild() calls made in
66− // tests may fail because the desired child item wasn't loaded yet.
67− // Thus here we try to ensure the scene has been fully loaded before proceeding with the tests.
68− // As I couldn't find an API in QQuickView & friends to tell me that the scene is 100% loaded
69− // (all items instantiated, etc), I resort to checking the existence of some key items until
70− // repeatedly until they're all there.
71− do {
72− var dashContentList = findChild(shell, "dashContentList");
73− waitForRendering(dashContentList);
74− var homeLoader = findChild(dashContentList, "clickscope loader");
75− ok = homeLoader !== null
76− && homeLoader.item !== undefined;
77−
78− var greeter = findChild(shell, "greeter");
79− ok &= greeter !== null;
80−
81− var launcherPanel = findChild(shell, "launcherPanel");
82− ok &= launcherPanel !== null;
83−
84− attempts++;
85− if (!ok) {
86− console.log("Attempt " + attempts + " failed. Waiting a bit before trying again.");
87− // wait a bit before retrying
88− wait(100);
89− } else {
90− console.log("All seem fine after " + attempts + " attempts.");
91− }
92− } while (!ok && attempts <= maxAttempts);
93−
94− verify(ok);
95
61
96 sessionSpy.target = findChild(shell, "greeter")
62 sessionSpy.target = findChild(shell, "greeter")
97 }
63 }
@@ -110,10 +76,11 @@ Item {
110 }
76 }
111
77
112 function killApps() {
78 function killApps() {
113− while (ApplicationManager.count > 0) {
79+ while (ApplicationManager.count > 1) {
80+ var appIndex = ApplicationManager.get(0).appId == "unity8-dash" ? 1 : 0
114− ApplicationManager.stopApplication(ApplicationManager.get(0).appId)
81+ ApplicationManager.stopApplication(ApplicationManager.get(appIndex).appId);
115 }
82 }
116− compare(ApplicationManager.count, 0)
83+ compare(ApplicationManager.count, 1)
117 }
84 }
118
85
119 function swipeAwayGreeter() {
86 function swipeAwayGreeter() {