on xenial help sign in
[ Michal Hruby ]

* Work with the scopes-v4 branch + departments->navigation renaming [ Michał Sawicz ] * Hardcode art shape size for click scope local and predefined categories While at it, drop the fillmode of cards * Use the correct API in PageHeader. (LP: #1353048) * Refactor dash activity indicator. (LP: #1351539) [ Albert Astals ] * Dash Departments fixes Update maxHeight manually since it depends on the position of the item and its parents and it can't know when the binding has to be updated Make parent stuff non interactive when the department list is shown * PageHeader: when on search clip y-coordinates otherwise the background spills out when on search (LP: #1350398) * Dash: Implement OverlayColor support in Cards * Hardcode art shape size for click scope local and predefined categories While at it, drop the fillmode of cards * Make test_departments test more stable There's various DashDepartments on the dash, make sure we're working over the one that is on screen, otherwise clicks don't end up where they should * Work with the scopes-v4 branch + departments->navigation renaming * Fixes for dash as app Load i18n catalog Process command line options Add the posibility to have a mouse touch adaptor (LP: #1353351) * Implement the Expandable Preview Widget Now TextSummary is not expandable by itself anymore, you have to use it inside an Expandable to get the behaviour * Add test prefix to xml output, seems CI needs it [ Antti Kaijanmäki ] * Indicators: Adds new ModemInfoItem to be used with indicator-network (LP: #1329204) [ Michael Terry ] * When the edge demo is running, don't show the greeter if the screen is turned off. This avoids an odd interaction where parts of the greeter are disabled but the edge demo isn't visible until you slide the greeter away. (LP: #1283425) * Don't hardcode the phablet password in our testing script. [ Ying-Chun Liu ] * Add divider dots. [ Mirco Müller ] * Make sure the TextField of a snap-decision notification has the active focus upon creation, thus the osk shows up right away. (LP: #1346867) [ Andrea Cimitan ] * Add touchdown effect to dash cards. * Import Ubuntu.Components for preview image gallery to pick up default flicking speeds.

commit3823278a36f37499e02b23aeb2114994be68aaae authorDiego Sarmentero <diego.sarmentero@gmail.com> dateFri 8 Aug 2014, 10:11 (12 years ago) parent919c5a48705631
77 files changed+1379−705
cmake/modules/QmlTest.cmake+2−2 debian/changelog+58 debian/control+2−2 plugins/Dash/CardCreator.js+26−12 plugins/Dash/ScopeStyle.qml+11−8 po/es.po+2−2 po/eu.po+2−2 po/hu.po+2−2 po/ja.po+7−7 po/pt_BR.po+7−7 po/sl.po+2−2 qml/Components/EdgeDemo.qml+15−15 qml/Components/PageHeader.qml+25−16 qml/Components/SeeMore.qml−70 qml/Components/graphics/pagination_dot_off@30.png qml/Components/graphics/pagination_dot_on@30.png qml/Dash/CardTool.qml+1−1 qml/Dash/Dash.qml+84−11 qml/Dash/DashApplication.qml+7 qml/Dash/DashContent.qml+7−4 qml/Dash/DashDepartments.qml → qml/Dash/DashNavigation.qml+50−43 qml/Dash/DashDepartmentsList.qml → qml/Dash/DashNavigationList.qml+14−18 qml/Dash/GenericScopeView.qml+12−12 qml/Dash/PreviewListView.qml+23−27 qml/Dash/Previews/PreviewExpandable.qml+101 qml/Dash/Previews/PreviewImageGallery.qml+1 qml/Dash/Previews/PreviewTextSummary.qml+3−16 qml/Dash/Previews/PreviewWidget.qml+3 qml/Dash/Previews/PreviewWidgetFactory.qml+5 qml/Greeter/Greeter.qml+1−1 qml/Notifications/NotificationMenuItemFactory.qml+3 qml/Panel/Indicators/MenuItemFactory.qml+74 qml/Panel/Indicators/ModemInfoItem.qml+111 qml/Panel/Indicators/RoamingIndication.qml+40 qml/ScopeTool.qml+2−11 qml/Shell.qml+4−23 run_on_device.sh+1−3 src/Dash/CMakeLists.txt+1 src/Dash/main.cpp+26−4 tests/autopilot/unity8/shell/emulators/dash.py+1−1 tests/mocks/Unity/CMakeLists.txt+3−3 tests/mocks/Unity/Unity.qmltypes+79−27 tests/mocks/Unity/fake_department.cpp → tests/mocks/Unity/fake_navigation.cpp+32−40 tests/mocks/Unity/fake_department.h → tests/mocks/Unity/fake_navigation.h+13−13 tests/mocks/Unity/fake_scope.cpp+65−17 tests/mocks/Unity/fake_scope.h+16−8 tests/mocks/Unity/fake_scopes.cpp+10−2 tests/mocks/Unity/fake_scopes.h+1 tests/mocks/Unity/fake_unity_plugin.cpp+2−2 tests/plugins/Dash/cardcreator/1.res+12−10 tests/plugins/Dash/cardcreator/1.tst+1−1 tests/plugins/Dash/cardcreator/2.res+8 tests/plugins/Dash/cardcreator/2.tst+1−1 tests/plugins/Dash/cardcreator/3.res+12−10 tests/plugins/Dash/cardcreator/3.tst+1−1 tests/plugins/Dash/cardcreator/4.res+8 tests/plugins/Dash/cardcreator/4.tst+1−1 tests/plugins/Dash/cardcreator/5.res+14−12 tests/plugins/Dash/cardcreator/5.tst+1−1 tests/plugins/Dash/cardcreator/6.res+10−8 tests/plugins/Dash/cardcreator/6.tst+1−1 tests/plugins/Dash/cardcreator/7.res+9−1 tests/plugins/Dash/cardcreator/7.tst+1−1 tests/plugins/Dash/cardcreatortest.cpp+13−4 tests/plugins/Dash/tst_ScopeStyle.qml+14−7 tests/qmltests/CMakeLists.txt+1−1 tests/qmltests/Components/tst_PageHeader.qml+21−23 tests/qmltests/Components/tst_SeeMore.qml−52 tests/qmltests/Dash/CardHelpers.js+4−3 tests/qmltests/Dash/Previews/tst_PreviewExpandable.qml+97 tests/qmltests/Dash/Previews/tst_PreviewTextSummary.qml+4−18 tests/qmltests/Dash/Previews/tst_PreviewWidgetFactory.qml+1 tests/qmltests/Dash/tst_Card.qml+15−3 tests/qmltests/Dash/tst_Dash.qml+28−15 tests/qmltests/Dash/tst_DashContent.qml+94−95 tests/qmltests/Dash/tst_GenericScopeView.qml+3−2 tests/qmltests/Panel/Indicators/tst_MenuItemFactory.qml+47
cmake/modules/QmlTest.cmake+2−2
@@ -135,7 +135,7 @@ macro(add_binary_qml_test CLASS_NAME LD_PATH DEPS)
135135 set(testCommand
136136 LD_LIBRARY_PATH=${LD_PATH}
137137 ${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
139139 -o -,txt)
140140
141141 add_qmltest_target(test${CLASS_NAME} "${testCommand}" FALSE TRUE)
@@ -151,7 +151,7 @@ macro(add_binary_qml_test CLASS_NAME LD_PATH DEPS)
151151 LD_LIBRARY_PATH=${LD_PATH}
152152 xvfb-run --server-args "-screen 0 1024x768x24" --auto-servernum
153153 ${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
155155 -o -,txt)
156156
157157 add_qmltest_target(xvfbtest${CLASS_NAME} "${xvfbtestCommand}" FALSE TRUE)
debian/changelog+58
@@ -1,3 +1,61 @@
1+unity8 (8.00+14.10.20140806.1-0ubuntu1) utopic; urgency=low
2+
3+ [ Michal Hruby ]
4+ * Work with the scopes-v4 branch + departments->navigation renaming
5+
6+ [ Michał Sawicz ]
7+ * Hardcode art shape size for click scope local and predefined
8+ categories While at it, drop the fillmode of cards
9+ * Use the correct API in PageHeader. (LP: #1353048)
10+ * Refactor dash activity indicator. (LP: #1351539)
11+
12+ [ Albert Astals ]
13+ * Dash Departments fixes Update maxHeight manually since it depends on
14+ the position of the item and its parents and it can't know when the
15+ binding has to be updated Make parent stuff non interactive when the
16+ department list is shown
17+ * PageHeader: when on search clip y-coordinates otherwise the
18+ background spills out when on search (LP: #1350398)
19+ * Dash: Implement OverlayColor support in Cards
20+ * Hardcode art shape size for click scope local and predefined
21+ categories While at it, drop the fillmode of cards
22+ * Make test_departments test more stable There's various
23+ DashDepartments on the dash, make sure we're working over the one
24+ that is on screen, otherwise clicks don't end up where they should
25+ * Work with the scopes-v4 branch + departments->navigation renaming
26+ * Fixes for dash as app Load i18n catalog Process command line options
27+ Add the posibility to have a mouse touch adaptor (LP: #1353351)
28+ * Implement the Expandable Preview Widget Now TextSummary is not
29+ expandable by itself anymore, you have to use it inside an
30+ Expandable to get the behaviour
31+ * Add test prefix to xml output, seems CI needs it
32+
33+ [ Antti Kaijanmäki ]
34+ * Indicators: Adds new ModemInfoItem to be used with indicator-network
35+ (LP: #1329204)
36+
37+ [ Michael Terry ]
38+ * When the edge demo is running, don't show the greeter if the screen
39+ is turned off. This avoids an odd interaction where parts of the
40+ greeter are disabled but the edge demo isn't visible until you slide
41+ the greeter away. (LP: #1283425)
42+ * Don't hardcode the phablet password in our testing script.
43+
44+ [ Ying-Chun Liu ]
45+ * Add divider dots.
46+
47+ [ Mirco Müller ]
48+ * Make sure the TextField of a snap-decision notification has the
49+ active focus upon creation, thus the osk shows up right away. (LP:
50+ #1346867)
51+
52+ [ Andrea Cimitan ]
53+ * Add touchdown effect to dash cards.
54+ * Import Ubuntu.Components for preview image gallery to pick up
55+ default flicking speeds.
56+
57+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 06 Aug 2014 19:40:05 +0000
58+
159unity8 (8.00+14.10.20140805-0ubuntu1) utopic; urgency=low
260
361 [ Michael Zanetti ]
debian/control+2−2
@@ -24,7 +24,7 @@ Build-Depends: cmake,
2424 libpulse-dev,
2525 libqmenumodel-dev (>= 0.2.8),
2626 libqt5xmlpatterns5-dev,
27− libunity-api-dev (>= 7.87),
27+ libunity-api-dev (>= 7.88),
2828 libusermetricsoutput1-dev,
2929 libxcb1-dev,
3030 pkg-config,
@@ -112,7 +112,7 @@ Depends: qtdeclarative5-ubuntu-thumbnailer0.1 | ubuntu-thumbnailer-impl,
112112 unity-application-impl-2,
113113 unity-notifications-impl-3,
114114 unity-plugin-scopes | unity-scopes-impl,
115− unity-scopes-impl-2,
115+ unity-scopes-impl-4,
116116 unity8-fake-env | unity-application-impl,
117117 ${misc:Depends},
118118Breaks: unity8 (<< 7.86),
plugins/Dash/CardCreator.js+26−12
@@ -71,19 +71,14 @@ var kArtShapeHolderCode = 'Item { \n\
7171 visible: image.status == Image.Ready; \n\
7272 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1; \n\
7373 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1; \n\
74− readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect; \n\
7574 Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; } \n\
76− onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings(); \n\
7775 Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); } \n\
7876 function updateWidthHeightBindings() { \n\
7977 if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) { \n\
8078 width = root.fixedArtShapeSize.width; \n\
8179 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\
8580 } 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\
8782 height = Qt.binding(function() { return !visible ? 0 : image.height }); \n\
8883 } \n\
8984 } \n\
@@ -92,8 +87,7 @@ var kArtShapeHolderCode = 'Item { \n\
9287 source: cardData && cardData["art"] || ""; \n\
9388 cache: true; \n\
9489 asynchronous: root.asynchronous; \n\
95− fillMode: components && components["art"]["fill-mode"] === "fit" ? Image.PreserveAspectFit: Image.PreserveAspectCrop; \n\
96− readonly property real aspect: implicitWidth / implicitHeight; \n\
90+ fillMode: Image.PreserveAspectCrop; \n\
9791 width: %2; \n\
9892 height: %3; \n\
9993 } \n\
@@ -114,7 +108,7 @@ var kOverlayLoaderCode = 'Loader { \n\
114108 sourceComponent: ShaderEffect { \n\
115109 id: overlay; \n\
116110 height: (fixedHeaderHeight > 0 ? fixedHeaderHeight : headerHeight) + units.gu(2); \n\
117− opacity: 0.6; \n\
111+ property color overlayColor: cardData && cardData["overlayColor"] || "#99000000"; \n\
118112 property var source: ShaderEffectSource { \n\
119113 id: shaderSource; \n\
120114 sourceItem: artShapeLoader.item; \n\
@@ -135,9 +129,10 @@ var kOverlayLoaderCode = 'Loader { \n\
135129 varying highp vec2 coord; \n\
136130 uniform sampler2D source; \n\
137131 uniform lowp float qt_Opacity; \n\
132+ uniform highp vec4 overlayColor; \n\
138133 void main() { \n\
139134 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\
141136 }"; \n\
142137 } \n\
143138 }\n';
@@ -257,6 +252,16 @@ var kTitleLabelCode = 'Label { \n\
257252 horizontalAlignment: root.headerAlignment; \n\
258253 }\n';
259254
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+
260265// %1 is used as anchors of subtitleLabel
261266// %2 is used as color of subtitleLabel
262267var kSubtitleLabelCode = 'Label { \n\
@@ -279,7 +284,7 @@ var kAttributesRowCode = 'CardAttributes { \n\
279284 objectName: "attributesRow"; \n\
280285 anchors { %1 } \n\
281286 color: %2; \n\
282− model: cardData && cardData["attributes"] || undefined; \n\
287+ model: cardData["attributes"]; \n\
283288 }\n';
284289
285290// %1 is used as top anchor of summary
@@ -569,6 +574,16 @@ function cardString(template, components) {
569574 code += kSummaryLabelCode.arg(summaryTopAnchor).arg(summaryTopMargin).arg(color);
570575 }
571576
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+
572587 if (hasSummary) {
573588 code += 'implicitHeight: summary.y + summary.height + (summary.text ? units.gu(1) : 0);\n';
574589 } else if (hasHeaderRow) {
@@ -593,7 +608,6 @@ function cardString(template, components) {
593608function createCardComponent(parent, template, components) {
594609 var imports = 'import QtQuick 2.2; \n\
595610 import Ubuntu.Components 0.1; \n\
596− import Ubuntu.Thumbnailer 0.1;\n\
597611 import Dash 0.1;\n';
598612 var card = cardString(template, components);
599613 var code = imports + 'Component {\n' + card + '}\n';
plugins/Dash/ScopeStyle.qml+11−8
@@ -38,14 +38,20 @@ QtObject {
3838 /// Color used for text and symbolic icons
3939 readonly property color foreground: "foreground-color" in style ? style["foreground-color"] : d.defaultDark
4040
41+ /// Luminance of the foreground color
42+ readonly property real foregroundLuminance: foreground ? luminance(foreground) : d.defaultForegroundLuminance
43+
4144 /// Color used for the overall background
4245 readonly property color background: "background-color" in style ? style["background-color"] : "transparent"
4346
47+ /// Luminance of the foreground color
48+ readonly property real backgroundLuminance: background ? luminance(background) : d.defaultBackgroundLuminance
49+
4450 /*! \brief Luminance threshold for switching between fore and background color
4551
4652 \note If background colour is not fully opaque, it's not taken into account.
4753 */
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
4955
5056 /*! \brief The lighter of foreground and background colors
5157
@@ -53,8 +59,8 @@ QtObject {
5359 and defaults to the theme-provided light color.
5460 */
5561 readonly property color light: {
56− if (background.a !== 1.0) return d.foregroundLuminance > d.defaultLightLuminance ? foreground : d.defaultLight;
57− return d.foregroundLuminance > d.backgroundLuminance ? foreground : background;
62+ if (background.a !== 1.0) return foregroundLuminance > d.defaultLightLuminance ? foreground : d.defaultLight;
63+ return foregroundLuminance > backgroundLuminance ? foreground : background;
5864 }
5965
6066 /*! \brief The darker of foreground and background colors
@@ -63,8 +69,8 @@ QtObject {
6369 and defaults to the theme-provided dark color.
6470 */
6571 readonly property color dark: {
66− if (background.a !== 1.0) return d.foregroundLuminance < d.defaultDarkLuminance ? foreground : d.defaultDark;
67− return d.foregroundLuminance < d.backgroundLuminance ? foreground : background;
72+ if (background.a !== 1.0) return foregroundLuminance < d.defaultDarkLuminance ? foreground : d.defaultDark;
73+ return foregroundLuminance < backgroundLuminance ? foreground : background;
6874 }
6975
7076 /// Source of the logo image for the header
@@ -78,9 +84,6 @@ QtObject {
7884
7985 //! @cond
8086 property var d: QtObject {
81− readonly property real foregroundLuminance: luminance(foreground)
82− readonly property real backgroundLuminance: luminance(background)
83−
8487 // FIXME: should be taken from the theme
8588 readonly property color defaultLight: "white"
8689 readonly property color defaultDark: "grey"
po/es.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-08-07 06:27+0000\n"
18−"X-Generator: Launchpad (build 17147)\n"
17+"X-Launchpad-Export-Date: 2014-08-08 07:07+0000\n"
18+"X-Generator: Launchpad (build 17156)\n"
1919
2020#: plugins/Unity/Launcher/launcheritem.cpp:43
2121#: plugins/Unity/Launcher/launcheritem.cpp:73
po/eu.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-08-07 06:27+0000\n"
18−"X-Generator: Launchpad (build 17147)\n"
17+"X-Launchpad-Export-Date: 2014-08-08 07:07+0000\n"
18+"X-Generator: Launchpad (build 17156)\n"
1919
2020#: plugins/Unity/Launcher/launcheritem.cpp:43
2121#: plugins/Unity/Launcher/launcheritem.cpp:73
po/hu.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-08-07 06:27+0000\n"
18−"X-Generator: Launchpad (build 17147)\n"
17+"X-Launchpad-Export-Date: 2014-08-08 07:07+0000\n"
18+"X-Generator: Launchpad (build 17156)\n"
1919
2020#: plugins/Unity/Launcher/launcheritem.cpp:43
2121#: plugins/Unity/Launcher/launcheritem.cpp:73
po/ja.po+7−7
@@ -8,14 +8,14 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2014-07-11 14:59+0200\n"
11−"PO-Revision-Date: 2014-08-06 15:19+0000\n"
12−"Last-Translator: Shushi Kurose <md81bird@hitaki.net>\n"
11+"PO-Revision-Date: 2014-08-08 06:18+0000\n"
12+"Last-Translator: Mitsuya Shibata <mty.shibata@gmail.com>\n"
1313"Language-Team: Japanese <ja@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-08-07 06:27+0000\n"
18−"X-Generator: Launchpad (build 17147)\n"
17+"X-Launchpad-Export-Date: 2014-08-08 07:07+0000\n"
18+"X-Generator: Launchpad (build 17156)\n"
1919
2020#: plugins/Unity/Launcher/launcheritem.cpp:43
2121#: plugins/Unity/Launcher/launcheritem.cpp:73
@@ -78,7 +78,7 @@ msgstr "緊急通報"
7878
7979#: qml/Components/Lockscreen.qml:231
8080msgid "OK"
81−msgstr ""
81+msgstr "OK"
8282
8383#: qml/Components/PassphraseLockscreen.qml:60
8484#, qt-format
@@ -99,7 +99,7 @@ msgstr ""
9999
100100#: qml/Components/SeeMore.qml:35
101101msgid "See more"
102−msgstr ""
102+msgstr "さらに表示する"
103103
104104#: qml/Components/SeeMore.qml:58 qml/Dash/GenericScopeView.qml:330
105105msgid "See less"
@@ -155,7 +155,7 @@ msgstr "音声入力を開始..."
155155
156156#: qml/Hud/Hud.qml:94
157157msgid "Speaking..."
158−msgstr ""
158+msgstr "入力中..."
159159
160160#: qml/Notifications/NotificationMenuItemFactory.qml:91
161161msgid "Show password"
po/pt_BR.po+7−7
@@ -8,23 +8,23 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2014-07-11 14:59+0200\n"
11−"PO-Revision-Date: 2014-08-04 18:33+0000\n"
12−"Last-Translator: Rafael Neri <Unknown>\n"
11+"PO-Revision-Date: 2014-08-07 12:34+0000\n"
12+"Last-Translator: Salomão Carneiro de Brito <salomaocar@gmail.com>\n"
1313"Language-Team: Brazilian Portuguese <pt_BR@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-08-05 06:45+0000\n"
18−"X-Generator: Launchpad (build 17147)\n"
17+"X-Launchpad-Export-Date: 2014-08-08 07:07+0000\n"
18+"X-Generator: Launchpad (build 17156)\n"
1919
2020#: plugins/Unity/Launcher/launcheritem.cpp:43
2121#: plugins/Unity/Launcher/launcheritem.cpp:73
2222msgid "Pin shortcut"
23−msgstr ""
23+msgstr "Fixar atalho"
2424
2525#: plugins/Unity/Launcher/launcheritem.cpp:73
2626msgid "Unpin shortcut"
27−msgstr ""
27+msgstr "Desafixar atalho"
2828
2929#: qml/Components/EdgeDemoOverlay.qml:151
3030msgid "Skip intro"
@@ -179,7 +179,7 @@ msgstr "Conferência"
179179
180180#: qml/Panel/Indicators/MenuItemFactory.qml:583
181181msgid "In queue…"
182−msgstr ""
182+msgstr "Em fila..."
183183
184184#: qml/Panel/Indicators/MenuItemFactory.qml:587
185185msgid "Downloading"
po/sl.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-08-07 06:27+0000\n"
18−"X-Generator: Launchpad (build 17147)\n"
17+"X-Launchpad-Export-Date: 2014-08-08 07:07+0000\n"
18+"X-Generator: Launchpad (build 17156)\n"
1919
2020#: plugins/Unity/Launcher/launcheritem.cpp:43
2121#: plugins/Unity/Launcher/launcheritem.cpp:73
qml/Components/EdgeDemo.qml+15−15
@@ -24,13 +24,13 @@ Item {
2424 property Item greeter
2525 property Item launcher
2626 property Item indicators
27− property Item underlay
27+ property Item stages
2828
2929 property bool launcherEnabled: true
30− property bool dashEnabled: true
30+ property bool stagesEnabled: true
3131 property bool panelEnabled: true
3232 property bool panelContentEnabled: true
33− property bool running: !launcherEnabled || !dashEnabled || !panelEnabled || !panelContentEnabled
33+ property bool running: !launcherEnabled || !stagesEnabled || !panelEnabled || !panelContentEnabled
3434
3535 property bool paused: false
3636
@@ -58,7 +58,7 @@ Item {
5858
5959 function stopDemo() {
6060 launcherEnabled = true
61− dashEnabled = true
61+ stagesEnabled = true
6262 panelEnabled = true
6363 panelContentEnabled = true
6464 if (d.rightEdgeDemo) d.rightEdgeDemo.destroy()
@@ -74,11 +74,11 @@ Item {
7474 }
7575
7676 launcherEnabled = false;
77− dashEnabled = false;
77+ stagesEnabled = false;
7878 panelEnabled = false;
7979 panelContentEnabled = false;
8080
81− // Begin with either greeter or dash, depending on which is visible
81+ // Begin with either greeter or top, depending on which is visible
8282 if (greeter && greeter.shown) {
8383 startRightEdgeDemo()
8484 } else {
@@ -138,12 +138,12 @@ Item {
138138
139139 function startTopEdgeDemo() {
140140 demo.panelEnabled = true;
141− if (demo.dash && demo.underlay) {
142− d.topEdgeDemo = d.overlay.createObject(demo.underlay, {
141+ if (demo.stages) {
142+ d.topEdgeDemo = d.overlay.createObject(demo.stages, {
143143 "edge": "top",
144144 "title": i18n.tr("Top edge"),
145145 "text": i18n.tr("Try swiping from the top edge to access the indicators"),
146− "anchors.fill": demo.underlay,
146+ "anchors.fill": demo.stages,
147147 });
148148 }
149149 if (d.topEdgeDemo) {
@@ -192,12 +192,12 @@ Item {
192192 function startLeftEdgeDemo() {
193193 demo.panelEnabled = false;
194194 demo.launcherEnabled = true;
195− if (demo.underlay) {
196− d.leftEdgeDemo = d.overlay.createObject(demo.underlay, {
195+ if (demo.stages) {
196+ d.leftEdgeDemo = d.overlay.createObject(demo.stages, {
197197 "edge": "left",
198198 "title": i18n.tr("Left edge"),
199199 "text": i18n.tr("Swipe from the left to reveal the launcher for quick access to apps"),
200− "anchors.fill": demo.underlay,
200+ "anchors.fill": demo.stages,
201201 });
202202 }
203203 if (d.leftEdgeDemo) {
@@ -220,12 +220,12 @@ Item {
220220
221221 function startFinalEdgeDemo() {
222222 demo.launcherEnabled = false;
223− if (demo.underlay) {
224− d.finalEdgeDemo = d.overlay.createObject(demo.underlay, {
223+ if (demo.stages) {
224+ d.finalEdgeDemo = d.overlay.createObject(demo.stages, {
225225 "edge": "none",
226226 "title": i18n.tr("Well done"),
227227 "text": i18n.tr("You have now mastered the edge gestures and can start using the phone<br><br>Tap on the screen to start"),
228− "anchors.fill": demo.underlay,
228+ "anchors.fill": demo.stages,
229229 "showSkip": false,
230230 });
231231 }
qml/Components/PageHeader.qml+25−16
@@ -32,9 +32,10 @@ Item {
3232 property bool searchEntryEnabled: false
3333 property ListModel searchHistory: SearchHistoryModel
3434 property alias searchQuery: searchTextField.text
35− property bool searchInProgress: false
3635
3736 property alias bottomItem: bottomContainer.children
37+ property int paginationCount: 0
38+ property int paginationIndex: -1
3839
3940 // TODO We should use foreground for the icons
4041 // of the toolbar but unfortunately Action does not have
@@ -125,7 +126,7 @@ Item {
125126 Flickable {
126127 id: headerContainer
127128 objectName: "headerContainer"
128− clip: openSearchAnimation.running
129+ clip: contentY < height
129130 anchors { left: parent.left; top: parent.top; right: parent.right }
130131 height: units.gu(6.5)
131132 contentHeight: headersColumn.height
@@ -169,6 +170,7 @@ Item {
169170 property var styledItem: searchHeader
170171 property string title
171172 property var config: PageHeadConfiguration {
173+ foregroundColor: root.scopeStyle ? root.scopeStyle.headerForeground : "grey"
172174 backAction: Action {
173175 iconName: "back"
174176 onTriggered: {
@@ -200,25 +202,13 @@ Item {
200202 anchors.fill: parent
201203 anchors.margins: units.gu(.75)
202204 source: "image://theme/clear"
203− opacity: searchTextField.text.length > 0 && !searchActivityIndicator.running
205+ opacity: searchTextField.text.length > 0
204206 visible: opacity > 0
205207 Behavior on opacity {
206208 UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration }
207209 }
208210 }
209211
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−
222212 onClicked: {
223213 root.resetSearch(true);
224214 root.openSearchHistory();
@@ -247,10 +237,10 @@ Item {
247237 contentHeight: height
248238 opacity: headerContainer.clip || !headerContainer.showSearch ? 1 : 0 // setting visible false cause column to relayout
249239 separatorSource: ""
250− textColor: root.scopeStyle ? root.scopeStyle.headerForeground : "grey"
251240 property var styledItem: header
252241 property string title: root.title
253242 property var config: PageHeadConfiguration {
243+ foregroundColor: root.scopeStyle ? root.scopeStyle.headerForeground : "grey"
254244 backAction: Action {
255245 iconName: "back"
256246 visible: root.showBackButton
@@ -294,6 +284,25 @@ Item {
294284 }
295285 }
296286
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+
297306 Component {
298307 id: popoverComponent
299308 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 {
126126 type:real \brief Height of the card's header.
127127 */
128128 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
130130
131131 /*!
132132 \brief Desired alignment of header components.
qml/Dash/Dash.qml+84−11
@@ -14,7 +14,7 @@
1414 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1515 */
1616
17−import QtQuick 2.0
17+import QtQuick 2.2
1818import Ubuntu.Components 0.1
1919import Unity 0.2
2020import Utils 0.1
@@ -38,7 +38,13 @@ Showable {
3838 }
3939
4040 function setCurrentScope(scopeId, animate, reset) {
41− 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+ }
4248
4349 if (scopeIndex == -1) {
4450 console.warn("No match for scope with id: %1".arg(scopeId))
@@ -63,15 +69,16 @@ Showable {
6369 }
6470 }
6571
66− SortFilterProxyModel {
67− id: filteredScopes
68− model: Scopes {
69− id: scopes
70− }
71− dynamicSortFilter: true
72+ Scopes {
73+ id: scopes
74+ }
7275
73− filterRole: Scopes.RoleVisible
74− filterRegExp: RegExp("^true$")
76+ Image {
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
7582 }
7683
7784 DashContent {
@@ -79,7 +86,6 @@ Showable {
7986 objectName: "dashContent"
8087 width: parent.width
8188 height: parent.height
82− model: filteredScopes
8389 scopes: scopes
8490 visible: x != -width
8591 onGotoScope: {
@@ -134,4 +140,71 @@ Showable {
134140 }
135141 }
136142 }
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+
137210}
qml/Dash/DashApplication.qml+7
@@ -16,6 +16,7 @@
1616
1717import QtQuick 2.2
1818import Ubuntu.Components 1.0
19+import Ubuntu.Thumbnailer 0.1 // Register support for image://thumbnailer/ and image://albumart/
1920
2021MainView {
2122 width: units.gu(40)
@@ -23,6 +24,12 @@ MainView {
2324
2425 useDeprecatedToolbar: false
2526
27+ Binding {
28+ target: i18n
29+ property: "domain"
30+ value: "unity8"
31+ }
32+
2633 Dash {
2734 anchors.fill: parent
2835 }
qml/Dash/DashContent.qml+7−4
@@ -23,9 +23,10 @@ import "../Components"
2323Item {
2424 id: dashContent
2525
26− property var model: null
27− property var scopes: null
26+ property alias scopes: dashContentList.model
2827 readonly property alias currentIndex: dashContentList.currentIndex
28+ readonly property bool processing: dashContentList.currentItem && dashContentList.currentItem.item
29+ && dashContentList.currentItem.item.processing || false
2930
3031 signal scopeLoaded(string scopeId)
3132 signal gotoScope(string scopeId)
@@ -89,10 +90,9 @@ Item {
8990 id: dashContentList
9091 objectName: "dashContentList"
9192
92− interactive: dashContent.scopes.loaded && currentItem && !currentItem.moving
93+ interactive: dashContent.scopes.loaded && currentItem && !currentItem.moving && !currentItem.navigationShown
9394
9495 anchors.fill: parent
95− model: dashContent.model
9696 orientation: ListView.Horizontal
9797 boundsBehavior: Flickable.DragAndOvershootBounds
9898 flickDeceleration: units.gu(625)
@@ -130,6 +130,7 @@ Item {
130130 objectName: scope.id + " loader"
131131
132132 readonly property bool moving: item ? item.moving : false
133+ readonly property bool navigationShown: item ? item.navigationShown : false
133134 readonly property var categoryView: item ? item.categoryView : null
134135 readonly property var theScope: scope
135136
@@ -143,6 +144,8 @@ Item {
143144 item.scope = Qt.binding(function() { return scope })
144145 item.isCurrent = Qt.binding(function() { return visible && ListView.isCurrentItem })
145146 dashContent.scopeLoaded(item.scope.id)
147+ item.paginationCount = Qt.binding(function() { return dashContentList.count } )
148+ item.paginationIndex = Qt.binding(function() { return dashContentList.currentIndex } )
146149 }
147150 Connections {
148151 target: isCurrent ? scope : null
qml/Dash/DashDepartments.qml → qml/Dash/DashNavigation.qmlrenamed+50−43
@@ -15,17 +15,17 @@
1515 */
1616
1717import QtQuick 2.2
18−import Ubuntu.Components 0.1
18+import Ubuntu.Components 1.1
1919
2020AbstractButton {
2121 id: root
22− objectName: "dashDepartments"
22+ objectName: "dashNavigation"
2323
2424 property var scope: null
2525
2626 property bool showList: false
2727
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
2929
3030 property alias windowWidth: blackRect.width
3131 property alias windowHeight: blackRect.height
@@ -34,20 +34,21 @@ AbstractButton {
3434 // Are we drilling down the tree or up?
3535 property bool isGoingBack: false
3636
37− visible: root.currentDepartment != null
37+ visible: root.currentNavigation != null
3838
3939 height: visible ? units.gu(5) : 0
4040
4141 onClicked: {
42+ navigationListView.updateMaxHeight();
4243 root.showList = !root.showList;
4344 }
4445
4546 Rectangle {
4647 id: blackRect
4748 color: "black"
48− opacity: departmentListView.currentItem && departmentListView.currentItem.visible ? 0.3 : 0
49+ opacity: navigationListView.currentItem && navigationListView.currentItem.visible ? 0.3 : 0
4950 Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
50− anchors.top: departmentListView.top
51+ anchors.top: navigationListView.top
5152 anchors.right: parent.right
5253 visible: opacity != 0
5354 }
@@ -78,7 +79,7 @@ AbstractButton {
7879 anchors.fill: parent
7980 anchors.margins: units.gu(2)
8081 verticalAlignment: Text.AlignVCenter
81− text: root.currentDepartment ? root.currentDepartment.label : ""
82+ text: root.currentNavigation ? root.currentNavigation.label : ""
8283 color: root.scopeStyle ? root.scopeStyle.foreground : "grey"
8384 }
8485
@@ -92,18 +93,18 @@ AbstractButton {
9293 color: root.scopeStyle ? root.scopeStyle.foreground : "grey"
9394 }
9495
95− // departmentListView is outside root
96+ // navigationListView is outside root
9697 ListView {
97− id: departmentListView
98− objectName: "departmentListView"
98+ id: navigationListView
99+ objectName: "navigationListView"
99100 orientation: ListView.Horizontal
100101 interactive: false
101102 clip: root.width != windowWidth
102103 model: ListModel {
103− id: departmentModel
104+ id: navigationModel
104105 // We have two roles
105− // departmentId: the department id of the department the list represents
106− // nullifyDepartment: overrides departmentId to be null
106+ // navigationId: the navigation id of the navigation the list represents
107+ // nullifyNavigation: overrides navigationId to be null
107108 // This is used to "clear" the delegate when going "right" on the tree
108109 }
109110 anchors {
@@ -111,7 +112,12 @@ AbstractButton {
111112 right: parent.right
112113 top: root.bottom
113114 }
114− readonly property int maxHeight: (windowHeight - mapToItem(null, root.x, root.y).y) - units.gu(8)
115+ property int maxHeight: -1
116+ Component.onCompleted: updateMaxHeight();
117+ function updateMaxHeight()
118+ {
119+ maxHeight = (windowHeight - mapToItem(null, 0, 0).y) - units.gu(8);
120+ }
115121 property int prevHeight: maxHeight
116122 height: currentItem ? currentItem.height : maxHeight
117123 onHeightChanged: {
@@ -120,83 +126,84 @@ AbstractButton {
120126 }
121127 }
122128 highlightMoveDuration: UbuntuAnimation.FastDuration
123− delegate: DashDepartmentsList {
124− objectName: "department" + index
129+ delegate: DashNavigationList {
130+ objectName: "navigation" + index
125131 visible: height != 0
126− width: departmentListView.width
132+ width: navigationListView.width
127133 scopeStyle: root.scopeStyle
128134 property real desiredHeight: {
129135 if (root.showList) {
130− if (department && department.loaded && x == departmentListView.contentX)
136+ if (navigation && navigation.loaded && x == navigationListView.contentX)
131137 {
132− return Math.min(implicitHeight, departmentListView.maxHeight);
138+ navigationListView.updateMaxHeight();
139+ return Math.min(implicitHeight, navigationListView.maxHeight);
133140 } else {
134− return departmentListView.prevHeight;
141+ return navigationListView.prevHeight;
135142 }
136143 } else {
137144 return 0;
138145 }
139146 }
140147 height: desiredHeight
141− department: (nullifyDepartment || !scope) ? null : scope.getDepartment(departmentId)
142− currentDepartment: root.currentDepartment
143− onEnterDepartment: {
144− scope.loadDepartment(newDepartmentId);
148+ navigation: (nullifyNavigation || !scope) ? null : scope.getNavigation(navigationId)
149+ currentNavigation: root.currentNavigation
150+ onEnterNavigation: {
151+ scope.setNavigationState(newNavigationId, false);
145152 // We only need to add a new item to the model
146153 // if we have children, otherwise just load it
147154 if (hasChildren) {
148155 isGoingBack = false;
149− departmentModel.append({"departmentId": newDepartmentId, "nullifyDepartment": false});
150− departmentListView.currentIndex++;
156+ navigationModel.append({"navigationId": newNavigationId, "nullifyNavigation": false});
157+ navigationListView.currentIndex++;
151158 } else {
152159 showList = false;
153160 }
154161 }
155162 onGoBackToParentClicked: {
156− scope.loadDepartment(department.parentDepartmentId);
163+ scope.setNavigationState(navigation.parentNavigationId, false);
157164 isGoingBack = true;
158− departmentModel.setProperty(departmentListView.currentIndex - 1, "nullifyDepartment", false);
159− departmentListView.currentIndex--;
165+ navigationModel.setProperty(navigationListView.currentIndex - 1, "nullifyNavigation", false);
166+ navigationListView.currentIndex--;
160167 }
161− onAllDepartmentClicked: {
168+ onAllNavigationClicked: {
162169 showList = false;
163− if (root.currentDepartment.parentDepartmentId == department.departmentId) {
170+ if (root.currentNavigation.parentNavigationId == navigation.navigationId) {
164171 // For leaves we have to go to the parent too
165− scope.loadDepartment(root.currentDepartment.parentDepartmentId);
172+ scope.setNavigationState(root.currentNavigation.parentNavigationId, false);
166173 }
167174 }
168175 }
169176 onContentXChanged: {
170− if (contentX == width * departmentListView.currentIndex) {
177+ if (contentX == width * navigationListView.currentIndex) {
171178 if (isGoingBack) {
172− departmentModel.remove(departmentListView.currentIndex + 1);
179+ navigationModel.remove(navigationListView.currentIndex + 1);
173180 } else {
174− departmentModel.setProperty(departmentListView.currentIndex - 1, "nullifyDepartment", true);
181+ navigationModel.setProperty(navigationListView.currentIndex - 1, "nullifyNavigation", true);
175182 }
176183 }
177184 }
178185 }
179186
180187 InverseMouseArea {
181− anchors.fill: departmentListView
188+ anchors.fill: navigationListView
182189 enabled: root.showList
183190 onClicked: root.showList = false
184191 }
185192
186193 onScopeChanged: {
187− departmentModel.clear();
188− if (scope && scope.hasDepartments) {
189− departmentModel.append({"departmentId": scope.currentDepartmentId, "nullifyDepartment": false});
194+ navigationModel.clear();
195+ if (scope && scope.hasNavigation) {
196+ navigationModel.append({"navigationId": scope.currentNavigationId, "nullifyNavigation": false});
190197 }
191198 }
192199
193200 Connections {
194201 target: scope
195− onHasDepartmentsChanged: {
196− if (scope.hasDepartments) {
197− departmentModel.append({"departmentId": scope.currentDepartmentId, "nullifyDepartment": false});
202+ onHasNavigationChanged: {
203+ if (scope.hasNavigation) {
204+ navigationModel.append({"navigationId": scope.currentNavigationId, "nullifyNavigation": false});
198205 } else {
199− departmentModel.clear();
206+ navigationModel.clear();
200207 }
201208 }
202209 }
qml/Dash/DashDepartmentsList.qml → qml/Dash/DashNavigationList.qmlrenamed+14−18
@@ -15,16 +15,16 @@
1515 */
1616
1717import QtQuick 2.2
18−import Ubuntu.Components 0.1
18+import Ubuntu.Components 1.1
1919
2020Item {
2121 id: root
22− property var department: null
23− property var currentDepartment: null
22+ property var navigation: null
23+ property var currentNavigation: null
2424 property var scopeStyle: null
25− signal enterDepartment(var newDepartmentId, bool hasChildren)
25+ signal enterNavigation(var newNavigationId, bool hasChildren)
2626 signal goBackToParentClicked()
27− signal allDepartmentClicked()
27+ signal allNavigationClicked()
2828
2929 readonly property int itemHeight: units.gu(5)
3030 readonly property color foregroundColor: root.scopeStyle ? root.scopeStyle.foreground : "grey"
@@ -35,11 +35,6 @@ Item {
3535 anchors.fill: parent
3636 }
3737
38− ActivityIndicator {
39− id: loadingIndicator
40− anchors.centerIn: parent
41− running: !(department && department.loaded)
42− }
4338 clip: true
4439
4540 Behavior on height {
@@ -54,6 +49,7 @@ Item {
5449
5550 anchors.fill: parent
5651
52+ flickableDirection: Flickable.VerticalFlick
5753 contentHeight: column.height
5854 contentWidth: width
5955
@@ -68,7 +64,7 @@ Item {
6864 id: backButton
6965 objectName: "backButton"
7066 width: parent.width
71− visible: department && !department.isRoot || false
67+ visible: navigation && !navigation.isRoot || false
7268 height: itemHeight
7369
7470 onClicked: root.goBackToParentClicked();
@@ -92,7 +88,7 @@ Item {
9288 left: backImage.right
9389 leftMargin: units.gu(0.5)
9490 }
95− text: department ? department.parentLabel : ""
91+ text: navigation ? navigation.parentLabel : ""
9692 color: root.foregroundColor
9793 }
9894
@@ -114,7 +110,7 @@ Item {
114110 id: allButton
115111 objectName: "allButton"
116112 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
118114 height: itemHeight
119115
120116 Label {
@@ -123,7 +119,7 @@ Item {
123119 left: parent.left
124120 leftMargin: units.gu(2)
125121 }
126− text: department ? (department.allLabel != "" ? department.allLabel : department.label) : ""
122+ text: navigation ? (navigation.allLabel != "" ? navigation.allLabel : navigation.label) : ""
127123 font.bold: true
128124 color: root.foregroundColor
129125 }
@@ -141,18 +137,18 @@ Item {
141137 height: units.dp(1)
142138 }
143139
144− onClicked: root.allDepartmentClicked();
140+ onClicked: root.allNavigationClicked();
145141 }
146142
147143 Repeater {
148− model: department && department.loaded ? department : null
144+ model: navigation && navigation.loaded ? navigation : null
149145 clip: true
150146 delegate: AbstractButton {
151147 objectName: root.objectName + "child" + index
152148 height: root.itemHeight
153149 width: root.width
154150
155− onClicked: root.enterDepartment(departmentId, hasChildren)
151+ onClicked: root.enterNavigation(navigationId, hasChildren)
156152
157153 Label {
158154 anchors {
@@ -188,7 +184,7 @@ Item {
188184 color: root.foregroundColor
189185 opacity: 0.1
190186 height: units.dp(1)
191− visible: index != department.count - 1
187+ visible: index != navigation.count - 1
192188 }
193189 }
194190 }
qml/Dash/GenericScopeView.qml+12−12
@@ -25,6 +25,7 @@ import "../Components/ListItems" as ListItems
2525FocusScope {
2626 id: scopeView
2727
28+ readonly property alias navigationShown: dashNavigation.showList
2829 property var scope: null
2930 property SortFilterProxyModel categories: categoryFilter
3031 property bool isCurrent: false
@@ -32,22 +33,16 @@ FocusScope {
3233 property bool hasBackAction: false
3334 property bool enableHeightBehaviorOnNextCreation: false
3435 property var categoryView: categoryView
36+ property alias paginationCount: pageHeader.paginationCount
37+ property alias paginationIndex: pageHeader.paginationIndex
3538
3639 property var scopeStyle: ScopeStyle {
3740 style: scope ? scope.customizations : {}
3841 }
3942
40− signal backClicked()
41−
42− onScopeChanged: {
43− if (scope) {
44− scope.activateApplication.connect(activateApp);
45− }
46− }
43+ readonly property bool processing: scope ? scope.searchInProgress || previewListView.processing : false
4744
48− function activateApp(appId) {
49− Qt.openUrlExternally(appId);
50− }
45+ signal backClicked()
5146
5247 function positionAtBeginning() {
5348 categoryView.positionAtBeginning()
@@ -119,6 +114,7 @@ FocusScope {
119114 model: scopeView.categories
120115 forceNoClip: previewListView.open
121116 pixelAligned: true
117+ interactive: !dashNavigation.showList
122118
123119 property string expandedCategoryId: ""
124120
@@ -211,6 +207,10 @@ FocusScope {
211207 baseItem.expand(shouldExpand, false /*animate*/);
212208 }
213209 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+ }
214214 item.cardTool = cardTool;
215215 }
216216
@@ -387,10 +387,10 @@ FocusScope {
387387 title: scopeView.scope ? scopeView.scope.name : ""
388388 showBackButton: scopeView.hasBackAction
389389 searchEntryEnabled: true
390− searchInProgress: scopeView.scope ? scopeView.scope.searchInProgress : false
391390 scopeStyle: scopeView.scopeStyle
392391
393− bottomItem: DashDepartments {
392+ bottomItem: DashNavigation {
393+ id: dashNavigation
394394 scope: scopeView.scope
395395 width: parent.width <= units.gu(60) ? parent.width : units.gu(40)
396396 anchors.right: parent.right
qml/Dash/PreviewListView.qml+23−27
@@ -32,6 +32,9 @@ Item {
3232 property alias currentItem: previewListView.currentItem
3333 property alias count: previewListView.count
3434
35+ readonly property bool processing: currentItem && (!currentItem.previewModel.loaded
36+ || currentItem.previewModel.processingAction)
37+
3538 PageHeader {
3639 id: header
3740 objectName: "pageHeader"
@@ -83,39 +86,32 @@ Item {
8386 }
8487 }
8588
86− delegate: Item {
87− objectName: "previewItem" + index
89+ delegate: Previews.Preview {
90+ id: preview
91+ objectName: "preview" + index
8892 height: previewListView.height
8993 width: previewListView.width
9094
91− readonly property bool ready: preview.previewModel.loaded
92−
93− Previews.Preview {
94− id: preview
95− objectName: "preview" + index
96− anchors.fill: parent
95+ isCurrent: ListView.isCurrentItem
9796
98− isCurrent: parent.ListView.isCurrentItem
99−
100− previewModel: {
101− var previewStack = root.scope.preview(result);
102− return previewStack.getPreviewModel(0);
103− }
104− scopeStyle: root.scopeStyle
97+ previewModel: {
98+ var previewStack = root.scope.preview(result);
99+ return previewStack.getPreviewModel(0);
105100 }
101+ scopeStyle: root.scopeStyle
102+ }
103+ }
106104
107− MouseArea {
108− id: processingMouseArea
109− objectName: "processingMouseArea"
110− anchors.fill: parent
111− enabled: !preview.previewModel.loaded || preview.previewModel.processingAction
112−
113− ActivityIndicator {
114− anchors.centerIn: parent
115− visible: root.open && parent.enabled
116− running: visible
117− }
118− }
105+ MouseArea {
106+ id: processingMouseArea
107+ objectName: "processingMouseArea"
108+ anchors {
109+ left: parent.left
110+ right: parent.right
111+ top: pageHeader.bottom
112+ bottom: parent.bottom
119113 }
114+
115+ enabled: root.processing
120116 }
121117}
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 @@
1515 */
1616
1717import QtQuick 2.0
18+import Ubuntu.Components 1.1
1819import "../../Components"
1920
2021/*! This preview widget shows a horizontal list of images.
qml/Dash/Previews/PreviewTextSummary.qml+3−16
@@ -23,7 +23,7 @@ import "../../Components"
2323 This widget shows text contained in widgetData["text"]
2424 along with a title that comes from widgetData["title"].
2525
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.
2727 */
2828
2929PreviewWidget {
@@ -50,14 +50,14 @@ PreviewWidget {
5050 id: textLabel
5151 objectName: "textLabel"
5252
53− readonly property int maximumCollapsedLineCount: 7
53+ readonly property int maximumCollapsedLineCount: 3
5454
5555 anchors {
5656 left: parent.left
5757 right: parent.right
5858 top: titleLabel.visible ? titleLabel.bottom : parent.top
5959 }
60− height: (!seeMore.visible || seeMore.more) ? contentHeight : contentHeight / lineCount * (maximumCollapsedLineCount - 2)
60+ height: (lineCount <= maximumCollapsedLineCount || root.expanded) ? contentHeight : contentHeight / lineCount * maximumCollapsedLineCount
6161 clip: true
6262 fontSize: "small"
6363 lineHeight: 1.2
@@ -70,17 +70,4 @@ PreviewWidget {
7070 UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration }
7171 }
7272 }
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− }
8673}
qml/Dash/Previews/PreviewWidget.qml+3
@@ -31,6 +31,9 @@ Item {
3131 //! The ScopeStyle component.
3232 property var scopeStyle: null
3333
34+ //! Should the widget show in expanded mode (For those that support it)
35+ property bool expanded: true
36+
3437 /*! \brief This signal should be emitted when a preview action was triggered.
3538 *
3639 * \param widgetId, actionId Respective identifiers from widgetData.
qml/Dash/Previews/PreviewWidgetFactory.qml+5
@@ -34,6 +34,9 @@ Loader {
3434 //! The ScopeStyle component.
3535 property var scopeStyle: null
3636
37+ //! Should the widget show in expanded mode (For those that support it)
38+ property bool expanded: true
39+
3740 //! Set to true if the parent preview is displayed.
3841 property bool isCurrentPreview: false
3942
@@ -49,6 +52,7 @@ Loader {
4952 switch (widgetType) {
5053 case "actions": return "PreviewActions.qml";
5154 case "audio": return "PreviewAudioPlayback.qml";
55+ case "expandable": return "PreviewExpandable.qml";
5256 case "gallery": return "PreviewImageGallery.qml";
5357 case "header": return "PreviewHeader.qml";
5458 case "image": return "PreviewZoomableImage.qml";
@@ -67,6 +71,7 @@ Loader {
6771 item.widgetId = Qt.binding(function() { return root.widgetId } )
6872 item.widgetData = Qt.binding(function() { return root.widgetData } )
6973 item.isCurrentPreview = Qt.binding(function() { return root.isCurrentPreview } )
74+ item.expanded = Qt.binding(function() { return root.expanded } )
7075 if (item.hasOwnProperty("scopeStyle")) item.scopeStyle = root.scopeStyle;
7176 }
7277
qml/Greeter/Greeter.qml+1−1
@@ -70,7 +70,7 @@ Showable {
7070 DraggingArea {
7171 id: dragHandle
7272 anchors.fill: parent
73− enabled: (greeter.narrowMode || !greeter.locked) && greeter.enabled
73+ enabled: (greeter.narrowMode || !greeter.locked) && greeter.enabled && greeter.shown
7474 orientation: Qt.Horizontal
7575 propagateComposedEvents: true
7676
qml/Notifications/NotificationMenuItemFactory.qml+3
@@ -76,6 +76,9 @@ Loader {
7676 }
7777 echoMode: checkBox.checked ? TextInput.Normal : TextInput.Password
7878 height: units.gu(5)
79+ Component.onCompleted: {
80+ forceActiveFocus();
81+ }
7982 onTextChanged: {
8083 menuModel.changeState(menuIndex, text);
8184 }
qml/Panel/Indicators/MenuItemFactory.qml+74
@@ -57,6 +57,7 @@ Item {
5757
5858 "unity.widgets.systemsettings.tablet.wifisection" : wifiSection,
5959 "unity.widgets.systemsettings.tablet.accesspoint" : accessPoint,
60+ "com.canonical.indicator.network.modeminfoitem" : modeminfoitem,
6061 }
6162
6263 function getExtendedProperty(object, propertyName, defaultValue) {
@@ -374,6 +375,79 @@ Item {
374375 }
375376 }
376377
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+
377451 Component {
378452 id: messageItem
379453
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 @@
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
1919import Ubuntu.Components.Popups 0.1
20+import Ubuntu.Thumbnailer 0.1 // Register support for image://thumbnailer/ and image://albumart/
2021import Utils 0.1
2122import Unity 0.2
2223import "Components"
@@ -45,16 +46,6 @@ Rectangle {
4546 signal searchClicked
4647 }
4748
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− }
5849
5950 Rectangle {
6051 anchors.fill: dashContent
@@ -72,8 +63,8 @@ Rectangle {
7263 DashContent {
7364 id: dashContent
7465
75− model: filteredScopes
7666 property var scope: scopes.getScope(currentIndex)
67+ scopes: Scopes { }
7768
7869 anchors {
7970 top: parent.top
qml/Shell.qml+4−23
@@ -112,25 +112,6 @@ Item {
112112 }
113113 }
114114
115− Item {
116− id: underlay
117− objectName: "underlay"
118− anchors.fill: parent
119−
120− // Whether the underlay is fully covered by opaque UI elements.
121− property bool fullyCovered: (panel.indicators.fullyOpened && shell.width <= panel.indicatorsMenuWidth)
122− || stages.fullyShown || greeterWrapper.fullyShown
123− visible: !fullyCovered
124−
125− Image {
126− anchors.fill: underlay
127− source: shell.width > shell.height ? "Dash/graphics/paper_landscape.png" : "Dash/graphics/paper_portrait.png"
128− fillMode: Image.PreserveAspectCrop
129− horizontalAlignment: Image.AlignRight
130− verticalAlignment: Image.AlignTop
131− }
132− }
133−
134115 Item {
135116 id: stages
136117 objectName: "stages"
@@ -186,12 +167,12 @@ Item {
186167 Binding {
187168 target: applicationsDisplayLoader.item
188169 property: "interactive"
189− value: !greeter.shown && !lockscreen.shown && panel.indicators.fullyClosed && launcher.progress == 0
170+ value: edgeDemo.stagesEnabled && !greeter.shown && !lockscreen.shown && panel.indicators.fullyClosed && launcher.progress == 0
190171 }
191172 Binding {
192173 target: applicationsDisplayLoader.item
193174 property: "spreadEnabled"
194− value: greeter.fakeActiveForApp === "" // to support emergency dialer hack
175+ value: edgeDemo.stagesEnabled && greeter.fakeActiveForApp === "" // to support emergency dialer hack
195176 }
196177 Binding {
197178 target: applicationsDisplayLoader.item
@@ -400,7 +381,7 @@ Item {
400381 onDisplayPowerStateChange: {
401382 // We ignore any display-off signals when the proximity sensor
402383 // is active. This usually indicates something like a phone call.
403− if (status == Powerd.Off && reason != Powerd.Proximity) {
384+ if (status == Powerd.Off && reason != Powerd.Proximity && !edgeDemo.running) {
404385 greeter.showNow();
405386 }
406387
@@ -580,7 +561,7 @@ Item {
580561 greeter: greeter
581562 launcher: launcher
582563 indicators: panel.indicators
583− underlay: underlay
564+ stages: stages
584565 }
585566
586567 Connections {
run_on_device.sh+1−3
@@ -2,7 +2,6 @@
22CODE_DIR=shell
33USER=phablet
44USER_ID=32011
5−PASSWORD=phablet
65PACKAGE=unity8
76BINARY=unity8
87TARGET_IP=${TARGET_IP-127.0.0.1}
@@ -13,7 +12,6 @@ SETUP=false
1312GDB=false
1413PINLOCK=false
1514KEYLOCK=false
16−SUDO="echo $PASSWORD | sudo -S"
1715NUM_JOBS='$(( `grep -c ^processor /proc/cpuinfo` + 1 ))'
1816FLIPPED=false
1917CHROOT_PREFIX="/data/ubuntu"
@@ -76,7 +74,7 @@ setup_adb_forwarding() {
7674
7775install_dependencies() {
7876 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
8078}
8179
8280sync_code() {
src/Dash/CMakeLists.txt+1
@@ -1,5 +1,6 @@
11set(DASH_SRCS
22 main.cpp
3+ ../MouseTouchAdaptor.cpp
34)
45
56add_executable(unity8-dash ${DASH_SRCS})
src/Dash/main.cpp+26−4
@@ -24,8 +24,10 @@
2424#include <QDebug>
2525#include <QCommandLineParser>
2626#include <QLibrary>
27+#include <libintl.h>
2728
2829#include <paths.h>
30+#include "../MouseTouchAdaptor.h"
2931
3032int main(int argc, const char *argv[])
3133{
@@ -35,11 +37,21 @@ int main(int argc, const char *argv[])
3537 parser.setApplicationDescription("Description: Unity 8 Shell Dash");
3638 parser.addHelpOption();
3739
38− QCommandLineOption testabilityOption("testability",
39− "Load the testability driver (Alternatively export QT_LOAD_TESTABILITY");
40− parser.addOption(testabilityOption);
40+ QCommandLineOption mousetouchOption("mousetouch",
41+ "Allow the mouse to provide touch input");
42+ parser.addOption(mousetouchOption);
4143
42− if (parser.isSet(testabilityOption) || getenv("QT_LOAD_TESTABILITY")) {
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")) {
4355 QLibrary testLib(QLatin1String("qttestability"));
4456 if (testLib.load()) {
4557 typedef void (*TasInitialize)(void);
@@ -54,10 +66,20 @@ int main(int argc, const char *argv[])
5466 }
5567 }
5668
69+ bindtextdomain("unity8", translationDirectory().toUtf8().data());
70+
5771 QQuickView* view = new QQuickView();
5872 view->setResizeMode(QQuickView::SizeRootObjectToView);
5973 view->setTitle("Unity Dash");
6074
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+
6183 QUrl source(::qmlDirectory()+"Dash/DashApplication.qml");
6284 prependImportPaths(view->engine(), ::overrideImportPaths());
6385 appendImportPaths(view->engine(), ::fallbackImportPaths());
tests/autopilot/unity8/shell/emulators/dash.py+1−1
@@ -150,7 +150,7 @@ class Dash(emulators.UnityEmulatorBase):
150150 headerContainer.contentY.wait_for(0)
151151 search_text_field = self._get_search_text_field()
152152 search_text_field.write(query)
153− current_header.select_single(objectName="searchIndicator").running.wait_for(False)
153+ self.select_single(objectName="processingIndicator").visible.wait_for(False)
154154
155155 def _get_search_text_field(self):
156156 page_header = self._get_current_page_header()
tests/mocks/Unity/CMakeLists.txt+3−3
@@ -7,7 +7,7 @@ add_subdirectory(DashCommunicator)
77pkg_search_module(DEE dee-1.0 REQUIRED)
88pkg_search_module(GOBJECT gobject-2.0 REQUIRED)
99pkg_search_module(DEEQT libdee-qt5 REQUIRED)
10−pkg_check_modules(SCOPES_API REQUIRED unity-shell-scopes=3)
10+pkg_check_modules(SCOPES_API REQUIRED unity-shell-scopes=4)
1111
1212include_directories(
1313 ${CMAKE_CURRENT_BINARY_DIR}
@@ -23,14 +23,14 @@ set(UnityQML_SOURCES
2323 fake_scope.cpp
2424 fake_scopes.cpp
2525 fake_categories.cpp
26− fake_department.cpp
26+ fake_navigation.cpp
2727 fake_resultsmodel.cpp
2828 fake_previewmodel.cpp
2929 fake_previewstack.cpp
3030 fake_previewwidgetmodel.cpp
3131 fake_unity_plugin.cpp
3232 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/CategoriesInterface.h
33− ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/DepartmentInterface.h
33+ ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/NavigationInterface.h
3434 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/PreviewModelInterface.h
3535 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/PreviewStackInterface.h
3636 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/PreviewWidgetModelInterface.h
tests/mocks/Unity/Unity.qmltypes+79−27
@@ -24,6 +24,12 @@ Module {
2424 Parameter { name: "categoryId"; type: "string" }
2525 Parameter { name: "json"; type: "string" }
2626 }
27+ Method {
28+ name: "data"
29+ type: "QVariant"
30+ Parameter { name: "row"; type: "int" }
31+ Parameter { name: "role"; type: "int" }
32+ }
2733 }
2834 Component {
2935 name: "PreviewModel"
@@ -62,6 +68,10 @@ Module {
6268 prototype: "unity::shell::scopes::ScopeInterface"
6369 exports: ["Unity/MockScope 0.2"]
6470 exportMetaObjectRevisions: [0]
71+ Signal {
72+ name: "performQuery"
73+ Parameter { name: "query"; type: "string" }
74+ }
6575 Method {
6676 name: "setSearchInProgress"
6777 Parameter { name: "inProg"; type: "bool" }
@@ -81,18 +91,21 @@ Module {
8191 Parameter { name: "scope"; type: "unity::shell::scopes::ScopeInterface"; isPointer: true }
8292 }
8393 Method {
84− name: "getDepartment"
85− type: "unity::shell::scopes::DepartmentInterface*"
86− Parameter { name: "id"; type: "string" }
94+ name: "getNavigation"
95+ type: "unity::shell::scopes::NavigationInterface*"
96+ Parameter { name: "navigationId"; type: "string" }
8797 }
8898 Method {
89− name: "loadDepartment"
90− Parameter { name: "id"; type: "string" }
99+ name: "getAltNavigation"
100+ type: "unity::shell::scopes::NavigationInterface*"
101+ Parameter { name: "altNavigationId"; type: "string" }
91102 }
92103 Method {
93− name: "performQuery"
94− Parameter { name: "query"; type: "string" }
104+ name: "setNavigationState"
105+ Parameter { name: "navigationId"; type: "string" }
106+ Parameter { name: "isAltNavigation"; type: "bool" }
95107 }
108+ Method { name: "refresh" }
96109 }
97110 Component {
98111 name: "Scopes"
@@ -137,6 +150,7 @@ Module {
137150 "RoleRawRendererTemplate": 3,
138151 "RoleRenderer": 4,
139152 "RoleComponents": 5,
153+ "RoleHeaderLink": 6,
140154 "RoleResults": 7,
141155 "RoleCount": 8
142156 }
@@ -157,27 +171,28 @@ Module {
157171 }
158172 }
159173 Component {
160− name: "unity::shell::scopes::DepartmentInterface"
174+ name: "unity::shell::scopes::NavigationInterface"
161175 prototype: "QAbstractListModel"
162− exports: ["Unity/Department 0.2"]
176+ exports: ["Unity/Navigation 0.2"]
163177 isCreatable: false
164178 exportMetaObjectRevisions: [0]
165179 Enum {
166180 name: "Roles"
167181 values: {
168− "RoleDepartmentId": 0,
182+ "RoleNavigationId": 0,
169183 "RoleLabel": 1,
170184 "RoleHasChildren": 2,
171185 "RoleIsActive": 3
172186 }
173187 }
174− Property { name: "departmentId"; type: "string"; isReadonly: true }
188+ Property { name: "navigationId"; type: "string"; isReadonly: true }
175189 Property { name: "label"; type: "string"; isReadonly: true }
176190 Property { name: "allLabel"; type: "string"; isReadonly: true }
177− Property { name: "parentDepartmentId"; type: "string"; isReadonly: true }
191+ Property { name: "parentNavigationId"; type: "string"; isReadonly: true }
178192 Property { name: "parentLabel"; type: "string"; isReadonly: true }
179193 Property { name: "loaded"; type: "bool"; isReadonly: true }
180194 Property { name: "isRoot"; type: "bool"; isReadonly: true }
195+ Property { name: "hidden"; type: "bool"; isReadonly: true }
181196 Property { name: "count"; type: "int"; isReadonly: true }
182197 }
183198 Component {
@@ -247,7 +262,8 @@ Module {
247262 "RoleEmblem": 8,
248263 "RoleSummary": 9,
249264 "RoleAttributes": 10,
250− "RoleBackground": 11
265+ "RoleBackground": 11,
266+ "RoleOverlayColor": 12
251267 }
252268 }
253269 Property { name: "categoryId"; type: "string" }
@@ -259,13 +275,22 @@ Module {
259275 exports: ["Unity/Scope 0.2"]
260276 isCreatable: false
261277 exportMetaObjectRevisions: [0]
278+ Enum {
279+ name: "Status"
280+ values: {
281+ "Okay": 0,
282+ "NoInternet": 1,
283+ "NoLocationData": 2,
284+ "Unknown": 3
285+ }
286+ }
262287 Property { name: "id"; type: "string"; isReadonly: true }
263288 Property { name: "name"; type: "string"; isReadonly: true }
264289 Property { name: "iconHint"; type: "string"; isReadonly: true }
265290 Property { name: "description"; type: "string"; isReadonly: true }
266291 Property { name: "searchHint"; type: "string"; isReadonly: true }
267292 Property { name: "searchInProgress"; type: "bool"; isReadonly: true }
268− Property { name: "visible"; type: "bool"; isReadonly: true }
293+ Property { name: "favorite"; type: "bool" }
269294 Property { name: "shortcut"; type: "string"; isReadonly: true }
270295 Property {
271296 name: "categories"
@@ -273,13 +298,27 @@ Module {
273298 isReadonly: true
274299 isPointer: true
275300 }
301+ Property {
302+ name: "settings"
303+ type: "unity::shell::scopes::SettingsModelInterface"
304+ isReadonly: true
305+ isPointer: true
306+ }
276307 Property { name: "searchQuery"; type: "string" }
277308 Property { name: "noResultsHint"; type: "string" }
278309 Property { name: "formFactor"; type: "string" }
279310 Property { name: "isActive"; type: "bool" }
280− Property { name: "currentDepartmentId"; type: "string"; isReadonly: true }
281− Property { name: "hasDepartments"; type: "bool"; isReadonly: true }
311+ Property { name: "currentNavigationId"; type: "string"; isReadonly: true }
312+ Property { name: "hasNavigation"; type: "bool"; isReadonly: true }
313+ Property { name: "currentAltNavigationId"; type: "string"; isReadonly: true }
314+ Property { name: "hasAltNavigation"; type: "bool"; isReadonly: true }
282315 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" }
283322 Signal { name: "showDash" }
284323 Signal { name: "hideDash" }
285324 Signal {
@@ -298,10 +337,6 @@ Module {
298337 name: "openScope"
299338 Parameter { name: "scope"; type: "unity::shell::scopes::ScopeInterface"; isPointer: true }
300339 }
301− Signal {
302− name: "activateApplication"
303− Parameter { name: "desktop"; type: "string" }
304− }
305340 Method {
306341 name: "activate"
307342 Parameter { name: "result"; type: "QVariant" }
@@ -317,14 +352,25 @@ Module {
317352 Parameter { name: "scope"; type: "unity::shell::scopes::ScopeInterface"; isPointer: true }
318353 }
319354 Method {
320− name: "getDepartment"
321− type: "unity::shell::scopes::DepartmentInterface*"
322− Parameter { name: "departmentId"; type: "string" }
355+ name: "getNavigation"
356+ type: "unity::shell::scopes::NavigationInterface*"
357+ Parameter { name: "navigationId"; type: "string" }
358+ }
359+ Method {
360+ name: "getAltNavigation"
361+ type: "unity::shell::scopes::NavigationInterface*"
362+ Parameter { name: "altNavigationId"; type: "string" }
323363 }
324364 Method {
325− name: "loadDepartment"
326− Parameter { name: "departmentId"; type: "string" }
365+ name: "setNavigationState"
366+ Parameter { name: "navId"; type: "string" }
367+ Parameter { name: "altNavigation"; type: "bool" }
327368 }
369+ Method {
370+ name: "performQuery"
371+ Parameter { name: "cannedQuery"; type: "string" }
372+ }
373+ Method { name: "refresh" }
328374 }
329375 Component {
330376 name: "unity::shell::scopes::ScopesInterface"
@@ -334,11 +380,17 @@ Module {
334380 values: {
335381 "RoleScope": 0,
336382 "RoleId": 1,
337− "RoleVisible": 2,
338− "RoleTitle": 3
383+ "RoleTitle": 2
339384 }
340385 }
341386 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+ }
342394 Method {
343395 name: "getScope"
344396 type: "unity::shell::scopes::ScopeInterface*"
tests/mocks/Unity/fake_department.cpp → tests/mocks/Unity/fake_navigation.cpprenamed+32−40
@@ -14,14 +14,15 @@
1414 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1515 */
1616
17−#include "fake_department.h"
17+#include "fake_navigation.h"
1818
1919#include "fake_scope.h"
2020
21+#include <QDebug>
2122#include <QTimer>
2223
23−Department::Department(const QString& departmentId, const QString& label, const QString& allLabel, const QString& parentId, const QString& parentLabel, Scope* scope)
24− : m_departmentId(departmentId)
24+Navigation::Navigation(const QString& navigationId, const QString& label, const QString& allLabel, const QString& parentId, const QString& parentLabel, Scope* scope)
25+ : m_navigationId(navigationId)
2526 , m_label(label)
2627 , m_allLabel(allLabel)
2728 , m_parentId(parentId)
@@ -30,96 +31,87 @@ Department::Department(const QString& departmentId, const QString& label, const
3031 , m_scope(scope)
3132{
3233 QTimer::singleShot(1500, this, SLOT(slotLoaded()));
33− connect(scope, SIGNAL(currentDepartmentIdChanged()), this, SLOT(slotCurrentDepartmentChanged()));
34+ connect(scope, SIGNAL(currentNavigationIdChanged()), this, SLOT(slotCurrentNavigationChanged()));
3435}
3536
36−QString Department::departmentId() const
37+QString Navigation::navigationId() const
3738{
38− return m_departmentId;
39+ return m_navigationId;
3940}
4041
41−QString Department::label() const
42+QString Navigation::label() const
4243{
4344 return m_label;
4445}
4546
46−QString Department::allLabel() const
47+QString Navigation::allLabel() const
4748{
4849 return m_allLabel;
4950}
5051
51−QString Department::parentDepartmentId() const
52+QString Navigation::parentNavigationId() const
5253{
5354 return m_parentId;
5455}
5556
56−QString Department::parentLabel() const
57+QString Navigation::parentLabel() const
5758{
5859 return m_parentLabel;
5960}
6061
61−void Department::slotLoaded()
62+void Navigation::slotLoaded()
6263{
6364 m_loaded = true;
6465 Q_EMIT loadedChanged();
6566}
6667
67−bool Department::loaded() const
68+bool Navigation::loaded() const
6869{
6970 return m_loaded;
7071}
7172
72−int Department::count() const
73+int Navigation::count() const
7374{
7475 return rowCount();
7576}
7677
77−bool Department::isRoot() const
78+bool Navigation::isRoot() const
7879{
79− return m_departmentId == "root";
80+ return m_navigationId == "root" || m_navigationId == "altroot";
8081}
8182
82−int Department::rowCount(const QModelIndex & /*parent*/) const
83+bool Navigation::hidden() const
8384{
84− if (!m_loaded || m_departmentId.startsWith("child") || m_departmentId == "middle3")
85− return 0;
86− else
87− return 8;
85+ return m_navigationId == "altroot";
8886}
8987
90−QHash<int, QByteArray> Department::roleNames() const
88+int Navigation::rowCount(const QModelIndex & /*parent*/) const
9189{
92− QHash<int, QByteArray> res;
93− res[RoleDepartmentId] = "departmentId";
94− res[RoleLabel] = "label";
95− res[RoleHasChildren] = "hasChildren";
96− res[RoleIsActive] = "isActive";
97− return res;
90+ if (!m_loaded || m_navigationId.startsWith("child") || m_navigationId == "middle3")
91+ return 0;
92+ else
93+ return 8;
9894}
9995
100−QVariant Department::data(const QModelIndex &index, int role) const
96+QVariant Navigation::data(const QModelIndex &index, int role) const
10197{
10298 switch (role) {
103− case RoleDepartmentId:
104− if (m_departmentId == "root")
99+ case RoleNavigationId:
100+ if (m_navigationId == "root")
105101 return QString("middle%1").arg(index.row());
106− else if (m_departmentId.startsWith("middle"))
107− return QString("child%1%2").arg(m_departmentId).arg(index.row());
108− break;
102+ else if (m_navigationId.startsWith("middle"))
103+ return QString("child%1%2").arg(m_navigationId).arg(index.row());
109104 case RoleLabel:
110− return QString("%1Child%2").arg(m_departmentId).arg(index.row());
111− break;
105+ return QString("%1Child%2").arg(m_navigationId).arg(index.row());
112106 case RoleHasChildren:
113− return m_departmentId == "root" && index.row() != 3;
114− break;
107+ return m_navigationId == "root" && index.row() != 3;
115108 case RoleIsActive:
116− return m_scope->currentDepartmentId() == data(index, RoleDepartmentId);
117− break;
109+ return m_scope->currentNavigationId() == data(index, RoleNavigationId);
118110 }
119111 return QVariant();
120112}
121113
122−void Department::slotCurrentDepartmentChanged()
114+void Navigation::slotCurrentNavigationChanged()
123115{
124116 // This is wasteful, should only emit it if really something changed in this
125117 // 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 @@
1414 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1515 */
1616
17−#ifndef FAKE_DEPARTMENT_H
18−#define FAKE_DEPARTMENT_H
17+#ifndef FAKE_NAVIGATION_H
18+#define FAKE_NAVIGATION_H
1919
20−#include <unity/shell/scopes/DepartmentInterface.h>
20+#include <unity/shell/scopes/NavigationInterface.h>
2121
2222class Scope;
2323
24−class Department : public unity::shell::scopes::DepartmentInterface
24+class Navigation : public unity::shell::scopes::NavigationInterface
2525{
2626 Q_OBJECT
2727
2828public:
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);
3030
31− QString departmentId() const override;
31+ QString navigationId() const override;
3232 QString label() const override;
3333 QString allLabel() const override;
34− QString parentDepartmentId() const override;
34+ QString parentNavigationId() const override;
3535 QString parentLabel() const override;
3636 bool loaded() const override;
37− int count() const override;
3837 bool isRoot() const override;
38+ bool hidden() const override;
39+ int count() const override;
3940
4041 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
41− QHash<int, QByteArray> roleNames() const;
4242 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
4343
4444public Q_SLOTS:
45− void slotCurrentDepartmentChanged();
45+ void slotCurrentNavigationChanged();
4646
4747private Q_SLOTS:
4848 void slotLoaded();
4949
5050private:
51− QString m_departmentId;
51+ QString m_navigationId;
5252 QString m_label;
5353 QString m_allLabel;
5454 QString m_parentId;
5555 QString m_parentLabel;
5656 bool m_loaded;
57− QString m_currentDepartment;
57+ QString m_currentNavigation;
5858 Scope *m_scope;
5959};
6060
61−#endif // FAKE_DEPARTMENT_H
61+#endif // FAKE_NAVIGATION_H
tests/mocks/Unity/fake_scope.cpp+65−17
@@ -14,24 +14,26 @@
1414 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1515 */
1616
17+#include <QDebug>
1718#include <QUrl>
1819
1920#include "fake_scope.h"
20−#include "fake_department.h"
21+#include "fake_navigation.h"
2122#include "fake_resultsmodel.h"
2223
2324Scope::Scope(QObject* parent) : Scope(QString(), QString(), false, parent)
2425{
2526}
2627
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)
2829 : unity::shell::scopes::ScopeInterface(parent)
2930 , m_id(id)
3031 , m_name(name)
31− , m_visible(visible)
3232 , m_searching(false)
33+ , m_favorite(favorite)
3334 , m_isActive(false)
34− , m_currentDeparment("root")
35+ , m_currentNavigationId("root")
36+ , m_currentAltNavigationId("altroot")
3537 , m_previewRendererName("preview-generic")
3638 , m_categories(new Categories(categories, this))
3739{
@@ -77,6 +79,11 @@ bool Scope::searchInProgress() const
7779 return m_searching;
7880}
7981
82+bool Scope::favorite() const
83+{
84+ return m_favorite;
85+}
86+
8087unity::shell::scopes::CategoriesInterface* Scope::categories() const
8188{
8289 return m_categories;
@@ -97,11 +104,6 @@ QString Scope::formFactor() const
97104 return m_formFactor;
98105}
99106
100−bool Scope::visible() const
101−{
102− return m_visible;
103−}
104−
105107bool Scope::isActive() const
106108{
107109 return m_isActive;
@@ -131,6 +133,13 @@ void Scope::setActive(const bool active)
131133 }
132134}
133135
136+void Scope::setFavorite(const bool favorite)
137+{
138+ if (favorite != m_favorite) {
139+ m_favorite = favorite;
140+ Q_EMIT favoriteChanged();
141+ }
142+}
134143void Scope::setSearchInProgress(const bool inProg)
135144{
136145 if (inProg != m_searching) {
@@ -170,16 +179,31 @@ void Scope::closeScope(unity::shell::scopes::ScopeInterface* /*scope*/)
170179 qFatal("Scope::closeScope is not implemented");
171180}
172181
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
174193{
175− return m_currentDeparment;
194+ return m_currentAltNavigationId;
176195}
177196
178−bool Scope::hasDepartments() const
197+bool Scope::hasAltNavigation() const
179198{
180199 return true;
181200}
182201
202+Scope::Status Scope::status() const
203+{
204+ return Status::Okay;
205+}
206+
183207QVariantMap Scope::customizations() const
184208{
185209 QVariantMap m, h;
@@ -196,7 +220,12 @@ QVariantMap Scope::customizations() const
196220 return m;
197221}
198222
199−unity::shell::scopes::DepartmentInterface* Scope::getDepartment(const QString& id)
223+void Scope::refresh()
224+{
225+ qDebug() << "Scope::refresh is currently not implmented in the fake scopes plugin";
226+}
227+
228+unity::shell::scopes::NavigationInterface* Scope::getNavigation(const QString& id)
200229{
201230 if (id.isEmpty())
202231 return nullptr;
@@ -210,11 +239,30 @@ unity::shell::scopes::DepartmentInterface* Scope::getDepartment(const QString& i
210239 parentId = id.mid(5, 7);
211240 parentLabel = parentId;
212241 }
213− return new Department(id, id, "all"+id, parentId, parentLabel, this);
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+ }
256+ return new Navigation(id, id, "all"+id, parentId, parentLabel, this);
214257}
215258
216−void Scope::loadDepartment(const QString& id)
259+void Scope::setNavigationState(const QString &navigationId, bool isAltNavigation)
217260{
218− m_currentDeparment = id;
219− Q_EMIT currentDepartmentIdChanged();
261+ if (isAltNavigation) {
262+ m_currentAltNavigationId = navigationId;
263+ Q_EMIT currentAltNavigationIdChanged();
264+ } else {
265+ m_currentNavigationId = navigationId;
266+ Q_EMIT currentNavigationIdChanged();
267+ }
220268}
tests/mocks/Unity/fake_scope.h+16−8
@@ -30,7 +30,7 @@ class Scope : public unity::shell::scopes::ScopeInterface
3030
3131public:
3232 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);
3434
3535 /* getters */
3636 QString id() const override;
@@ -38,9 +38,9 @@ public:
3838 QString iconHint() const override;
3939 QString description() const override;
4040 QString searchHint() const override;
41− bool visible() const override;
4241 QString shortcut() const override;
4342 bool searchInProgress() const override;
43+ bool favorite() const override;
4444 unity::shell::scopes::CategoriesInterface* categories() const override;
4545 QString searchQuery() const override;
4646 QString noResultsHint() const override;
@@ -53,6 +53,7 @@ public:
5353 void setNoResultsHint(const QString& hint) override;
5454 void setFormFactor(const QString& form_factor) override;
5555 void setActive(const bool) override;
56+ void setFavorite(const bool) override;
5657 Q_INVOKABLE void setSearchInProgress(const bool inProg); // This is not invokable in the Interface, here for testing benefits
5758
5859 Q_INVOKABLE void activate(QVariant const& result) override;
@@ -60,14 +61,20 @@ public:
6061 Q_INVOKABLE void cancelActivation() override;
6162 Q_INVOKABLE void closeScope(unity::shell::scopes::ScopeInterface* scope) override;
6263
63− QString currentDepartmentId() const override;
64− bool hasDepartments() const override;
65− Q_INVOKABLE unity::shell::scopes::DepartmentInterface* getDepartment(const QString& id) override;
66− Q_INVOKABLE void loadDepartment(const QString& id) override;
64+ QString currentNavigationId() const override;
65+ bool hasNavigation() const 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;
70+ Q_INVOKABLE void setNavigationState(const QString &navigationId, bool isAltNavigation) override;
6771 Q_SIGNAL void performQuery(const QString& query) override;
6872
73+ Status status() const override;
6974 QVariantMap customizations() const override;
7075
76+ Q_INVOKABLE void refresh() override;
77+
7178protected:
7279
7380 QString m_id;
@@ -77,10 +84,11 @@ protected:
7784 QString m_searchQuery;
7885 QString m_noResultsHint;
7986 QString m_formFactor;
80− bool m_visible;
8187 bool m_searching;
88+ bool m_favorite;
8289 bool m_isActive;
83− QString m_currentDeparment;
90+ QString m_currentNavigationId;
91+ QString m_currentAltNavigationId;
8492
8593 QString m_previewRendererName;
8694
tests/mocks/Unity/fake_scopes.cpp+10−2
@@ -32,6 +32,11 @@ Scopes::Scopes(QObject *parent)
3232 timer.setSingleShot(true);
3333 timer.setInterval(100);
3434 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+
3540 load();
3641}
3742
@@ -92,8 +97,6 @@ QVariant Scopes::data(const QModelIndex& index, int role) const
9297 return QVariant::fromValue(scope);
9398 } else if (role == Scopes::RoleId) {
9499 return QVariant::fromValue(scope->id());
95− } else if (role == Scopes::RoleVisible) {
96− return QVariant::fromValue(scope->visible());
97100 } else if (role == Scopes::RoleTitle) {
98101 return QVariant::fromValue(scope->name());
99102 } else {
@@ -125,6 +128,11 @@ bool Scopes::loaded() const
125128 return m_loaded;
126129}
127130
131+int Scopes::count() const
132+{
133+ return rowCount();
134+}
135+
128136unity::shell::scopes::ScopeInterface* Scopes::overviewScope() const
129137{
130138 return nullptr;
tests/mocks/Unity/fake_scopes.h+1
@@ -50,6 +50,7 @@ public:
5050 QModelIndex parent ( const QModelIndex & index ) const;
5151
5252 bool loaded() const override;
53+ int count() const override;
5354 unity::shell::scopes::ScopeInterface* overviewScope() const override;
5455
5556private Q_SLOTS:
tests/mocks/Unity/fake_unity_plugin.cpp+2−2
@@ -22,7 +22,7 @@
2222// local
2323#include "fake_scopes.h"
2424#include "fake_categories.h"
25−#include "fake_department.h"
25+#include "fake_navigation.h"
2626#include "fake_previewmodel.h"
2727#include "fake_previewwidgetmodel.h"
2828#include "fake_resultsmodel.h"
@@ -43,7 +43,7 @@ void FakeUnityPlugin::registerTypes(const char *uri)
4343 qmlRegisterType<Scopes>(uri, 0, 2, "Scopes");
4444 qmlRegisterType<Scope>(uri, 0, 2, "MockScope");
4545 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.");
4747 qmlRegisterUncreatableType<unity::shell::scopes::CategoriesInterface>(uri, 0, 2, "Categories", "Can't create Categories object in QML.");
4848 qmlRegisterUncreatableType<unity::shell::scopes::PreviewModelInterface>(uri, 0, 2, "PreviewModel", "Can't create new PreviewModel in QML. Get them from PreviewStack instance.");
4949 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 {
3333 visible: image.status == Image.Ready;
3434 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
3535 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; }
38− onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings();
36+ Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
3937 Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
4038 function updateWidthHeightBindings() {
4139 if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) {
4240 width = root.fixedArtShapeSize.width;
4341 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 });
4742 } else {
48− width = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.width : height * image.aspect });
49− height = Qt.binding(function() { return !visible ? 0 : image.height });
43+ width = Qt.binding(function() { return !visible ? 0 : image.width });
44+ height = Qt.binding(function() { return !visible ? 0 : image.height });
5045 }
5146 }
5247 image: Image {
@@ -54,8 +49,7 @@ Item {
5449 source: cardData && cardData["art"] || "";
5550 cache: true;
5651 asynchronous: root.asynchronous;
57− fillMode: components && components["art"]["fill-mode"] === "fit" ? Image.PreserveAspectFit: Image.PreserveAspectCrop;
58− readonly property real aspect: implicitWidth / implicitHeight;
52+ fillMode: Image.PreserveAspectCrop;
5953 width: root.width;
6054 height: width / artShape.aspect;
6155 }
@@ -84,5 +78,13 @@ leftMargin: units.gu(1);
8478 font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
8579 horizontalAlignment: root.headerAlignment;
8680 }
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+}
8789implicitHeight: titleLabel.y + titleLabel.height + units.gu(1);
8890}
tests/plugins/Dash/cardcreator/1.tst+1−1
@@ -1,3 +1,3 @@
11template: {"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"}}
33result: 1.res
tests/plugins/Dash/cardcreator/2.res+8
@@ -116,5 +116,13 @@ left: parent.left;
116116
117117 ]
118118 }
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+}
119127implicitHeight: row.y + row.height + units.gu(1);
120128}
tests/plugins/Dash/cardcreator/2.tst+1−1
@@ -1,3 +1,3 @@
11template: {"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"}}
33result: 2.res
tests/plugins/Dash/cardcreator/3.res+12−10
@@ -25,7 +25,7 @@ Item {
2525 objectName: "artShapeLoader";
2626 active: cardData && cardData["art"] || false;
2727 asynchronous: root.asynchronous;
28− visible: status == Loader.Ready;
28+ visible: status == Loader.Ready;
2929 sourceComponent: UbuntuShape {
3030 id: artShape;
3131 objectName: "artShape";
@@ -33,20 +33,15 @@ Item {
3333 visible: image.status == Image.Ready;
3434 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
3535 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1;
36− readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect;
3736 Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
38− onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings();
3937 Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
4038 function updateWidthHeightBindings() {
4139 if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) {
4240 width = root.fixedArtShapeSize.width;
4341 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 });
4742 } else {
48− width = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.width : height * image.aspect });
49− height = Qt.binding(function() { return !visible ? 0 : image.height });
43+ width = Qt.binding(function() { return !visible ? 0 : image.width });
44+ height = Qt.binding(function() { return !visible ? 0 : image.height });
5045 }
5146 }
5247 image: Image {
@@ -54,8 +49,7 @@ Item {
5449 source: cardData && cardData["art"] || "";
5550 cache: true;
5651 asynchronous: root.asynchronous;
57− fillMode: components && components["art"]["fill-mode"] === "fit" ? Image.PreserveAspectFit: Image.PreserveAspectCrop;
58− readonly property real aspect: implicitWidth / implicitHeight;
52+ fillMode: Image.PreserveAspectCrop;
5953 width: root.width;
6054 height: width / artShape.aspect;
6155 }
@@ -103,5 +97,13 @@ Label {
10397 font.weight: Font.Light;
10498 horizontalAlignment: root.headerAlignment;
10599 }
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+}
106108implicitHeight: subtitleLabel.y + subtitleLabel.height + units.gu(1);
107109}
tests/plugins/Dash/cardcreator/3.tst+1−1
@@ -1,3 +1,3 @@
11template: {"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"}}
33result: 3.res
tests/plugins/Dash/cardcreator/4.res+8
@@ -94,5 +94,13 @@ Label {
9494}
9595]
9696}
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+}
97105implicitHeight: row.y + row.height + units.gu(1);
98106}
tests/plugins/Dash/cardcreator/4.tst+1−1
@@ -1,3 +1,3 @@
11template: {"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"}}
33result: 4.res
tests/plugins/Dash/cardcreator/5.res+14−12
@@ -25,7 +25,7 @@ Item {
2525 objectName: "artShapeLoader";
2626 active: cardData && cardData["art"] || false;
2727 asynchronous: root.asynchronous;
28− visible: status == Loader.Ready;
28+ visible: status == Loader.Ready;
2929 sourceComponent: UbuntuShape {
3030 id: artShape;
3131 objectName: "artShape";
@@ -33,20 +33,15 @@ Item {
3333 visible: image.status == Image.Ready;
3434 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
3535 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1;
36− readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect;
3736 Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
38− onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings();
3937 Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
4038 function updateWidthHeightBindings() {
4139 if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) {
4240 width = root.fixedArtShapeSize.width;
4341 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 });
4742 } else {
48− width = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.width : height * image.aspect });
49− height = Qt.binding(function() { return !visible ? 0 : image.height });
43+ width = Qt.binding(function() { return !visible ? 0 : image.width });
44+ height = Qt.binding(function() { return !visible ? 0 : image.height });
5045 }
5146 }
5247 image: Image {
@@ -54,13 +49,12 @@ Item {
5449 source: cardData && cardData["art"] || "";
5550 cache: true;
5651 asynchronous: root.asynchronous;
57− fillMode: components && components["art"]["fill-mode"] === "fit" ? Image.PreserveAspectFit: Image.PreserveAspectCrop;
58− readonly property real aspect: implicitWidth / implicitHeight;
52+ fillMode: Image.PreserveAspectCrop;
5953 width: root.width;
6054 height: width / artShape.aspect;
6155 }
6256 }
63− }
57+ }
6458 }
6559Loader {
6660 id: overlayLoader;
@@ -69,7 +63,7 @@ Loader {
6963 right: artShapeHolder.right;
7064 bottom: artShapeHolder.bottom;
7165 }
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;
7367 asynchronous: root.asynchronous;
7468 visible: showHeader && status == Loader.Ready;
7569 sourceComponent: ShaderEffect {
@@ -143,5 +137,13 @@ Label {
143137 font.weight: Font.Light;
144138 horizontalAlignment: root.headerAlignment;
145139 }
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+}
146148implicitHeight: subtitleLabel.y + subtitleLabel.height + units.gu(1);
147149}
tests/plugins/Dash/cardcreator/5.tst+1−1
@@ -1,3 +1,3 @@
11template: {"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"}}
33result: 5.res
tests/plugins/Dash/cardcreator/6.res+10−8
@@ -33,19 +33,14 @@ Item {
3333 visible: image.status == Image.Ready;
3434 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
3535 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1;
36− readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect;
3736 Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
38− onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings();
3937 Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
4038 function updateWidthHeightBindings() {
4139 if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) {
4240 width = root.fixedArtShapeSize.width;
4341 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 });
4742 } 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 });
4944 height = Qt.binding(function() { return !visible ? 0 : image.height });
5045 }
5146 }
@@ -54,8 +49,7 @@ Item {
5449 source: cardData && cardData["art"] || "";
5550 cache: true;
5651 asynchronous: root.asynchronous;
57− fillMode: components && components["art"]["fill-mode"] === "fit" ? Image.PreserveAspectFit: Image.PreserveAspectCrop;
58− readonly property real aspect: implicitWidth / implicitHeight;
52+ fillMode: Image.PreserveAspectCrop;
5953 width: root.width;
6054 height: width / artShape.aspect;
6155 }
@@ -63,5 +57,13 @@ Item {
6357 }
6458 }
6559readonly 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+}
6668implicitHeight: artShapeHolder.height;
6769}
tests/plugins/Dash/cardcreator/6.tst+1−1
@@ -1,3 +1,3 @@
11template: {"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"}}
33result: 6.res
tests/plugins/Dash/cardcreator/7.res+9−1
@@ -116,7 +116,7 @@ CardAttributes {
116116 objectName: "attributesRow";
117117 anchors { left: parent.left; right: parent.right }
118118 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"];
120120 }
121121
122122 ]
@@ -124,5 +124,13 @@ CardAttributes {
124124
125125 ]
126126 }
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+}
127135implicitHeight: row.y + row.height + units.gu(1);
128136}
tests/plugins/Dash/cardcreator/7.tst+1−1
@@ -1,3 +1,3 @@
11template: {"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}}
33result: 7.res
tests/plugins/Dash/cardcreatortest.cpp+13−4
@@ -19,6 +19,7 @@
1919#include <QQuickItem>
2020#include <QQuickView>
2121#include <QtTestGui>
22+#include <QDebug>
2223#include <QTemporaryFile>
2324
2425class CardCreatorTest : public QObject
@@ -74,15 +75,23 @@ private Q_SLOTS:
7475 QFile testResultFile(testDirPath + resultFileName);
7576 QVERIFY(testResultFile.open(QIODevice::ReadOnly));
7677 QTextStream ts2(&testResultFile);
77− const QString expectedResult = ts2.readAll();
78− const QString executedResult = cardStringResult.toString();
78+
7979 // Record failed results to /tmp
80+ const QString executedResult = cardStringResult.toString();
8081 QTemporaryFile tmpFile(QDir::tempPath() + QDir::separator() + "testCardCreatorFailedResultXXXXXX");
8182 tmpFile.open();
8283 tmpFile.setAutoRemove(false);
8384 tmpFile.write(executedResult.toUtf8().constData());
84− QCOMPARE(executedResult.simplified(), expectedResult.simplified());
85− tmpFile.setAutoRemove(true); // Remove the result if it passed
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) {
90+ QCOMPARE(cardStringResultLines[i].simplified(), expectedLines[i].simplified());
91+ }
92+
93+ // Remove the result if it passed
94+ tmpFile.setAutoRemove(true);
8695
8796 QVariant createCardComponentResult;
8897 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 {
5454 { tag: "lightgrey", luminance: 0.8275 },
5555 { tag: "grey", luminance: 0.5020 },
5656 { tag: "darkgrey", luminance: 0.6627 },
57+ { tag: "red", luminance: 0.2126 },
58+ { tag: "green", luminance: 0.3590 },
59+ { tag: "blue", luminance: 0.0722 },
5760 ];
5861 }
5962
@@ -64,10 +67,10 @@ Rectangle {
6467
6568 function test_foreground_data() {
6669 return [
67− { tag: "default", index: 0, foreground: "grey" },
68− { tag: "red on black", index: 1, foreground: "red" },
69− { tag: "green on white", index: 2, foreground: "green" },
70− { tag: "blue on darkgrey", index: 3, foreground: "blue" },
70+ { tag: "default", index: 0, foreground: "grey", luminance: 0.5020 },
71+ { tag: "red on black", index: 1, foreground: "red", luminance: 0.2126 },
72+ { tag: "green on white", index: 2, foreground: "green", luminance: 0.3590 },
73+ { tag: "blue on darkgrey", index: 3, foreground: "blue", luminance: 0.0722 },
7174 ];
7275 }
7376
@@ -75,14 +78,15 @@ Rectangle {
7578 tool.style = testCase.styles[data.index];
7679 verify(Qt.colorEqual(tool.foreground, data.foreground),
7780 "Foreground color not equal: %1 != %2".arg(tool.foreground).arg(data.foreground));
81+ compare(tool.foregroundLuminance.toFixed(4), data.luminance.toFixed(4));
7882 }
7983
8084 function test_background_data() {
8185 return [
8286 { tag: "default", index: 0, background: "transparent" },
83− { tag: "red on black", index: 1, background: "black" },
84− { tag: "green on white", index: 2, background: "white" },
85− { tag: "blue on darkgrey", index: 3, background: "darkgrey" },
87+ { tag: "red on black", index: 1, background: "black", luminance: 0 },
88+ { tag: "green on white", index: 2, background: "white", luminance: 1 },
89+ { tag: "blue on darkgrey", index: 3, background: "darkgrey", luminance: 0.6627 },
8690 ];
8791 }
8892
@@ -90,6 +94,9 @@ Rectangle {
9094 tool.style = testCase.styles[data.index];
9195 verify(Qt.colorEqual(tool.background, data.background),
9296 "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+ }
93100 }
94101
95102 function test_threshold_data() {
tests/qmltests/CMakeLists.txt+1−1
@@ -30,7 +30,6 @@ add_qml_test(Components Rating)
3030add_qml_test(Components ResponsiveFlowView)
3131add_qml_test(Components ResponsiveGridView)
3232add_qml_test(Components ResponsiveVerticalJournal IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins)
33−add_qml_test(Components SeeMore)
3433add_qml_test(Components Showable)
3534add_qml_test(Components PageHeader)
3635add_qml_test(Components ZoomableImage)
@@ -43,6 +42,7 @@ add_qml_test(Dash GenericScopeView)
4342add_qml_test(Dash/Previews Preview)
4443add_qml_test(Dash/Previews PreviewActions)
4544add_qml_test(Dash/Previews PreviewAudioPlayback)
45+add_qml_test(Dash/Previews PreviewExpandable)
4646add_qml_test(Dash/Previews PreviewHeader)
4747add_qml_test(Dash/Previews PreviewImageGallery)
4848add_qml_test(Dash/Previews PreviewPayments)
tests/qmltests/Components/tst_PageHeader.qml+21−23
@@ -119,29 +119,6 @@ Item {
119119 compare(pageHeader.searchHistory.get(0).query, "humppa4")
120120 }
121121
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−
145122 function test_titleImage() {
146123
147124 var titleImage = findChild(pageHeader, "titleImage");
@@ -192,6 +169,27 @@ Item {
192169 ];
193170 }
194171
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+
195193 function test_popup_closing(data) {
196194 searchEnabled = true;
197195 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 @@
1616
1717.pragma library
1818
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"]
2020
2121var defaultLayout = ' \
2222{ \
@@ -31,10 +31,10 @@ var defaultLayout = ' \
3131 "components": { \
3232 "title": null, \
3333 "art": { \
34− "aspect-ratio": 1.0, \
35− "fill-mode": "crop" \
34+ "aspect-ratio": 1.0 \
3635 }, \
3736 "subtitle": null, \
37+ "overlayColor": null, \
3838 "mascot": null, \
3939 "emblem": null, \
4040 "old-price": null, \
@@ -60,6 +60,7 @@ var fullMapping = ' \
6060 "art": "art", \
6161 "subtitle": "subtitle", \
6262 "mascot": "mascot", \
63+ "overlayColor": "overlayColor", \
6364 "summary": "summary", \
6465 "attributes": "attributes" \
6566}'
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 {
3737
3838 property var widgetDataShortText: {
3939 "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."
4141 }
4242
4343 PreviewTextSummary {
@@ -72,28 +72,14 @@ Rectangle {
7272 tryCompare(textLabel, "y", 0)
7373 }
7474
75− function test_see_more() {
76− var seeMore = findChild(previewTextSummary, "seeMore")
77−
78− // when it's more than textLabel.maximumCollapsedLineCount lines of text, show SeeMore component
75+ function test_show_collapsed() {
7976 verify(textLabel.lineCount > textLabel.maximumCollapsedLineCount)
80− compare(seeMore.visible, true)
81− verify(seeMore.more === false)
82− verify(textLabel.height < textLabel.contentHeight)
8377
84− // test interactions with SeeMore
85− var seeMoreLabel = findChild(seeMore, "seeMoreLabel")
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)
78+ previewTextSummary.expanded = false;
79+ tryCompareFunction(function() { return textLabel.height < textLabel.contentHeight; }, true)
9280
93− // text SeeMore automatic hiding
9481 previewTextSummary.widgetData = widgetDataShortText
9582 verify(textLabel.lineCount <= textLabel.maximumCollapsedLineCount)
96− compare(seeMore.visible, false)
9783 tryCompare(textLabel, "height", textLabel.contentHeight)
9884 tryCompare(previewTextSummary, "height", titleLabel.height + textLabel.height)
9985 }
tests/qmltests/Dash/Previews/tst_PreviewWidgetFactory.qml+1
@@ -77,6 +77,7 @@ Rectangle {
7777 return [
7878 { tag: "Actions", type: "actions", source: "PreviewActions.qml" },
7979 { tag: "Audio", type: "audio", source: "PreviewAudioPlayback.qml" },
80+ { tag: "Expandable", type: "expandable", source: "PreviewExpandable.qml" },
8081 { tag: "Gallery", type: "gallery", source: "PreviewImageGallery.qml" },
8182 { tag: "Header", type: "header", source: "PreviewHeader.qml" },
8283 { tag: "Image", type: "image", source: "PreviewZoomableImage.qml" },
tests/qmltests/Dash/tst_Card.qml+15−3
@@ -55,8 +55,8 @@ Rectangle {
5555 "layout": { "components": Helpers.update(JSON.parse(Helpers.fullMapping), { "art": { "aspect-ratio": 2 } }) }
5656 },
5757 {
58− "name": "Art, title - fitted",
59− "layout": { "components": Helpers.update(JSON.parse(Helpers.fullMapping), { "art": { "fill-mode": "fit" } }) }
58+ "name": "Art, title - tall",
59+ "layout": { "components": Helpers.update(JSON.parse(Helpers.fullMapping), { "art": { "aspect-ratio": 0.7 } }) }
6060 },
6161 {
6262 "name": "Art, header, summary - horizontal",
@@ -269,7 +269,7 @@ Rectangle {
269269 { tag: "Small", width: units.gu(12), index: 1 },
270270 { tag: "Large", width: units.gu(38), index: 2 },
271271 { 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 },
273273 { tag: "VerticalWidth", width: function() { return headerRow.width + units.gu(1) * 2 }, index: 0 },
274274 { tag: "HorizontalHeight", height: function() { return headerRow.height + units.gu(1) * 2 }, index: 5 },
275275 { tag: "HorizontalWidth", width: function() { return headerRow.x - units.gu(1) }, index: 5 },
@@ -475,5 +475,17 @@ Rectangle {
475475 compare(shape !== null, data.shape);
476476 tryCompare(mascotImage, "visible", !data.shape);
477477 }
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+ }
478490 }
479491}
tests/qmltests/Dash/tst_Dash.qml+28−15
@@ -45,12 +45,8 @@ Item {
4545 name: "Dash"
4646 when: windowShown
4747
48− property var scopes
49−
50− Component.onCompleted: {
51− var dashContent = findChild(dash, "dashContent");
52− scopes = dashContent.scopes;
53− }
48+ readonly property Item dashContent: findChild(dash, "dashContent");
49+ readonly property var scopes: dashContent.scopes
5450
5551 function init() {
5652 // clear and reload the scopes.
@@ -64,10 +60,10 @@ Item {
6460
6561 function get_scope_data() {
6662 return [
67− { tag: "MockScope1", visualIndex: 0, shouldBeVisible: true },
68− { tag: "MockScope2", visualIndex: -1, shouldBeVisible: false },
69− { tag: "clickscope", visualIndex: 1, shouldBeVisible: true },
70− { tag: "MockScope5", visualIndex: 2, shouldBeVisible: true },
63+ { tag: "MockScope1", visualIndex: 0 },
64+ { tag: "MockScope2", visualIndex: 1 },
65+ { tag: "clickscope", visualIndex: 2 },
66+ { tag: "MockScope5", visualIndex: 3 },
7167 ]
7268 }
7369
@@ -76,10 +72,6 @@ Item {
7672 }
7773
7874 function test_show_scope_on_load(data) {
79− if (data.shouldBeVisible == false) {
80− console.log("Not testing " + data.tag + ": not visible");
81− return;
82− }
8375 var dashContentList = findChild(dash, "dashContentList");
8476
8577 dash.showScopeOnLoaded = data.tag
@@ -87,7 +79,7 @@ Item {
8779 tryCompare(dashContentList, "count", 0);
8880 scopes.load();
8981 tryCompare(scopes, "loaded", true);
90− tryCompare(dashContentList, "count", 4);
82+ tryCompare(dashContentList, "count", 5);
9183
9284 verify(dashContentList != undefined);
9385 tryCompare(dashContentList, "currentIndex", data.visualIndex);
@@ -110,5 +102,26 @@ Item {
110102 dashCommunicatorService.mockSetCurrentScope("clickscope", true, true);
111103 tryCompare(dashContentList, "currentIndex", 1)
112104 }
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+ }
113126 }
114127}
tests/qmltests/Dash/tst_DashContent.qml+94−95
@@ -43,9 +43,6 @@ Item {
4343 id: dashContent
4444 anchors.fill: parent
4545
46− model: SortFilterProxyModel {
47− model: scopesModel
48− }
4946 scopes : scopesModel
5047 }
5148
@@ -268,117 +265,119 @@ Item {
268265 verify(carouselLV.tileWidth / carouselLV.tileHeight == cardTool.components["art"]["aspect-ratio"]);
269266 }
270267
271− function test_departments() {
272− var dashDepartments = findChild(dashContent, "dashDepartments");
273− compare(dashDepartments.visible, true);
274− compare(dashDepartments.showList, false);
275− waitForRendering(dashDepartments);
276− mouseClick(dashDepartments, 0, 0);
277− compare(dashDepartments.showList, true);
278−
279− var departmentListView = findChild(dashDepartments, "departmentListView");
280− compare(departmentListView.count, 1);
281− tryCompare(departmentListView.currentItem.department, "loaded", true);
282−
283− waitForRendering(departmentListView);
284− waitForRendering(departmentListView.currentItem);
285−
286− var allButton = findChild(dashDepartments, "allButton");
268+ function test_navigations() {
269+ var dashContentList = findChild(dashContent, "dashContentList");
270+ tryCompareFunction(function() { return findChild(dashContentList.currentItem, "dashNavigation") != null; }, true);
271+ var dashNavigation = findChild(dashContentList.currentItem, "dashNavigation");
272+ tryCompare(dashNavigation, "visible", true);
273+ compare(dashNavigation.showList, false);
274+ waitForRendering(dashNavigation);
275+ mouseClick(dashNavigation, 0, 0);
276+ compare(dashNavigation.showList, true);
277+
278+ var navigationListView = findChild(dashNavigation, "navigationListView");
279+ compare(navigationListView.count, 1);
280+ tryCompare(navigationListView.currentItem.navigation, "loaded", true);
281+
282+ waitForRendering(navigationListView);
283+ waitForRendering(navigationListView.currentItem);
284+
285+ var allButton = findChild(dashNavigation, "allButton");
287286 compare(allButton.visible, false);
288287
289− var department = findChild(dashDepartments, "department0child3");
290− mouseClick(department, 0, 0);
291− compare(dashDepartments.showList, false);
292− tryCompare(dashDepartments.currentDepartment, "departmentId", "middle3");
293− tryCompare(departmentListView.currentItem.department, "departmentId", "root");
288+ var navigation = findChild(dashNavigation, "navigation0child3");
289+ mouseClick(navigation, 0, 0);
290+ compare(dashNavigation.showList, false);
291+ tryCompare(dashNavigation.currentNavigation, "navigationId", "middle3");
292+ tryCompare(navigationListView.currentItem.navigation, "navigationId", "root");
294293
295− mouseClick(dashDepartments, 0, 0);
296− compare(dashDepartments.showList, true);
297− waitForRendering(departmentListView);
298− waitForRendering(departmentListView.currentItem);
294+ mouseClick(dashNavigation, 0, 0);
295+ compare(dashNavigation.showList, true);
296+ waitForRendering(navigationListView);
297+ waitForRendering(navigationListView.currentItem);
299298 compare(allButton.visible, true);
300299
301300 mouseClick(allButton, 0, 0);
302− compare(dashDepartments.showList, false);
303− tryCompare(dashDepartments.currentDepartment, "departmentId", "root");
304− tryCompare(departmentListView.currentItem.department, "departmentId", "root");
305−
306− mouseClick(dashDepartments, 0, 0);
307− compare(dashDepartments.showList, true);
308− waitForRendering(departmentListView);
309− waitForRendering(departmentListView.currentItem);
301+ compare(dashNavigation.showList, false);
302+ tryCompare(dashNavigation.currentNavigation, "navigationId", "root");
303+ tryCompare(navigationListView.currentItem.navigation, "navigationId", "root");
304+
305+ mouseClick(dashNavigation, 0, 0);
306+ compare(dashNavigation.showList, true);
307+ waitForRendering(navigationListView);
308+ waitForRendering(navigationListView.currentItem);
310309 compare(allButton.visible, false);
311310
312− department = findChild(dashDepartments, "department0child2");
313− mouseClick(department, 0, 0);
314− compare(dashDepartments.showList, true);
315− tryCompare(dashDepartments.currentDepartment, "departmentId", "middle2");
316− tryCompare(departmentListView.currentItem.department, "departmentId", "middle2");
311+ navigation = findChild(dashNavigation, "navigation0child2");
312+ mouseClick(navigation, 0, 0);
313+ compare(dashNavigation.showList, true);
314+ tryCompare(dashNavigation.currentNavigation, "navigationId", "middle2");
315+ tryCompare(navigationListView.currentItem.navigation, "navigationId", "middle2");
317316
318− var departmentList1 = findChild(dashDepartments, "department1");
319− allButton = findChild(departmentList1, "allButton");
320− var backButton = findChild(findChild(departmentList1, "department1"), "backButton");
317+ var navigationList1 = findChild(dashNavigation, "navigation1");
318+ allButton = findChild(navigationList1, "allButton");
319+ var backButton = findChild(findChild(navigationList1, "navigation1"), "backButton");
321320 compare(allButton.visible, true);
322321 compare(backButton.visible, true);
323322
324− tryCompare(departmentListView, "contentX", departmentList1.x);
325− waitForRendering(departmentListView);
323+ tryCompare(navigationListView, "contentX", navigationList1.x);
324+ waitForRendering(navigationListView);
326325 mouseClick(allButton, 0, 0);
327− compare(dashDepartments.showList, false);
328− tryCompare(dashDepartments.currentDepartment, "departmentId", "middle2");
329− tryCompare(departmentListView.currentItem.department, "departmentId", "middle2");
330−
331− mouseClick(dashDepartments, 0, 0);
332− compare(dashDepartments.showList, true);
333− waitForRendering(departmentListView);
334− waitForRendering(departmentListView.currentItem);
326+ compare(dashNavigation.showList, false);
327+ tryCompare(dashNavigation.currentNavigation, "navigationId", "middle2");
328+ tryCompare(navigationListView.currentItem.navigation, "navigationId", "middle2");
329+
330+ mouseClick(dashNavigation, 0, 0);
331+ compare(dashNavigation.showList, true);
332+ waitForRendering(navigationListView);
333+ waitForRendering(navigationListView.currentItem);
335334 compare(allButton.visible, true);
336335 compare(backButton.visible, true);
337336
338− tryCompare(departmentList1.department, "loaded", true);
339− department = findChild(dashDepartments, "department1child2");
340− mouseClick(department, 0, 0);
341− compare(dashDepartments.showList, false);
342− tryCompare(dashDepartments.currentDepartment, "departmentId", "childmiddle22");
343− tryCompare(departmentListView.currentItem.department, "departmentId", "middle2");
344−
345− mouseClick(dashDepartments, 0, 0);
346− compare(dashDepartments.showList, true);
347− waitForRendering(departmentListView);
348− waitForRendering(departmentListView.currentItem);
349−
350− tryCompare(departmentList1.department, "loaded", true);
351− department = findChild(dashDepartments, "department1child3");
352− mouseClick(department, 0, 0);
353− compare(dashDepartments.showList, false);
354− tryCompare(dashDepartments.currentDepartment, "departmentId", "childmiddle23");
355− tryCompare(departmentListView.currentItem.department, "departmentId", "middle2");
356−
357− mouseClick(dashDepartments, 0, 0);
358− compare(dashDepartments.showList, true);
359− waitForRendering(departmentListView);
360− waitForRendering(departmentListView.currentItem);
337+ tryCompare(navigationList1.navigation, "loaded", true);
338+ navigation = findChild(dashNavigation, "navigation1child2");
339+ mouseClick(navigation, 0, 0);
340+ compare(dashNavigation.showList, false);
341+ tryCompare(dashNavigation.currentNavigation, "navigationId", "childmiddle22");
342+ tryCompare(navigationListView.currentItem.navigation, "navigationId", "middle2");
343+
344+ mouseClick(dashNavigation, 0, 0);
345+ compare(dashNavigation.showList, true);
346+ waitForRendering(navigationListView);
347+ waitForRendering(navigationListView.currentItem);
348+
349+ tryCompare(navigationList1.navigation, "loaded", true);
350+ navigation = findChild(dashNavigation, "navigation1child3");
351+ mouseClick(navigation, 0, 0);
352+ compare(dashNavigation.showList, false);
353+ tryCompare(dashNavigation.currentNavigation, "navigationId", "childmiddle23");
354+ tryCompare(navigationListView.currentItem.navigation, "navigationId", "middle2");
355+
356+ mouseClick(dashNavigation, 0, 0);
357+ compare(dashNavigation.showList, true);
358+ waitForRendering(navigationListView);
359+ waitForRendering(navigationListView.currentItem);
361360 mouseClick(backButton, 0, 0);
362361
363− tryCompare(dashDepartments.currentDepartment, "departmentId", "root");
364− tryCompare(departmentListView.currentItem.department, "departmentId", "root");
365− compare(dashDepartments.showList, true);
366− mouseClick(dashDepartments, 0, 0);
367− compare(dashDepartments.showList, false);
368−
369− mouseClick(dashDepartments, 0, 0);
370− compare(dashDepartments.showList, true);
371− tryCompare(departmentListView.currentItem.department, "loaded", true);
372− department = findChild(dashDepartments, "department0child2");
373− mouseClick(department, 0, 0);
374− compare(dashDepartments.showList, true);
375− departmentList1 = findChild(dashDepartments, "department1");
376− compare(departmentList1.department.loaded, false);
377− tryCompare(dashDepartments.currentDepartment, "departmentId", "middle2");
378− allButton = findChild(departmentList1, "allButton");
379− tryCompare(dashDepartments.currentDepartment, "departmentId", "middle2");
362+ tryCompare(dashNavigation.currentNavigation, "navigationId", "root");
363+ tryCompare(navigationListView.currentItem.navigation, "navigationId", "root");
364+ compare(dashNavigation.showList, true);
365+ mouseClick(dashNavigation, 0, 0);
366+ compare(dashNavigation.showList, false);
367+
368+ mouseClick(dashNavigation, 0, 0);
369+ compare(dashNavigation.showList, true);
370+ tryCompare(navigationListView.currentItem.navigation, "loaded", true);
371+ navigation = findChild(dashNavigation, "navigation0child2");
372+ mouseClick(navigation, 0, 0);
373+ compare(dashNavigation.showList, true);
374+ navigationList1 = findChild(dashNavigation, "navigation1");
375+ compare(navigationList1.navigation.loaded, false);
376+ tryCompare(dashNavigation.currentNavigation, "navigationId", "middle2");
377+ allButton = findChild(navigationList1, "allButton");
378+ tryCompare(dashNavigation.currentNavigation, "navigationId", "middle2");
380379 mouseClick(allButton, 0, 0);
381− tryCompare(dashDepartments.currentDepartment, "departmentId", "middle2");
380+ tryCompare(dashNavigation.currentNavigation, "navigationId", "middle2");
382381 }
383382 }
384383}
tests/qmltests/Dash/tst_GenericScopeView.qml+3−2
@@ -129,8 +129,9 @@ Item {
129129 var initialHeight = category.height;
130130 mouseClick(seeAll, seeAll.width / 2, seeAll.height / 2);
131131 verify(category.expanded);
132− tryCompareFunction(function() { return category.height > initialHeight; }, true);
132+ tryCompare(category, "height", category.item.expandedHeight + seeAll.height);
133133
134+ waitForRendering(seeAll);
134135 mouseClick(seeAll, seeAll.width / 2, seeAll.height / 2);
135136 verify(!category.expanded);
136137 }
@@ -319,7 +320,7 @@ Item {
319320 units.gu(2),
320321 testCase.previewListView.height / 2);
321322 tryCompare(previewListViewList, "moving", false);
322− tryCompare(testCase.previewListView.currentItem, "objectName", "previewItem" + i);
323+ tryCompare(testCase.previewListView.currentItem, "objectName", "preview" + i);
323324
324325 }
325326 closePreview();
tests/qmltests/Panel/Indicators/tst_MenuItemFactory.qml+47
@@ -112,6 +112,7 @@ Item {
112112
113113 { tag: 'wifisection', type: "unity.widgets.systemsettings.tablet.wifisection", objectName: "wifiSection" },
114114 { tag: 'accesspoint', type: "unity.widgets.systemsettings.tablet.accesspoint", objectName: "accessPoint" },
115+ { tag: 'modeminfoitem', type: "com.canonical.indicator.network.modeminfoitem", objectName: "modemInfoItem" },
115116
116117 { tag: 'unknown', type: "", objectName: "standardMenu"}
117118 ];
@@ -542,6 +543,52 @@ Item {
542543 compare(loader.item.enabled, data.enabled, "Enabled does not match data");
543544 }
544545
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+
545592 function test_create_messageItem() {
546593 menuData.type = "com.canonical.indicator.messages.messageitem";
547594