on xenial help sign in
Merge from trunk
commit422481342c8f0d57c0f922e632166c94760ea011 authorMichael Terry <michael.terry@canonical.com> dateWed 14 Jan 2015, 22:03 (12 years ago) parent3b088699c258fb
109 files changed+2208−810
build.sh+4−1 cmake/modules/QmlTest.cmake+3 debian/changelog+75 debian/control+7−5 plugins/Dash/CardCreator.js+1−1 plugins/LightDM/CMakeLists.txt+1−1 plugins/LightDM/UsersModel.cpp+1−1 plugins/LightDM/UsersModel.h+2−2 plugins/Lights/Lights.cpp+9−24 plugins/Unity/DashCommunicator/dashconnection.cpp+30 plugins/Unity/DashCommunicator/dashconnection.h+4−1 plugins/Unity/Indicators/CMakeLists.txt+3−1 plugins/Unity/Indicators/Indicators.qmltypes+18−7 plugins/Unity/Indicators/actionrootstate.cpp+97 plugins/Unity/Indicators/actionrootstate.h+55 plugins/Unity/Indicators/modelactionrootstate.cpp+127 plugins/Unity/Indicators/modelactionrootstate.h+61 plugins/Unity/Indicators/plugin.cpp+4−2 plugins/Unity/Indicators/rootactionstate.cpp → plugins/Unity/Indicators/rootstateparser.cpp+74−141 plugins/Unity/Indicators/rootactionstate.h → plugins/Unity/Indicators/rootstateparser.h+18−34 plugins/Utils/CMakeLists.txt+1−1 plugins/Utils/plugin.cpp+2−2 plugins/Utils/qsortfilterproxymodelqml.cpp → plugins/Utils/unitysortfilterproxymodelqml.cpp+15−15 plugins/Utils/qsortfilterproxymodelqml.h → plugins/Utils/unitysortfilterproxymodelqml.h+5−5 po/ca.po+43−39 po/fa.po+96−88 po/nl.po+49−42 qml/Dash/Dash.qml+6−12 qml/Dash/DashContent.qml+2−2 qml/Dash/DashNavigation.qml+4 qml/Dash/DashNavigationButton.qml+2 qml/Dash/GenericScopeView.qml+33−5 qml/Dash/ScopesList.qml+1 qml/Greeter/Clock.qml+1−1 qml/Greeter/Infographics.qml+9−7 qml/Greeter/NarrowGreeter.qml+1−1 qml/Notifications/Notifications.qml+1−1 qml/Panel/IndicatorItem.qml−8 qml/Panel/Indicators/IndicatorBase.qml+1−1 qml/Panel/Indicators/IndicatorsLight.qml+19−1 qml/Panel/Indicators/VisibleIndicators.qml+2−2 qml/Panel/IndicatorsMenu.qml+5 qml/Shell.qml+20−2 src/libunity8-private/abstractdbusservicemonitor.cpp+21−8 src/libunity8-private/abstractdbusservicemonitor.h+9−5 src/main.cpp−6 tests/autopilot/unity8/shell/emulators/create_interactive_notification.py−1 tests/autopilot/unity8/shell/emulators/edges_demo.py+140 tests/autopilot/unity8/shell/fixture_setup.py+38 tests/autopilot/unity8/shell/tests/test_edges_demo.py+52 tests/mocks/CMakeLists.txt+1 tests/mocks/LightDM/CMakeLists.txt+1−1 tests/mocks/LightDM/Greeter.cpp+6 tests/mocks/LightDM/Greeter.h+3 tests/mocks/LightDM/demo/CMakeLists.txt+1 tests/mocks/Lights/CMakeLists.txt+8 tests/mocks/Lights/Lights.cpp+84 tests/mocks/Lights/Lights.h+66 tests/mocks/Lights/Lights.qmltypes+45 tests/mocks/Lights/plugin.cpp+33 tests/mocks/Lights/plugin.h+32 tests/mocks/Lights/qmldir+3 tests/mocks/QMenuModel/CMakeLists.txt+1 tests/mocks/QMenuModel/QDBusActionGroup.qml+20−67 tests/mocks/QMenuModel/actiondata.h+52 tests/mocks/QMenuModel/plugin.cpp+10 tests/mocks/Unity/Indicators/ActionRootState.qml+46 tests/mocks/Unity/Indicators/RootActionState.qml → tests/mocks/Unity/Indicators/ModelActionRootState.qml tests/mocks/Unity/Indicators/qmldir+2−1 tests/plugins/LightDM/CMakeLists.txt+4−8 tests/plugins/LightDM/dbus.cpp+11−2 tests/plugins/Unity/Indicators/rootactionstatetest.cpp+4−4 tests/plugins/Utils/CMakeLists.txt+1−1 tests/plugins/Utils/qsortfilterproxymodeltest.cpp → tests/plugins/Utils/unitysortfilterproxymodeltest.cpp+14−14 tests/qmltests/CMakeLists.txt+1 tests/qmltests/Components/tst_Carousel.qml+5−5 tests/qmltests/Components/tst_Lockscreen.qml+1−1 tests/qmltests/Components/tst_ResponsiveVerticalJournal.qml+1−1 tests/qmltests/Dash/Previews/tst_PreviewActions.qml+3−3 tests/qmltests/Dash/Previews/tst_PreviewAudioPlayback.qml+5−5 tests/qmltests/Dash/Previews/tst_PreviewExpandable.qml+2−2 tests/qmltests/Dash/Previews/tst_PreviewImageGallery.qml+6−6 tests/qmltests/Dash/Previews/tst_PreviewPayments.qml+5−5 tests/qmltests/Dash/Previews/tst_PreviewRatingDisplay.qml+1−1 tests/qmltests/Dash/Previews/tst_PreviewRatingInput.qml+2−2 tests/qmltests/Dash/Previews/tst_PreviewZoomableImage.qml+2−2 tests/qmltests/Dash/ScopeSettings/tst_ScopeSettingBoolean.qml+2−2 tests/qmltests/Dash/ScopeSettings/tst_ScopeSettingNumber.qml+3−3 tests/qmltests/Dash/ScopeSettings/tst_ScopeSettingString.qml+2−2 tests/qmltests/Dash/tst_Card.qml+4−4 tests/qmltests/Dash/tst_Dash.qml+42−25 tests/qmltests/Dash/tst_DashContent.qml+105−27 tests/qmltests/Dash/tst_GenericScopeView.qml+26−26 tests/qmltests/Dash/tst_PageHeader.qml+1−1 tests/qmltests/Dash/tst_PreviewListView.qml+2−2 tests/qmltests/Launcher/tst_Launcher.qml+8−8 tests/qmltests/Notifications/tst_Notifications.qml+6−6 tests/qmltests/Notifications/tst_OptionToggle.qml+7−7 tests/qmltests/Notifications/tst_SwipeToAct.qml+1−1 tests/qmltests/Notifications/tst_VisualSnapDecisionsQueue.qml+2−2 tests/qmltests/Panel/Indicators/tst_IndicatorsLight.qml+129 tests/qmltests/Panel/Indicators/tst_MenuItemFactory.qml+52−1 tests/qmltests/Panel/tst_IndicatorsBar.qml+1−1 tests/qmltests/Stages/tst_PhoneStage.qml+2 tests/qmltests/Wizard/tst_Wizard.qml+36−12 tests/qmltests/tst_Shell.qml+3−3 tests/qmltests/tst_ShellWithPin.qml+31 tests/qmltests/tst_TabletShell.qml+1−1 tests/utils/modules/Unity/Test/UnityTestCase.qml+88−69
build.sh+4−1
@@ -61,7 +61,10 @@ install_dependencies() {
6161}
6262
6363mk_build_deps() {
64− [ ! -f unity8-build-deps*deb -o $CODE_DIR/debian/control -nt unity8-build-deps*deb ] && mk-build-deps --install --root-cmd sudo $CODE_DIR/debian/control
64+ if [ ! -f control -o $CODE_DIR/debian/control -nt control ]; then
65+ sed 's/\:native//g' $CODE_DIR/debian/control > control
66+ mk-build-deps --install --root-cmd sudo control
67+ fi
6568}
6669
6770if [ -f "/usr/bin/ccache" ] ; then
cmake/modules/QmlTest.cmake+3
@@ -153,7 +153,9 @@ endmacro(add_qml_test_internal)
153153
154154macro(add_binary_qml_test CLASS_NAME LD_PATH DEPS ENVVAR)
155155 set(testCommand
156+ ${ENVVAR}
156157 LD_LIBRARY_PATH=${LD_PATH}
158+ dbus-launch
157159 ${CMAKE_CURRENT_BINARY_DIR}/${CLASS_NAME}TestExec
158160 -o ${CMAKE_BINARY_DIR}/test${CLASS_NAME}.xml,xunitxml
159161 -o -,txt)
@@ -171,6 +173,7 @@ macro(add_binary_qml_test CLASS_NAME LD_PATH DEPS ENVVAR)
171173 ${ENVVAR}
172174 LD_LIBRARY_PATH=${LD_PATH}
173175 xvfb-run --server-args "-screen 0 1024x768x24" --auto-servernum
176+ dbus-launch
174177 ${CMAKE_CURRENT_BINARY_DIR}/${CLASS_NAME}TestExec
175178 -o ${CMAKE_BINARY_DIR}/test${CLASS_NAME}.xml,xunitxml
176179 -o -,txt)
debian/changelog+75
@@ -1,3 +1,78 @@
1+unity8 (8.02+15.04.20150113.1-0ubuntu1) vivid; urgency=low
2+
3+ [ Andrea Cimitan ]
4+ * support background on horizontal cards with summary (LP: #1393008)
5+
6+ [ Gerry Boland ]
7+ * DashCommunicator: replace QDBusInterface with a non-blocking
8+ simplification which does not introspect the service on creation
9+ (LP: #1403508)
10+
11+ [ Leo Arias ]
12+ * Added an autopilot test for the edges demo.
13+
14+ [ Albert Astals ]
15+ * Don't show the manage dash pull up arrow on temp scopes (LP:
16+ #1401869)
17+ * Remove hack, newer Qt already support keyClick(char)
18+ * Tests: Add Qt 5.5 removal TODOs
19+ * Make sure we use fPIC when compiling files for the static library
20+ too
21+ * Make sure changing a scope doesn't trigger creation/destruction of
22+ delegates until it's finished (LP: #1410122)
23+
24+ [ Michael Zanetti ]
25+ * patch debian/control file before using it to make it work with mk-
26+ build-deps
27+
28+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 13 Jan 2015 20:58:08 +0000
29+
30+unity8 (8.02+15.04.20150109.2-0ubuntu1) vivid; urgency=low
31+
32+ [ Michał Sawicz ]
33+ * We don't need the SIGSTOP in main() any more.
34+ * Add a test to make sure the shell always starts disabled until it is
35+ enabled by a complete PAM interaction.
36+
37+ [ Leo Arias ]
38+ * Added an autopilot test for the edges demo.
39+
40+ [ Nick Dedekind ]
41+ * Unhook Lights interface from indicator widgets (LP: #1385331)
42+
43+ [ Albert Astals ]
44+ * Fix going to scopes when the Manage Dash is open (LP: #1403464)
45+ * QSortFilterProxyModelQML -> UnitySortFilterProxyModelQML
46+ * Clip the Scopes List header
47+ * Fix ScopesList not being under finger
48+ * Make waitForRendering with no item fail instead of crash
49+ * Disable Dash horizontal scroll while Navigation InverseMouseArea is
50+ pressed (LP: #1403048)
51+ * Test: Make sure the mouse area is enabled before clicking into it
52+ * Test: We actually need to click on the customBackButton and not on
53+ backButton
54+ * Test: By default mouseX act on the middle
55+
56+ [ Michael Terry ]
57+ * Don't block handling power events on loading the greeter's qml and
58+ the background image.
59+ * Show OSK above the wizard. (LP: #1401213)
60+ * Unify the name of the Greeter DBus test, make it use our standard
61+ binary test macro (which also nicely exports xml results), and make
62+ the test a little more robust against timing issues.
63+ * Add a test to make sure the shell always starts disabled until it is
64+ enabled by a complete PAM interaction.
65+
66+ [ Martin Pitt ]
67+ * tests: Fix Notify.Notification.add_action invocation to work also
68+ with unpatched libnotify API. (LP: #1223401)
69+
70+ [ Rodney Dawes ]
71+ * Depend on :native version of g++ to allow cross-compiling to work.
72+ (LP: #1353855)
73+
74+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Fri, 09 Jan 2015 10:43:06 +0000
75+
176unity8 (8.02+15.04.20141216.1-0ubuntu1) vivid; urgency=low
277
378 [ Ubuntu daily release ]
debian/control+7−5
@@ -10,8 +10,10 @@ Build-Depends: cmake,
1010 gsettings-ubuntu-schemas (>= 0.0.2+14.10.20140815),
1111# We rely on C++11 features, and to prevent from ABI breaks
1212# in libstdc++ causing us issues, we explicitly select a G++
13−# version.
14− g++-4.9,
13+# version. To allow cross-compiling to work, we also must
14+# append :native to g++-4.9 so we don't try to run armhf g++
15+# on an x86 CPU for eaxmple, when cross-compiling.
16+ g++-4.9:native,
1517 libconnectivity-qt1-dev,
1618 libgl1-mesa-dev[!armhf] | libgl-dev[!armhf],
1719 libgl1-mesa-dri,
@@ -22,7 +24,7 @@ Build-Depends: cmake,
2224 libpam0g-dev,
2325 libpay2-dev,
2426 libpulse-dev,
25− libqmenumodel-dev (>= 0.2.8),
27+ libqmenumodel-dev (>= 0.2.9),
2628 libqt5xmlpatterns5-dev,
2729 libsystemsettings-dev,
2830 libunity-api-dev (>= 7.94),
@@ -61,7 +63,7 @@ X-Ubuntu-Use-Langpack: yes
6163
6264Package: indicators-client
6365Architecture: amd64 armhf i386
64−Depends: qmenumodel-qml (>= 0.2.8),
66+Depends: qmenumodel-qml (>= 0.2.9),
6567 qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.1.1239) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.1.1239),
6668 unity8 (= ${binary:Version}),
6769 ${misc:Depends},
@@ -85,7 +87,7 @@ Provides: indicator-renderer,
8587Depends: gsettings-desktop-schemas,
8688 libcap2-bin,
8789 libglib2.0-bin,
88− qmenumodel-qml (>= 0.2.8),
90+ qmenumodel-qml (>= 0.2.9),
8991 qml-module-qt-labs-folderlistmodel,
9092 qml-module-qtquick-xmllistmodel,
9193 qtdeclarative5-gsettings1.0,
plugins/Dash/CardCreator.js+1−1
@@ -320,7 +320,7 @@ function cardString(template, components) {
320320 var hasSummary = components["summary"] || false;
321321 var artAndSummary = hasArt && hasSummary;
322322 var isHorizontal = template["card-layout"] === "horizontal";
323− var hasBackground = !isHorizontal && (template["card-background"] || components["background"] || artAndSummary);
323+ var hasBackground = (hasSummary || !isHorizontal) && (template["card-background"] || components["background"] || artAndSummary);
324324 var hasTitle = components["title"] || false;
325325 var hasMascot = components["mascot"] || false;
326326 var hasEmblem = components["emblem"] && !(hasMascot && template["card-size"] === "small") || false;
plugins/LightDM/CMakeLists.txt+1−1
@@ -15,7 +15,7 @@ include_directories(
1515)
1616
1717set(QMLPLUGIN_SRC
18− ../Utils/qsortfilterproxymodelqml.cpp # FIXME evaluate a more generic approach for using other plugins
18+ ../Utils/unitysortfilterproxymodelqml.cpp # FIXME evaluate a more generic approach for using other plugins
1919 DBusGreeter.cpp
2020 DBusGreeterList.cpp
2121 Greeter.cpp
plugins/LightDM/UsersModel.cpp+1−1
@@ -58,7 +58,7 @@ QVariant MangleModel::data(const QModelIndex &index, int role) const
5858// **** Now we continue with actual UsersModel class ****
5959
6060UsersModel::UsersModel(QObject* parent)
61− : QSortFilterProxyModelQML(parent)
61+ : UnitySortFilterProxyModelQML(parent)
6262{
6363 setModel(new MangleModel(this));
6464 setSortCaseSensitivity(Qt::CaseInsensitive);
plugins/LightDM/UsersModel.h+2−2
@@ -23,10 +23,10 @@
2323#ifndef UNITY_USERSMODEL_H
2424#define UNITY_USERSMODEL_H
2525
26−#include <qsortfilterproxymodelqml.h>
26+#include <unitysortfilterproxymodelqml.h>
2727#include <QtCore/QObject>
2828
29−class UsersModel : public QSortFilterProxyModelQML
29+class UsersModel : public UnitySortFilterProxyModelQML
3030{
3131 Q_OBJECT
3232
plugins/Lights/Lights.cpp+9−24
@@ -44,12 +44,20 @@ Lights::~Lights()
4444
4545void Lights::setState(Lights::State newState)
4646{
47+ if (!init()) {
48+ qWarning() << "No lights device";
49+ return;
50+ }
51+
4752 if (m_state != newState) {
4853 if (newState == Lights::On) {
4954 turnOn();
5055 } else {
5156 turnOff();
5257 }
58+
59+ m_state = newState;
60+ Q_EMIT stateChanged(m_state);
5361 }
5462}
5563
@@ -115,6 +123,7 @@ bool Lights::init()
115123 err = module->methods->open(module, LIGHT_ID_NOTIFICATIONS, &device);
116124 if (err == 0) {
117125 m_lightDevice = (light_device_t*)device;
126+ turnOff();
118127 return true;
119128 } else {
120129 qWarning() << "Failed to access notification lights";
@@ -127,15 +136,6 @@ bool Lights::init()
127136
128137void Lights::turnOn()
129138{
130− if (!init()) {
131− qWarning() << "No lights device";
132− return;
133− }
134−
135− if (m_state == Lights::On) {
136− return;
137− }
138−
139139 // pulse
140140 light_state_t state;
141141 memset(&state, 0, sizeof(light_state_t));
@@ -147,23 +147,11 @@ void Lights::turnOn()
147147
148148 if (m_lightDevice->set_light(m_lightDevice, &state) != 0) {
149149 qWarning() << "Failed to turn the light off";
150− } else {
151− m_state = Lights::On;
152− Q_EMIT stateChanged(m_state);
153150 }
154151}
155152
156153void Lights::turnOff()
157154{
158− if (!init()) {
159− qWarning() << "No lights device";
160− return;
161− }
162−
163− if (m_state == Lights::Off) {
164− return;
165− }
166−
167155 light_state_t state;
168156 memset(&state, 0, sizeof(light_state_t));
169157 state.color = 0x00000000;
@@ -174,8 +162,5 @@ void Lights::turnOff()
174162
175163 if (m_lightDevice->set_light(m_lightDevice, &state) != 0) {
176164 qWarning() << "Failed to turn the light off";
177− } else {
178− m_state = Lights::Off;
179− Q_EMIT stateChanged(m_state);
180165 }
181166}
plugins/Unity/DashCommunicator/dashconnection.cpp+30
@@ -19,12 +19,42 @@
1919#include <QDBusInterface>
2020#include <QDBusPendingCall>
2121
22+/* The default implementation of AbstractDBusServiceMonitor creates a QDBusInterface when the service
23+ * appears on the bus.
24+ *
25+ * On construction QDBusInterface synchronously introspects the service, which will block the GUI
26+ * thread of this process if the service is busy. QDBusAbstractInterface does not perform this
27+ * introspection, so let's subclass that and avoid the blocking scenario.
28+ *
29+ * However we lose Qt's wrapping of the DBus service with a MetaObject, with the result that we
30+ * cannot easily connect to DBus signals with the usual connect() calls. So this approach only
31+ * suited to push communication with the DBus service.
32+ */
33+class AsyncDBusInterface : public QDBusAbstractInterface
34+{
35+public:
36+ AsyncDBusInterface(const QString &service, const QString &path,
37+ const QString &interface, const QDBusConnection &connection,
38+ QObject *parent = 0)
39+ : QDBusAbstractInterface(service, path, interface.toLatin1().data(), connection, parent)
40+ {}
41+ ~AsyncDBusInterface() = default;
42+};
43+
44+
2245DashConnection::DashConnection(const QString &service, const QString &path, const QString &interface, QObject *parent):
2346 AbstractDBusServiceMonitor(service, path, interface, SessionBus, parent)
2447{
2548
2649}
2750
51+/* Override the default implementation to create a non-blocking DBus interface (see note above). */
52+QDBusAbstractInterface* DashConnection::createInterface(const QString &service, const QString &path,
53+ const QString &interface, const QDBusConnection &connection)
54+{
55+ return new AsyncDBusInterface(service, path, interface, connection);
56+}
57+
2858void DashConnection::setCurrentScope(int index, bool animate, bool isSwipe)
2959{
3060 if (dbusInterface()) {
plugins/Unity/DashCommunicator/dashconnection.h+4−1
@@ -20,7 +20,6 @@
2020// local
2121#include "abstractdbusservicemonitor.h"
2222
23−
2423class DashConnection: public AbstractDBusServiceMonitor
2524{
2625 Q_OBJECT
@@ -29,6 +28,10 @@ public:
2928
3029public Q_SLOTS:
3130 void setCurrentScope(int index, bool animate, bool isSwipe);
31+
32+private:
33+ QDBusAbstractInterface* createInterface(const QString &service, const QString &path,
34+ const QString &interface, const QDBusConnection &connection) override;
3235};
3336
3437#endif
plugins/Unity/Indicators/CMakeLists.txt+3−1
@@ -16,14 +16,16 @@ include_directories(
1616)
1717
1818set(IndicatorsQML_SOURCES
19+ actionrootstate.cpp
1920 indicator.cpp
2021 indicators.h
2122 indicatorsmanager.cpp
2223 indicatorsmodel.cpp
2324 menucontentactivator.cpp
25+ modelactionrootstate.cpp
2426 modelprinter.cpp
2527 plugin.cpp
26− rootactionstate.cpp
28+ rootstateparser.cpp
2729 sharedunitymenumodel.cpp
2830 unitymenumodelcache.cpp
2931 unitymenumodelstack.cpp
plugins/Unity/Indicators/Indicators.qmltypes+18−7
@@ -7,6 +7,14 @@ import QtQuick.tooling 1.1
77// 'qmlplugindump -notrelocatable Unity.Indicators 0.1 plugins'
88
99Module {
10+ Component {
11+ name: "ActionRootState"
12+ prototype: "RootStateObject"
13+ exports: ["Unity.Indicators/ActionRootState 0.1"]
14+ exportMetaObjectRevisions: [0]
15+ Property { name: "actionGroup"; type: "QDBusActionGroup"; isPointer: true }
16+ Property { name: "actionName"; type: "string" }
17+ }
1018 Component {
1119 name: "ActionState"
1220 prototype: "QObject"
@@ -23,7 +31,6 @@ Module {
2331 }
2432 }
2533 }
26− Component { name: "ActionStateParser"; prototype: "QObject" }
2734 Component {
2835 name: "FlatMenuProxyModelRole"
2936 prototype: "QObject"
@@ -146,6 +153,14 @@ Module {
146153 exportMetaObjectRevisions: [0]
147154 Property { name: "active"; type: "bool"; isReadonly: true }
148155 }
156+ Component {
157+ name: "ModelActionRootState"
158+ prototype: "RootStateObject"
159+ exports: ["Unity.Indicators/ModelActionRootState 0.1"]
160+ exportMetaObjectRevisions: [0]
161+ Property { name: "menu"; type: "UnityMenuModel"; isPointer: true }
162+ Signal { name: "indexChanged" }
163+ }
149164 Component {
150165 name: "ModelPrinter"
151166 prototype: "QObject"
@@ -192,11 +207,8 @@ Module {
192207 }
193208 Component { name: "QIdentityProxyModel"; prototype: "QAbstractProxyModel" }
194209 Component {
195− name: "RootActionState"
196− prototype: "ActionStateParser"
197− exports: ["Unity.Indicators/RootActionState 0.1"]
198− exportMetaObjectRevisions: [0]
199− Property { name: "menu"; type: "UnityMenuModel"; isPointer: true }
210+ name: "RootStateObject"
211+ prototype: "QObject"
200212 Property { name: "valid"; type: "bool"; isReadonly: true }
201213 Property { name: "title"; type: "string"; isReadonly: true }
202214 Property { name: "leftLabel"; type: "string"; isReadonly: true }
@@ -205,7 +217,6 @@ Module {
205217 Property { name: "accessibleName"; type: "string"; isReadonly: true }
206218 Property { name: "visible"; type: "bool"; isReadonly: true }
207219 Signal { name: "updated" }
208− Signal { name: "indexChanged" }
209220 }
210221 Component {
211222 name: "SharedUnityMenuModel"
plugins/Unity/Indicators/actionrootstate.cppnew 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 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+#include "actionrootstate.h"
18+
19+#include <qdbusactiongroup.h>
20+#include <QDebug>
21+
22+ActionRootState::ActionRootState(QObject *parent)
23+ : RootStateObject(parent)
24+ , m_actionGroup(nullptr)
25+{
26+}
27+
28+QDBusActionGroup *ActionRootState::actionGroup() const
29+{
30+ return m_actionGroup;
31+}
32+
33+void ActionRootState::setActionGroup(QDBusActionGroup *actionGroup)
34+{
35+ if (m_actionGroup != actionGroup) {
36+ bool wasValid = valid();
37+
38+ if (m_actionGroup) {
39+ disconnect(m_actionGroup, 0, this, 0);
40+ }
41+ m_actionGroup = actionGroup;
42+
43+ if (m_actionGroup) {
44+ connect(m_actionGroup, &QDBusActionGroup::statusChanged, this, [&](bool) { updateActionState(); });
45+ connect(m_actionGroup, &QDBusActionGroup::actionAppear, this, [&](const QString&) { updateActionState(); });
46+ connect(m_actionGroup, &QDBusActionGroup::actionVanish, this, [&](const QString&) { updateActionState(); });
47+ connect(m_actionGroup, &QDBusActionGroup::actionStateChanged, this, [&](QVariant) { updateActionState(); });
48+
49+ connect(m_actionGroup, &QObject::destroyed, this, [&](QObject*) { updateActionState(); });
50+ }
51+ updateActionState();
52+ Q_EMIT actionGroupChanged();
53+
54+ if (wasValid != valid()) Q_EMIT validChanged();
55+ }
56+}
57+
58+QString ActionRootState::actionName() const
59+{
60+ return m_actionName;
61+}
62+
63+void ActionRootState::setActionName(const QString &actionName)
64+{
65+ if (m_actionName != actionName) {
66+ bool wasValid = valid();
67+
68+ m_actionName = actionName;
69+ updateActionState();
70+
71+ Q_EMIT actionNameChanged();
72+
73+ if (wasValid != valid()) Q_EMIT validChanged();
74+ }
75+}
76+
77+bool ActionRootState::valid() const
78+{
79+ return m_actionGroup && m_actionGroup->status() == DBusEnums::Connected &&
80+ !m_actionName.isEmpty() && m_actionGroup->hasAction(m_actionName);
81+}
82+
83+void ActionRootState::updateActionState()
84+{
85+ if (valid()) {
86+ ActionStateParser* oldParser = m_actionGroup->actionStateParser();
87+ m_actionGroup->setActionStateParser(&m_parser);
88+
89+ QVariantMap state = m_actionGroup->actionState(m_actionName).toMap();
90+
91+ m_actionGroup->setActionStateParser(oldParser);
92+
93+ setCurrentState(state);
94+ } else {
95+ setCurrentState(QVariantMap());
96+ }
97+}
plugins/Unity/Indicators/actionrootstate.hnew file+55
@@ -0,0 +1,55 @@
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+#ifndef ACTIONROOTSTATE_H
18+#define ACTIONROOTSTATE_H
19+
20+#include "unityindicatorsglobal.h"
21+
22+#include "rootstateparser.h"
23+
24+class QDBusActionGroup;
25+
26+class UNITYINDICATORS_EXPORT ActionRootState : public RootStateObject
27+{
28+ Q_OBJECT
29+ Q_PROPERTY(QDBusActionGroup* actionGroup READ actionGroup WRITE setActionGroup NOTIFY actionGroupChanged)
30+ Q_PROPERTY(QString actionName READ actionName WRITE setActionName NOTIFY actionNameChanged)
31+
32+public:
33+ ActionRootState(QObject *parent = 0);
34+
35+ QDBusActionGroup *actionGroup() const;
36+ void setActionGroup(QDBusActionGroup *actionGroup);
37+
38+ QString actionName() const;
39+ void setActionName(const QString& actionName);
40+
41+ bool valid() const override;
42+
43+Q_SIGNALS:
44+ void actionGroupChanged();
45+ void actionNameChanged();
46+
47+private Q_SLOTS:
48+ void updateActionState();
49+
50+private:
51+ QDBusActionGroup* m_actionGroup;
52+ QString m_actionName;
53+};
54+
55+#endif // ACTIONROOTSTATE_H
plugins/Unity/Indicators/modelactionrootstate.cppnew file+127
@@ -0,0 +1,127 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Nick Dedekind <nick.dedekind@canonical.com>
18+ */
19+
20+#include "modelactionrootstate.h"
21+#include "indicators.h"
22+
23+#include <unitymenumodel.h>
24+#include <QVariant>
25+#include <QIcon>
26+
27+extern "C" {
28+#include <glib.h>
29+#include <gio/gio.h>
30+}
31+
32+ModelActionRootState::ModelActionRootState(QObject *parent)
33+ : RootStateObject(parent),
34+ m_menu(nullptr)
35+{
36+}
37+
38+ModelActionRootState::~ModelActionRootState()
39+{
40+}
41+
42+UnityMenuModel* ModelActionRootState::menu() const
43+{
44+ return m_menu;
45+}
46+
47+void ModelActionRootState::setMenu(UnityMenuModel* menu)
48+{
49+ if (m_menu != menu) {
50+ bool wasValid = valid();
51+
52+ if (m_menu) {
53+ m_menu->disconnect(this);
54+ }
55+ m_menu = menu;
56+
57+ if (m_menu) {
58+ connect(m_menu, SIGNAL(rowsInserted(const QModelIndex&, int, int)), SLOT(onModelRowsAdded(const QModelIndex&, int, int)));
59+ connect(m_menu, SIGNAL(rowsRemoved(const QModelIndex&, int, int)), SLOT(onModelRowsRemoved(const QModelIndex&, int, int)));
60+ connect(m_menu, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&)), SLOT(onModelDataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&)));
61+
62+ connect(m_menu, SIGNAL(destroyed()), SLOT(reset()));
63+ }
64+ updateActionState();
65+ Q_EMIT menuChanged();
66+
67+ if (wasValid != valid())
68+ Q_EMIT validChanged();
69+ }
70+}
71+
72+bool ModelActionRootState::valid() const
73+{
74+ return m_menu && m_menu->rowCount() > 0;
75+}
76+
77+void ModelActionRootState::onModelRowsAdded(const QModelIndex& parent, int start, int end)
78+{
79+ Q_UNUSED(parent);
80+ if (start == 0 && end >= 0) {
81+ updateActionState();
82+ }
83+}
84+
85+void ModelActionRootState::onModelRowsRemoved(const QModelIndex& parent, int start, int end)
86+{
87+ Q_UNUSED(parent);
88+ if (start == 0 && end >= 0) {
89+ updateActionState();
90+ }
91+}
92+
93+void ModelActionRootState::onModelDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>& roles)
94+{
95+ Q_UNUSED(roles);
96+ if (!topLeft.isValid() || !bottomRight.isValid()) {
97+ return;
98+ }
99+
100+ if (topLeft.row() <= 0 && bottomRight.row() >= 0) {
101+ updateActionState();
102+ }
103+}
104+
105+void ModelActionRootState::reset()
106+{
107+ m_menu = nullptr;
108+
109+ Q_EMIT menuChanged();
110+ setCurrentState(QVariantMap());
111+}
112+
113+void ModelActionRootState::updateActionState()
114+{
115+ if (m_menu && m_menu->rowCount() > 0) {
116+ ActionStateParser* oldParser = m_menu->actionStateParser();
117+ m_menu->setActionStateParser(&m_parser);
118+
119+ QVariantMap state = m_menu->get(0, "actionState").toMap();
120+
121+ m_menu->setActionStateParser(oldParser);
122+
123+ setCurrentState(state);
124+ } else {
125+ setCurrentState(QVariantMap());
126+ }
127+}
plugins/Unity/Indicators/modelactionrootstate.hnew file+61
@@ -0,0 +1,61 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Nick Dedekind <nick.dedekind@canonical.com>
18+ */
19+
20+#ifndef MODELACTIONROOTSTATE_H
21+#define MODELACTIONROOTSTATE_H
22+
23+#include "unityindicatorsglobal.h"
24+
25+#include "rootstateparser.h"
26+
27+class UnityMenuModel;
28+
29+class UNITYINDICATORS_EXPORT ModelActionRootState : public RootStateObject
30+{
31+ Q_OBJECT
32+ Q_PROPERTY(UnityMenuModel* menu READ menu WRITE setMenu NOTIFY menuChanged)
33+public:
34+ ModelActionRootState(QObject *parent = 0);
35+ virtual ~ModelActionRootState();
36+
37+ UnityMenuModel* menu() const;
38+ void setMenu(UnityMenuModel* menu);
39+
40+ int index() const;
41+ void setIndex(int index);
42+
43+ bool valid() const override;
44+
45+Q_SIGNALS:
46+ void menuChanged();
47+ void indexChanged();
48+
49+private Q_SLOTS:
50+ void onModelRowsAdded(const QModelIndex& parent, int start, int end);
51+ void onModelRowsRemoved(const QModelIndex& parent, int start, int end);
52+ void onModelDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>&);
53+ void reset();
54+
55+private:
56+ void updateActionState();
57+
58+ UnityMenuModel* m_menu;
59+};
60+
61+#endif // MODELACTIONROOTSTATE_H
plugins/Unity/Indicators/plugin.cpp+4−2
@@ -24,12 +24,13 @@
2424#include "plugin.h"
2525
2626// local
27+#include "actionrootstate.h"
2728#include "indicators.h"
2829#include "indicatorsmanager.h"
2930#include "indicatorsmodel.h"
3031#include "menucontentactivator.h"
32+#include "modelactionrootstate.h"
3133#include "modelprinter.h"
32−#include "rootactionstate.h"
3334#include "sharedunitymenumodel.h"
3435#include "unitymenumodelcache.h"
3536#include "unitymenumodelstack.h"
@@ -51,7 +52,8 @@ void IndicatorsPlugin::registerTypes(const char *uri)
5152 qmlRegisterType<IndicatorsModel>(uri, 0, 1, "IndicatorsModel");
5253 qmlRegisterType<MenuContentActivator>(uri, 0, 1, "MenuContentActivator");
5354 qmlRegisterType<UnityMenuModelStack>(uri, 0, 1, "UnityMenuModelStack");
54− qmlRegisterType<RootActionState>(uri, 0, 1, "RootActionState");
55+ qmlRegisterType<ModelActionRootState>(uri, 0, 1, "ModelActionRootState");
56+ qmlRegisterType<ActionRootState>(uri, 0, 1, "ActionRootState");
5557 qmlRegisterType<ModelPrinter>(uri, 0, 1, "ModelPrinter");
5658 qmlRegisterType<VisibleIndicatorsModel>(uri, 0, 1, "VisibleIndicatorsModel");
5759 qmlRegisterType<SharedUnityMenuModel>(uri, 0, 1, "SharedUnityMenuModel");
plugins/Unity/Indicators/rootactionstate.cpp → plugins/Unity/Indicators/rootstateparser.cpprenamed+74−141
@@ -12,155 +12,18 @@
1212 *
1313 * You should have received a copy of the GNU Lesser General Public License
1414 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Authors:
17− * Nick Dedekind <nick.dedekind@canonical.com>
1815 */
1916
20−#include "rootactionstate.h"
21−#include "indicators.h"
22−
23−#include <unitymenumodel.h>
24−#include <QVariant>
25−#include <QIcon>
17+#include "rootstateparser.h"
2618
2719extern "C" {
2820#include <glib.h>
2921#include <gio/gio.h>
3022}
3123
32−RootActionState::RootActionState(QObject *parent)
33− : ActionStateParser(parent),
34− m_menu(nullptr)
35−{
36−}
37−
38−RootActionState::~RootActionState()
39−{
40−}
41−
42−UnityMenuModel* RootActionState::menu() const
43−{
44− return m_menu;
45−}
46−
47−void RootActionState::setMenu(UnityMenuModel* menu)
48−{
49− if (m_menu != menu) {
50− if (m_menu) {
51− m_menu->disconnect(this);
52− }
53− m_menu = menu;
54−
55− if (m_menu) {
56− connect(m_menu, SIGNAL(rowsInserted(const QModelIndex&, int, int)), SLOT(onModelRowsAdded(const QModelIndex&, int, int)));
57− connect(m_menu, SIGNAL(rowsRemoved(const QModelIndex&, int, int)), SLOT(onModelRowsRemoved(const QModelIndex&, int, int)));
58− connect(m_menu, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&)), SLOT(onModelDataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&)));
59−
60− connect(m_menu, SIGNAL(destroyed()), SLOT(reset()));
61− }
62− updateActionState();
63− Q_EMIT menuChanged();
64− }
65−}
66−
67−void RootActionState::onModelRowsAdded(const QModelIndex& parent, int start, int end)
24+RootStateParser::RootStateParser(QObject* parent)
25+ : ActionStateParser(parent)
6826{
69− Q_UNUSED(parent);
70− if (start == 0 && end >= 0) {
71− updateActionState();
72− }
73−}
74−
75−void RootActionState::onModelRowsRemoved(const QModelIndex& parent, int start, int end)
76−{
77− Q_UNUSED(parent);
78− if (start == 0 && end >= 0) {
79− updateActionState();
80− }
81−}
82−
83−void RootActionState::onModelDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>& roles)
84−{
85− Q_UNUSED(roles);
86− if (!topLeft.isValid() || !bottomRight.isValid()) {
87− return;
88− }
89−
90− if (topLeft.row() <= 0 && bottomRight.row() >= 0) {
91− updateActionState();
92− }
93−}
94−
95−void RootActionState::reset()
96−{
97− m_cachedState.clear();
98− m_menu = nullptr;
99−
100− Q_EMIT menuChanged();
101− Q_EMIT updated();
102−}
103−
104−void RootActionState::updateActionState()
105−{
106− if (m_menu && m_menu->rowCount() > 0) {
107− ActionStateParser* oldParser = m_menu->actionStateParser();
108− m_menu->setActionStateParser(this);
109−
110− m_cachedState = m_menu->get(0, "actionState").toMap();
111−
112− m_menu->setActionStateParser(oldParser);
113− } else {
114− m_cachedState.clear();
115− }
116− Q_EMIT updated();
117−}
118−
119−bool RootActionState::isValid() const
120−{
121− return m_menu && m_menu->rowCount() > 0;
122−}
123−
124−QString RootActionState::title() const
125−{
126− if (!isValid()) return QString();
127−
128− return m_cachedState.value("title", QVariant::fromValue(QString())).toString();
129−}
130−
131−QString RootActionState::leftLabel() const
132−{
133− if (!isValid()) return QString();
134−
135− return m_cachedState.value("pre-label", QVariant::fromValue(QString())).toString();
136−}
137−
138−QString RootActionState::rightLabel() const
139−{
140− if (!isValid()) return QString();
141−
142− return m_cachedState.value("label", QVariant::fromValue(QString())).toString();
143−}
144−
145−QStringList RootActionState::icons() const
146−{
147− if (!isValid()) return QStringList();
148−
149− return m_cachedState.value("icons", QVariant::fromValue(QStringList())).toStringList();
150−}
151−
152−QString RootActionState::accessibleName() const
153−{
154− if (!isValid()) return QString();
155−
156− return m_cachedState.value("accessible-desc", QVariant::fromValue(QString())).toString();
157−}
158−
159−bool RootActionState::indicatorVisible() const
160−{
161− if (!isValid()) return false;
162−
163− return m_cachedState.value("visible", QVariant::fromValue(true)).toBool();
16427}
16528
16629static QString iconUri(GIcon *icon)
@@ -209,7 +72,7 @@ static QString iconUri(GIcon *icon)
20972 return uri;
21073}
21174
212−QVariant RootActionState::toQVariant(GVariant* state) const
75+QVariant RootStateParser::toQVariant(GVariant* state) const
21376{
21477 if (!state) {
21578 return QVariant();
@@ -296,3 +159,73 @@ QVariant RootActionState::toQVariant(GVariant* state) const
296159 }
297160 return ActionStateParser::toQVariant(state);
298161}
162+
163+
164+RootStateObject::RootStateObject(QObject* parent)
165+ : QObject(parent)
166+{
167+}
168+
169+QString RootStateObject::title() const
170+{
171+ if (!valid()) return QString();
172+
173+ return m_currentState.value("title", QVariant::fromValue(QString())).toString();
174+}
175+
176+QString RootStateObject::leftLabel() const
177+{
178+ if (!valid()) return QString();
179+
180+ return m_currentState.value("pre-label", QVariant::fromValue(QString())).toString();
181+}
182+
183+QString RootStateObject::rightLabel() const
184+{
185+ if (!valid()) return QString();
186+
187+ return m_currentState.value("label", QVariant::fromValue(QString())).toString();
188+}
189+
190+QStringList RootStateObject::icons() const
191+{
192+ if (!valid()) return QStringList();
193+
194+ return m_currentState.value("icons", QVariant::fromValue(QStringList())).toStringList();
195+}
196+
197+QString RootStateObject::accessibleName() const
198+{
199+ if (!valid()) return QString();
200+
201+ return m_currentState.value("accessible-desc", QVariant::fromValue(QString())).toString();
202+}
203+
204+bool RootStateObject::indicatorVisible() const
205+{
206+ if (!valid()) return false;
207+
208+ return m_currentState.value("visible", QVariant::fromValue(true)).toBool();
209+}
210+
211+void RootStateObject::setCurrentState(const QVariantMap& newState)
212+{
213+ QString oldTitle = title();
214+ QString oldLeftLabel = leftLabel();
215+ QString oldRightLabel = rightLabel();
216+ QStringList oldIcons = icons();
217+ QString oldAccessibleName = accessibleName();
218+ bool oldIndicatorVisible = indicatorVisible();
219+
220+ if (m_currentState != newState) {
221+ m_currentState = newState;
222+ Q_EMIT updated();
223+
224+ if (oldTitle != title()) Q_EMIT titleChanged();
225+ if (oldLeftLabel != leftLabel()) Q_EMIT leftLabelChanged();
226+ if (oldRightLabel != rightLabel()) Q_EMIT rightLabelChanged();
227+ if (oldIcons != icons()) Q_EMIT iconsChanged();
228+ if (oldAccessibleName != accessibleName()) Q_EMIT accessibleNameChanged();
229+ if (oldIndicatorVisible != indicatorVisible()) Q_EMIT indicatorVisibleChanged();
230+ }
231+}
plugins/Unity/Indicators/rootactionstate.h → plugins/Unity/Indicators/rootstateparser.hrenamed+18−34
@@ -12,26 +12,27 @@
1212 *
1313 * You should have received a copy of the GNU Lesser General Public License
1414 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Authors:
17− * Nick Dedekind <nick.dedekind@canonical.com>
1815 */
1916
20−#ifndef ROOTACTIONSTATE_H
21−#define ROOTACTIONSTATE_H
17+#ifndef ROOTSTATEPARSER_H
18+#define ROOTSTATEPARSER_H
2219
2320#include "unityindicatorsglobal.h"
2421
2522#include <actionstateparser.h>
2623
27−class UnityMenuModel;
24+class UNITYINDICATORS_EXPORT RootStateParser : public ActionStateParser
25+{
26+public:
27+ RootStateParser(QObject* parent = nullptr);
28+ virtual QVariant toQVariant(GVariant* state) const override;
29+};
2830
29−class UNITYINDICATORS_EXPORT RootActionState : public ActionStateParser
31+class UNITYINDICATORS_EXPORT RootStateObject : public QObject
3032{
3133 Q_OBJECT
32− Q_PROPERTY(UnityMenuModel* menu READ menu WRITE setMenu NOTIFY menuChanged)
3334
34− Q_PROPERTY(bool valid READ isValid NOTIFY validChanged)
35+ Q_PROPERTY(bool valid READ valid NOTIFY validChanged)
3536 Q_PROPERTY(QString title READ title NOTIFY titleChanged)
3637 Q_PROPERTY(QString leftLabel READ leftLabel NOTIFY leftLabelChanged)
3738 Q_PROPERTY(QString rightLabel READ rightLabel NOTIFY rightLabelChanged)
@@ -39,16 +40,10 @@ class UNITYINDICATORS_EXPORT RootActionState : public ActionStateParser
3940 Q_PROPERTY(QString accessibleName READ accessibleName NOTIFY accessibleNameChanged)
4041 Q_PROPERTY(bool indicatorVisible READ indicatorVisible NOTIFY indicatorVisibleChanged)
4142public:
42− RootActionState(QObject *parent = 0);
43− virtual ~RootActionState();
43+ RootStateObject(QObject* parent = 0);
4444
45− UnityMenuModel* menu() const;
46− void setMenu(UnityMenuModel* menu);
45+ virtual bool valid() const = 0;
4746
48− int index() const;
49− void setIndex(int index);
50−
51− bool isValid() const;
5247 QString title() const;
5348 QString leftLabel() const;
5449 QString rightLabel() const;
@@ -56,15 +51,12 @@ public:
5651 QString accessibleName() const;
5752 bool indicatorVisible() const;
5853
59− // from ActionStateParser
60− virtual QVariant toQVariant(GVariant* state) const override;
54+ QVariantMap currentState() const { return m_currentState; }
55+ void setCurrentState(const QVariantMap& currentState);
6156
6257Q_SIGNALS:
6358 void updated();
6459
65− void menuChanged();
66− void indexChanged();
67−
6860 void validChanged();
6961 void titleChanged();
7062 void leftLabelChanged();
@@ -73,17 +65,9 @@ Q_SIGNALS:
7365 void accessibleNameChanged();
7466 void indicatorVisibleChanged();
7567
76−private Q_SLOTS:
77− void onModelRowsAdded(const QModelIndex& parent, int start, int end);
78− void onModelRowsRemoved(const QModelIndex& parent, int start, int end);
79− void onModelDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>&);
80− void reset();
81−
82−private:
83− void updateActionState();
84−
85− UnityMenuModel* m_menu;
86− QVariantMap m_cachedState;
68+protected:
69+ RootStateParser m_parser;
70+ QVariantMap m_currentState;
8771};
8872
89−#endif // ROOTACTIONSTATE_H
73+#endif // ROOTSTATEPARSER_H
plugins/Utils/CMakeLists.txt+1−1
@@ -12,7 +12,7 @@ include_directories(
1212
1313set(QMLPLUGIN_SRC
1414 qlimitproxymodelqml.cpp
15− qsortfilterproxymodelqml.cpp
15+ unitysortfilterproxymodelqml.cpp
1616 relativetimeformatter.cpp
1717 timeformatter.cpp
1818 unitymenumodelpaths.cpp
plugins/Utils/plugin.cpp+2−2
@@ -27,7 +27,7 @@
2727
2828// local
2929#include "qlimitproxymodelqml.h"
30−#include "qsortfilterproxymodelqml.h"
30+#include "unitysortfilterproxymodelqml.h"
3131#include "relativetimeformatter.h"
3232#include "timeformatter.h"
3333#include "unitymenumodelpaths.h"
@@ -39,7 +39,7 @@ void UtilsPlugin::registerTypes(const char *uri)
3939 Q_ASSERT(uri == QLatin1String("Utils"));
4040 qmlRegisterType<QAbstractItemModel>();
4141 qmlRegisterType<QLimitProxyModelQML>(uri, 0, 1, "LimitProxyModel");
42− qmlRegisterType<QSortFilterProxyModelQML>(uri, 0, 1, "SortFilterProxyModel");
42+ qmlRegisterType<UnitySortFilterProxyModelQML>(uri, 0, 1, "UnitySortFilterProxyModel");
4343 qmlRegisterType<UnityMenuModelPaths>(uri, 0, 1, "UnityMenuModelPaths");
4444 qmlRegisterType<TimeFormatter>(uri, 0, 1, "TimeFormatter");
4545 qmlRegisterType<WindowKeysFilter>(uri, 0, 1, "WindowKeysFilter");
plugins/Utils/qsortfilterproxymodelqml.cpp → plugins/Utils/unitysortfilterproxymodelqml.cpprenamed+15−15
@@ -15,12 +15,12 @@
1515 */
1616
1717// self
18−#include "qsortfilterproxymodelqml.h"
18+#include "unitysortfilterproxymodelqml.h"
1919
2020// Qt
2121#include <QDebug>
2222
23−QSortFilterProxyModelQML::QSortFilterProxyModelQML(QObject *parent)
23+UnitySortFilterProxyModelQML::UnitySortFilterProxyModelQML(QObject *parent)
2424 : QSortFilterProxyModel(parent)
2525 , m_invertMatch(false)
2626{
@@ -32,7 +32,7 @@ QSortFilterProxyModelQML::QSortFilterProxyModelQML(QObject *parent)
3232/*
3333 * Enter row index of filtered/sorted model, returns row index of source model
3434 */
35−int QSortFilterProxyModelQML::mapRowToSource(int row)
35+int UnitySortFilterProxyModelQML::mapRowToSource(int row)
3636{
3737 if (sourceModel() == nullptr)
3838 return -1;
@@ -40,13 +40,13 @@ int QSortFilterProxyModelQML::mapRowToSource(int row)
4040 return QSortFilterProxyModel::mapToSource(index(row, 0)).row();
4141}
4242
43−QHash<int, QByteArray> QSortFilterProxyModelQML::roleNames() const
43+QHash<int, QByteArray> UnitySortFilterProxyModelQML::roleNames() const
4444{
4545 return sourceModel() ? sourceModel()->roleNames() : QHash<int, QByteArray>();
4646}
4747
4848void
49−QSortFilterProxyModelQML::setModel(QAbstractItemModel *itemModel)
49+UnitySortFilterProxyModelQML::setModel(QAbstractItemModel *itemModel)
5050{
5151 if (itemModel == nullptr) {
5252 return;
@@ -69,7 +69,7 @@ QSortFilterProxyModelQML::setModel(QAbstractItemModel *itemModel)
6969}
7070
7171QVariantMap
72−QSortFilterProxyModelQML::get(int row)
72+UnitySortFilterProxyModelQML::get(int row)
7373{
7474 QVariantMap res;
7575 const QHash<int, QByteArray> roles = roleNames();
@@ -81,7 +81,7 @@ QSortFilterProxyModelQML::get(int row)
8181}
8282
8383QVariant
84−QSortFilterProxyModelQML::data(int row, int role)
84+UnitySortFilterProxyModelQML::data(int row, int role)
8585{
8686 if (sourceModel() == nullptr) {
8787 return QVariant();
@@ -91,7 +91,7 @@ QSortFilterProxyModelQML::data(int row, int role)
9191}
9292
9393int
94−QSortFilterProxyModelQML::totalCount() const
94+UnitySortFilterProxyModelQML::totalCount() const
9595{
9696 if (sourceModel() != nullptr) {
9797 return sourceModel()->rowCount();
@@ -101,19 +101,19 @@ QSortFilterProxyModelQML::totalCount() const
101101}
102102
103103int
104−QSortFilterProxyModelQML::count()
104+UnitySortFilterProxyModelQML::count()
105105{
106106 return rowCount();
107107}
108108
109109bool
110−QSortFilterProxyModelQML::invertMatch() const
110+UnitySortFilterProxyModelQML::invertMatch() const
111111{
112112 return m_invertMatch;
113113}
114114
115115void
116−QSortFilterProxyModelQML::setInvertMatch(bool invertMatch)
116+UnitySortFilterProxyModelQML::setInvertMatch(bool invertMatch)
117117{
118118 if (invertMatch != m_invertMatch) {
119119 m_invertMatch = invertMatch;
@@ -123,7 +123,7 @@ QSortFilterProxyModelQML::setInvertMatch(bool invertMatch)
123123}
124124
125125bool
126−QSortFilterProxyModelQML::filterAcceptsRow(int sourceRow,
126+UnitySortFilterProxyModelQML::filterAcceptsRow(int sourceRow,
127127 const QModelIndex &sourceParent) const
128128{
129129 // If there's no regexp set, always accept all rows indepenently of the invertMatch setting
@@ -136,7 +136,7 @@ QSortFilterProxyModelQML::filterAcceptsRow(int sourceRow,
136136}
137137
138138int
139−QSortFilterProxyModelQML::findFirst(int role, const QVariant& value) const
139+UnitySortFilterProxyModelQML::findFirst(int role, const QVariant& value) const
140140{
141141 QModelIndexList matches = match(index(0, 0), role, value, 1, Qt::MatchExactly);
142142 if (!matches.isEmpty()) {
@@ -147,7 +147,7 @@ QSortFilterProxyModelQML::findFirst(int role, const QVariant& value) const
147147}
148148
149149int
150−QSortFilterProxyModelQML::mapFromSource(int row)
150+UnitySortFilterProxyModelQML::mapFromSource(int row)
151151{
152152 if (sourceModel() != nullptr) {
153153 return QSortFilterProxyModel::mapFromSource(sourceModel()->index(row, 0)).row();
@@ -157,7 +157,7 @@ QSortFilterProxyModelQML::mapFromSource(int row)
157157}
158158
159159int
160−QSortFilterProxyModelQML::mapToSource(int row)
160+UnitySortFilterProxyModelQML::mapToSource(int row)
161161{
162162 if (sourceModel() != nullptr) {
163163 return QSortFilterProxyModel::mapToSource(index(row, 0)).row();
plugins/Utils/qsortfilterproxymodelqml.h → plugins/Utils/unitysortfilterproxymodelqml.hrenamed+5−5
@@ -14,12 +14,12 @@
1414 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1515 */
1616
17−#ifndef QSORTFILTERPROXYMODELQML_H
18−#define QSORTFILTERPROXYMODELQML_H
17+#ifndef UNITYSORTFILTERPROXYMODELQML_H
18+#define UNITYSORTFILTERPROXYMODELQML_H
1919
2020#include <QSortFilterProxyModel>
2121
22−class QSortFilterProxyModelQML : public QSortFilterProxyModel
22+class UnitySortFilterProxyModelQML : public QSortFilterProxyModel
2323{
2424 Q_OBJECT
2525
@@ -29,7 +29,7 @@ class QSortFilterProxyModelQML : public QSortFilterProxyModel
2929 Q_PROPERTY(bool invertMatch READ invertMatch WRITE setInvertMatch NOTIFY invertMatchChanged)
3030
3131public:
32− explicit QSortFilterProxyModelQML(QObject *parent = 0);
32+ explicit UnitySortFilterProxyModelQML(QObject *parent = 0);
3333
3434 Q_INVOKABLE QVariantMap get(int row); // Use with caution, it can be slow to query all the roles
3535 Q_INVOKABLE QVariant data(int row, int role);
@@ -60,4 +60,4 @@ private:
6060 bool m_invertMatch;
6161};
6262
63−#endif // QSORTFILTERPROXYMODELQML_H
63+#endif // UNITYSORTFILTERPROXYMODELQML_H
po/ca.po+43−39
@@ -8,15 +8,15 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2014-12-10 10:55+0100\n"
11−"PO-Revision-Date: 2014-11-10 09:22+0000\n"
11+"PO-Revision-Date: 2015-01-13 13:15+0000\n"
1212"Last-Translator: David Planella <david.planella@ubuntu.com>\n"
1313"Language-Team: Catalan <ca@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-12-13 07:11+0000\n"
19−"X-Generator: Launchpad (build 17286)\n"
18+"X-Launchpad-Export-Date: 2015-01-14 06:48+0000\n"
19+"X-Generator: Launchpad (build 17298)\n"
2020
2121#: plugins/LightDM/Greeter.cpp:130
2222msgid "Password: "
@@ -237,15 +237,15 @@ msgstr "Deixeu anar per actualitzar..."
237237
238238#: qml/Dash/ScopesList.qml:63
239239msgid "Manage"
240−msgstr ""
240+msgstr "Gestiona"
241241
242242#: qml/Dash/ScopesList.qml:107
243243msgid "Home"
244−msgstr ""
244+msgstr "Inici"
245245
246246#: qml/Dash/ScopesList.qml:108
247247msgid "Also installed"
248−msgstr ""
248+msgstr "També instal·lat"
249249
250250#: qml/Greeter/Greeter.qml:174
251251msgid "Unlock"
@@ -361,86 +361,86 @@ msgstr ""
361361
362362#: qml/Wizard/Page.qml:89
363363msgid "Back"
364−msgstr ""
364+msgstr "Enrere"
365365
366366#: qml/Wizard/Pages/10-welcome.qml:27
367367msgid "Hi!"
368−msgstr ""
368+msgstr "Hola!"
369369
370370#: qml/Wizard/Pages/10-welcome.qml:44
371371msgid "Welcome to your Ubuntu phone."
372−msgstr ""
372+msgstr "Us donem la benvinguda al vostre telèfon Ubuntu."
373373
374374#: qml/Wizard/Pages/10-welcome.qml:52
375375msgid "Let’s get started."
376−msgstr ""
376+msgstr "Comencem."
377377
378378#: qml/Wizard/Pages/10-welcome.qml:88 qml/Wizard/Pages/30-passwd-type.qml:128
379379#: qml/Wizard/Pages/40-wifi.qml:197 qml/Wizard/Pages/50-location.qml:131
380380#: qml/Wizard/Pages/60-reporting.qml:50 qml/Wizard/Pages/passwd-confirm.qml:82
381381#: qml/Wizard/Pages/passwd-set.qml:90
382382msgid "Continue"
383−msgstr ""
383+msgstr "Continua"
384384
385385#: qml/Wizard/Pages/20-sim.qml:25
386386msgid "Add a SIM card and restart your device"
387−msgstr ""
387+msgstr "Afegiu una targeta SIM i reinicieu el dispositiu"
388388
389389#: qml/Wizard/Pages/20-sim.qml:55
390390msgid "Without it, you won’t be able to make calls or use text messaging."
391−msgstr ""
391+msgstr "Sense ella, no podreu fer trucades o enviar missatges de text."
392392
393393#: qml/Wizard/Pages/20-sim.qml:69 qml/Wizard/Pages/40-wifi.qml:197
394394msgid "Skip"
395−msgstr ""
395+msgstr "Omet"
396396
397397#: qml/Wizard/Pages/30-passwd-type.qml:39
398398msgid "Lock security"
399−msgstr ""
399+msgstr "Seguretat del bloqueig"
400400
401401#: qml/Wizard/Pages/30-passwd-type.qml:74
402402msgid "Please select how you’d like to unlock your phone."
403−msgstr ""
403+msgstr "Seleccioneu com voleu desblocar el telèfon."
404404
405405#: qml/Wizard/Pages/30-passwd-type.qml:97
406406msgid "Swipe"
407−msgstr ""
407+msgstr "Lliscament amb el dit"
408408
409409#: qml/Wizard/Pages/30-passwd-type.qml:98
410410msgid "No security"
411−msgstr ""
411+msgstr "Sense seguretat"
412412
413413#: qml/Wizard/Pages/30-passwd-type.qml:100
414414msgid "Passcode"
415−msgstr ""
415+msgstr "Codi d'accés"
416416
417417#: qml/Wizard/Pages/30-passwd-type.qml:101
418418msgid "4 digits only"
419−msgstr ""
419+msgstr "Només 4 dígits"
420420
421421#: qml/Wizard/Pages/30-passwd-type.qml:103
422422msgid "Passphrase"
423−msgstr ""
423+msgstr "Contrasenya"
424424
425425#: qml/Wizard/Pages/30-passwd-type.qml:104
426426msgid "Numbers and letters"
427−msgstr ""
427+msgstr "Números i lletres"
428428
429429#: qml/Wizard/Pages/40-wifi.qml:28
430430msgid "Connect to Wi‑Fi"
431−msgstr ""
431+msgstr "Connecta't a la Wi-Fi"
432432
433433#: qml/Wizard/Pages/40-wifi.qml:147
434434msgid "Available networks…"
435−msgstr ""
435+msgstr "Xarxes disponibles..."
436436
437437#: qml/Wizard/Pages/40-wifi.qml:148
438438msgid "No available networks."
439−msgstr ""
439+msgstr "No hi ha xarxes disponibles"
440440
441441#: qml/Wizard/Pages/50-location.qml:27
442442msgid "Location"
443−msgstr ""
443+msgstr "Ubicació"
444444
445445#: qml/Wizard/Pages/50-location.qml:62
446446msgid "Let the phone detect your location:"
@@ -471,70 +471,74 @@ msgstr ""
471471
472472#: qml/Wizard/Pages/60-reporting.qml:24
473473msgid "Improving your experience"
474−msgstr ""
474+msgstr "Millora de l'experiència"
475475
476476#: qml/Wizard/Pages/60-reporting.qml:36
477477msgid ""
478478"Your phone is set up to automatically report errors to Canonical and its "
479479"partners, the makers of the operating system."
480480msgstr ""
481+"Aquest telèfon està configurat per enviar errors de manera automàtica a "
482+"Canonical i associats, els creadors del sistema operatiu."
481483
482484#: qml/Wizard/Pages/60-reporting.qml:43
483485msgid ""
484486"This can be disabled in <b>System Settings</b> under <b>Security &amp; "
485487"Privacy</b>"
486488msgstr ""
489+"Podeu inhabilitar-ho a <b>Configuració del sistema</b>, a la secció "
490+"<b>Seguretat i privadesa</b>"
487491
488492#: qml/Wizard/Pages/80-finished.qml:24
489493msgid "All done"
490−msgstr ""
494+msgstr "Tot fet"
491495
492496#: qml/Wizard/Pages/80-finished.qml:39
493497msgid "Nice work!"
494−msgstr ""
498+msgstr "Bona feina!"
495499
496500#: qml/Wizard/Pages/80-finished.qml:46
497501msgid "Your phone is now ready to use."
498−msgstr ""
502+msgstr "Ja podeu utilitzar el vostre telèfon."
499503
500504#: qml/Wizard/Pages/80-finished.qml:53
501505msgid "Finish"
502−msgstr ""
506+msgstr "Finalitza"
503507
504508#: qml/Wizard/Pages/here-terms.qml:27
505509msgid "Terms & Conditions"
506−msgstr ""
510+msgstr "Condicions generals"
507511
508512#: qml/Wizard/Pages/passwd-confirm.qml:49
509513msgid "Confirm passphrase"
510−msgstr ""
514+msgstr "Confirmeu la contrasenya"
511515
512516#: qml/Wizard/Pages/passwd-confirm.qml:50
513517msgid "Confirm passcode"
514−msgstr ""
518+msgstr "Confirmeu el codi d'accés"
515519
516520#: qml/Wizard/Pages/passwd-confirm.qml:53
517521#: qml/Wizard/Pages/passwd-confirm.qml:54
518522msgid "Please try again."
519−msgstr ""
523+msgstr "Torneu-ho a intentar."
520524
521525#: qml/Wizard/Pages/passwd-set.qml:61
522526msgid "Choose your passcode"
523−msgstr ""
527+msgstr "Trieu el codi d'accés"
524528
525529#: qml/Wizard/Pages/passwd-set.qml:68
526530msgid "Passphrase must be 4 characters long"
527−msgstr ""
531+msgstr "La contrasenya ha de tenir 4 caràcters com a mínim"
528532
529533#: qml/Wizard/StackButton.qml:39
530534#, qt-format
531535msgid "〈 %1"
532−msgstr ""
536+msgstr "〈 %1"
533537
534538#: qml/Wizard/StackButton.qml:42
535539#, qt-format
536540msgid "%1 〉"
537−msgstr ""
541+msgstr "%1 〉"
538542
539543#~ msgid "Confirm"
540544#~ msgstr "Confirma"
po/fa.po+96−88
@@ -8,26 +8,26 @@ msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2014-12-10 10:55+0100\n"
11−"PO-Revision-Date: 2014-12-10 12:53+0000\n"
11+"PO-Revision-Date: 2015-01-09 15:59+0000\n"
1212"Last-Translator: Danial Behzadi <dani.behzi@gmail.com>\n"
1313"Language-Team: Persian <fa@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2014-12-13 07:11+0000\n"
19−"X-Generator: Launchpad (build 17286)\n"
18+"X-Launchpad-Export-Date: 2015-01-10 07:18+0000\n"
19+"X-Generator: Launchpad (build 17298)\n"
2020
2121#: plugins/LightDM/Greeter.cpp:130
2222msgid "Password: "
2323msgstr "گذرواژه: "
2424
2525#: plugins/Unity/Launcher/launcheritem.cpp:45
26−#: plugins/Unity/Launcher/launcheritem.cpp:100
26+#: plugins/Unity/Launcher/launcheritem.cpp:91
2727msgid "Pin shortcut"
2828msgstr "سنجاق کردن میانبر"
2929
30−#: plugins/Unity/Launcher/launcheritem.cpp:100
30+#: plugins/Unity/Launcher/launcheritem.cpp:91
3131msgid "Unpin shortcut"
3232msgstr "برداشتن سنجاق میانبر"
3333
@@ -50,45 +50,45 @@ msgid "Please wait %1 minute and then try again…"
5050msgid_plural "Please wait %1 minutes and then try again…"
5151msgstr[0] "لطفاُ %1 دقیقه صبر نموده و سپس مجدّداً تلاش نمایید…"
5252
53−#: qml/Components/Dialogs.qml:70
53+#: qml/Components/Dialogs.qml:74
5454msgid "Log out"
5555msgstr "خروج از حساب"
5656
57−#: qml/Components/Dialogs.qml:71
57+#: qml/Components/Dialogs.qml:75
5858msgid "Are you sure you want to log out?"
5959msgstr "مطمئنید که می‌خواهید از حساب خارج شوید"
6060
61−#: qml/Components/Dialogs.qml:73 qml/Components/Dialogs.qml:97
62−#: qml/Components/Dialogs.qml:122
61+#: qml/Components/Dialogs.qml:77 qml/Components/Dialogs.qml:101
62+#: qml/Components/Dialogs.qml:126
6363msgid "No"
6464msgstr "خیر"
6565
66−#: qml/Components/Dialogs.qml:80 qml/Components/Dialogs.qml:104
67−#: qml/Components/Dialogs.qml:129
66+#: qml/Components/Dialogs.qml:84 qml/Components/Dialogs.qml:108
67+#: qml/Components/Dialogs.qml:133
6868msgid "Yes"
6969msgstr "بله"
7070
71−#: qml/Components/Dialogs.qml:94
71+#: qml/Components/Dialogs.qml:98
7272msgid "Shut down"
7373msgstr "خاموش کردن"
7474
75−#: qml/Components/Dialogs.qml:95
75+#: qml/Components/Dialogs.qml:99
7676msgid "Are you sure you want to shut down?"
7777msgstr "مطمئنید که می‌خواهید خاموش کنید؟"
7878
79−#: qml/Components/Dialogs.qml:119
79+#: qml/Components/Dialogs.qml:123
8080msgid "Reboot"
8181msgstr "راه‌اندازی مجدّد"
8282
83−#: qml/Components/Dialogs.qml:120
83+#: qml/Components/Dialogs.qml:124
8484msgid "Are you sure you want to reboot?"
8585msgstr "مطمئنید که می‌خواهید مجدّداً راه‌اندازی کنسد؟"
8686
87−#: qml/Components/Dialogs.qml:144
87+#: qml/Components/Dialogs.qml:148
8888msgid "Power"
8989msgstr "توان"
9090
91−#: qml/Components/Dialogs.qml:145
91+#: qml/Components/Dialogs.qml:149
9292msgid ""
9393"Are you sure you would like\n"
9494"to power off?"
@@ -96,15 +96,15 @@ msgstr ""
9696"آیا مطمئن هستید که\n"
9797"می‌خواهید خاموش کنید؟"
9898
99−#: qml/Components/Dialogs.qml:147
99+#: qml/Components/Dialogs.qml:151
100100msgid "Power off"
101101msgstr "خاموش کردن"
102102
103−#: qml/Components/Dialogs.qml:157
103+#: qml/Components/Dialogs.qml:161
104104msgid "Restart"
105105msgstr "شروع مجدّد"
106106
107−#: qml/Components/Dialogs.qml:167
107+#: qml/Components/Dialogs.qml:171
108108msgid "Cancel"
109109msgstr "لغو"
110110
@@ -112,43 +112,43 @@ msgstr "لغو"
112112msgid "Skip intro"
113113msgstr "پرش از مقدّمه"
114114
115−#: qml/Components/EdgeDemo.qml:125
115+#: qml/Components/EdgeDemo.qml:112
116116msgid "Right edge"
117117msgstr "لبه‌ی راست"
118118
119−#: qml/Components/EdgeDemo.qml:126
119+#: qml/Components/EdgeDemo.qml:113
120120msgid "Try swiping from the right edge to unlock the phone"
121121msgstr "برای باز کردن قفل تلفن، از لبه‌ی راست بکشید"
122122
123−#: qml/Components/EdgeDemo.qml:157
123+#: qml/Components/EdgeDemo.qml:144
124124msgid "Top edge"
125125msgstr "لبه‌ی بالا"
126126
127−#: qml/Components/EdgeDemo.qml:158
127+#: qml/Components/EdgeDemo.qml:145
128128msgid "Try swiping from the top edge to access the indicators"
129129msgstr "برای دست‌رسی به نشانگرها، از لبه‌ی بالا بکشید"
130130
131−#: qml/Components/EdgeDemo.qml:183
131+#: qml/Components/EdgeDemo.qml:170
132132msgid "Close"
133133msgstr "بستن"
134134
135−#: qml/Components/EdgeDemo.qml:184
135+#: qml/Components/EdgeDemo.qml:171
136136msgid "Swipe up again to close the settings screen"
137137msgstr "برای بستن صفحه‌ی تنظیمات، دوباره به بالا بکشپد"
138138
139−#: qml/Components/EdgeDemo.qml:214
139+#: qml/Components/EdgeDemo.qml:201
140140msgid "Left edge"
141141msgstr "لبه‌ی چپ"
142142
143−#: qml/Components/EdgeDemo.qml:215
143+#: qml/Components/EdgeDemo.qml:202
144144msgid "Swipe from the left to reveal the launcher for quick access to apps"
145145msgstr "برای آشکار شدن اجراگر به منظور دست‌رسی سریع به اپ‌ها از سمت چپ بکشید"
146146
147−#: qml/Components/EdgeDemo.qml:242
147+#: qml/Components/EdgeDemo.qml:229
148148msgid "Well done"
149149msgstr "عالی بود"
150150
151−#: qml/Components/EdgeDemo.qml:243
151+#: qml/Components/EdgeDemo.qml:230
152152msgid ""
153153"You have now mastered the edge gestures and can start using the "
154154"phone<br><br>Tap on the screen to start"
@@ -156,44 +156,44 @@ msgstr ""
156156"هم اکنون در استفاده از ژست های حرکتی مهارت لازم را دارید و می‌توانید استفاده "
157157"از تلفن را آغاز کنید<br><br>برای شروع صفحه را لمس کنید"
158158
159−#: qml/Components/Lockscreen.qml:238
159+#: qml/Components/Lockscreen.qml:223
160160msgid "Return to Call"
161161msgstr "بازگشت به تماس"
162162
163−#: qml/Components/Lockscreen.qml:238
163+#: qml/Components/Lockscreen.qml:223
164164msgid "Emergency Call"
165165msgstr "تماس اضطراری"
166166
167−#: qml/Components/Lockscreen.qml:270
167+#: qml/Components/Lockscreen.qml:255
168168msgid "OK"
169169msgstr "قبول"
170170
171−#: qml/Dash/GenericScopeView.qml:431 qml/Dash/GenericScopeView.qml:588
171+#: qml/Dash/GenericScopeView.qml:434 qml/Dash/GenericScopeView.qml:591
172172msgid "See less"
173173msgstr "کم‌تر ببینید"
174174
175−#: qml/Dash/GenericScopeView.qml:431
175+#: qml/Dash/GenericScopeView.qml:434
176176msgid "See all"
177177msgstr "دیدن همه"
178178
179−#: qml/Dash/GenericScopeView.qml:493 qml/Dash/PageHeader.qml:267
179+#: qml/Dash/GenericScopeView.qml:496 qml/Dash/PageHeader.qml:268
180180#: qml/Panel/SearchIndicator.qml:27
181181msgid "Search"
182182msgstr "جست‌وجو"
183183
184−#: qml/Dash/PageHeader.qml:260
184+#: qml/Dash/PageHeader.qml:261
185185msgid "Store"
186186msgstr "فروشگاه"
187187
188−#: qml/Dash/PageHeader.qml:277
188+#: qml/Dash/PageHeader.qml:278
189189msgid "Settings"
190190msgstr "تنظیمات"
191191
192−#: qml/Dash/PageHeader.qml:284
192+#: qml/Dash/PageHeader.qml:285
193193msgid "Remove from Favorites"
194194msgstr "برداشتن از برگزیده‌ها"
195195
196−#: qml/Dash/PageHeader.qml:284
196+#: qml/Dash/PageHeader.qml:285
197197msgid "Add to Favorites"
198198msgstr "افزودن به برگزیده‌ها"
199199
@@ -289,49 +289,49 @@ msgstr "باز کردن قفل سیم‌کارت"
289289msgid "Roaming"
290290msgstr "رومینگ"
291291
292−#: qml/Shell.qml:367
292+#: qml/Shell.qml:402
293293#, qt-format
294294msgid "Enter %1"
295295msgstr "%1 را وارد کنید"
296296
297−#: qml/Shell.qml:368 qml/Wizard/Pages/passwd-set.qml:60
297+#: qml/Shell.qml:394
298298msgid "Enter passphrase"
299299msgstr "عبارت‌عبور را وارد کنید"
300300
301−#: qml/Shell.qml:369
301+#: qml/Shell.qml:398
302302msgid "Enter passcode"
303303msgstr "رمزعبور را وارد کنید"
304304
305−#: qml/Shell.qml:370
305+#: qml/Shell.qml:403
306306#, qt-format
307307msgid "Sorry, incorrect %1"
308308msgstr "متأسّفیم، %1 نادرست بود"
309309
310−#: qml/Shell.qml:371
310+#: qml/Shell.qml:395
311311msgid "Sorry, incorrect passphrase"
312312msgstr "متأسّفیم، عبارت‌عبور نادرست بود"
313313
314−#: qml/Shell.qml:372
314+#: qml/Shell.qml:396
315315msgid "Please re-enter"
316316msgstr "لطفاً دوباره وارد کنید"
317317
318−#: qml/Shell.qml:373
318+#: qml/Shell.qml:399
319319msgid "Sorry, incorrect passcode"
320320msgstr "متأسّفیم، رمزعبور نادرست بود"
321321
322−#: qml/Shell.qml:467 qml/Wizard/Pages/passwd-confirm.qml:53
322+#: qml/Shell.qml:444
323323msgid "Sorry, incorrect passphrase."
324324msgstr "متأسّفیم، عبارت‌عبور نادرست است."
325325
326−#: qml/Shell.qml:468 qml/Wizard/Pages/passwd-confirm.qml:54
326+#: qml/Shell.qml:445
327327msgid "Sorry, incorrect passcode."
328328msgstr "متأسّفیم، رمزعبور نادرست است."
329329
330−#: qml/Shell.qml:469
330+#: qml/Shell.qml:446
331331msgid "This will be your last attempt."
332332msgstr "این آخرین تلاش شما خواهد بود."
333333
334−#: qml/Shell.qml:471
334+#: qml/Shell.qml:448
335335msgid ""
336336"If passphrase is entered incorrectly, your phone will conduct a factory "
337337"reset and all personal data will be deleted."
@@ -339,7 +339,7 @@ msgstr ""
339339"اگر عبارت‌عبور نادرست وارد شود، تلفن شما بازنشانی کارخانه خواهد شد و تمامی "
340340"اطّلاعات شخصی حذف خواهند شد."
341341
342−#: qml/Shell.qml:472
342+#: qml/Shell.qml:449
343343msgid ""
344344"If passcode is entered incorrectly, your phone will conduct a factory reset "
345345"and all personal data will be deleted."
@@ -349,98 +349,100 @@ msgstr ""
349349
350350#: qml/Wizard/Page.qml:89
351351msgid "Back"
352−msgstr ""
352+msgstr "بازگشت"
353353
354354#: qml/Wizard/Pages/10-welcome.qml:27
355355msgid "Hi!"
356−msgstr ""
356+msgstr "سلام!"
357357
358358#: qml/Wizard/Pages/10-welcome.qml:44
359359msgid "Welcome to your Ubuntu phone."
360−msgstr ""
360+msgstr "به تلفن اوبونتوی خودتان خوش آمدید."
361361
362362#: qml/Wizard/Pages/10-welcome.qml:52
363363msgid "Let’s get started."
364−msgstr ""
364+msgstr "بیایید شروع کینم."
365365
366366#: qml/Wizard/Pages/10-welcome.qml:88 qml/Wizard/Pages/30-passwd-type.qml:128
367367#: qml/Wizard/Pages/40-wifi.qml:197 qml/Wizard/Pages/50-location.qml:131
368368#: qml/Wizard/Pages/60-reporting.qml:50 qml/Wizard/Pages/passwd-confirm.qml:82
369369#: qml/Wizard/Pages/passwd-set.qml:90
370370msgid "Continue"
371−msgstr ""
371+msgstr "ادامه"
372372
373373#: qml/Wizard/Pages/20-sim.qml:25
374374msgid "Add a SIM card and restart your device"
375−msgstr ""
375+msgstr "سیم‌کارتی افزوده و دستگاهتان را شروع مجدّد کنید"
376376
377377#: qml/Wizard/Pages/20-sim.qml:55
378378msgid "Without it, you won’t be able to make calls or use text messaging."
379379msgstr ""
380+"بدون آن، نخواهید توانست تماس گرفته با از پیام‌رسانی متنی استفاده کنید."
380381
381382#: qml/Wizard/Pages/20-sim.qml:69 qml/Wizard/Pages/40-wifi.qml:197
382383msgid "Skip"
383−msgstr ""
384+msgstr "پرش"
384385
385386#: qml/Wizard/Pages/30-passwd-type.qml:39
386387msgid "Lock security"
387−msgstr ""
388+msgstr "امنیت قفل"
388389
389390#: qml/Wizard/Pages/30-passwd-type.qml:74
390391msgid "Please select how you’d like to unlock your phone."
391−msgstr ""
392+msgstr "لطفاً برگزینید که می‌خواهید چگونه قفل تلفنتان را باز کنید."
392393
393394#: qml/Wizard/Pages/30-passwd-type.qml:97
394395msgid "Swipe"
395−msgstr ""
396+msgstr "لغزش"
396397
397398#: qml/Wizard/Pages/30-passwd-type.qml:98
398399msgid "No security"
399−msgstr ""
400+msgstr "بدون امنیت"
400401
401402#: qml/Wizard/Pages/30-passwd-type.qml:100
402403msgid "Passcode"
403−msgstr ""
404+msgstr "رمزعبور"
404405
405406#: qml/Wizard/Pages/30-passwd-type.qml:101
406407msgid "4 digits only"
407−msgstr ""
408+msgstr "فقط ۴ رقم"
408409
409410#: qml/Wizard/Pages/30-passwd-type.qml:103
410411msgid "Passphrase"
411−msgstr ""
412+msgstr "عبارت‌عبور"
412413
413414#: qml/Wizard/Pages/30-passwd-type.qml:104
414415msgid "Numbers and letters"
415−msgstr ""
416+msgstr "اعداد و حروف"
416417
417418#: qml/Wizard/Pages/40-wifi.qml:28
418419msgid "Connect to Wi‑Fi"
419−msgstr ""
420+msgstr "اتّصال به بی‌سیم"
420421
421422#: qml/Wizard/Pages/40-wifi.qml:147
422423msgid "Available networks…"
423−msgstr ""
424+msgstr "شبکه‌های موجود…"
424425
425426#: qml/Wizard/Pages/40-wifi.qml:148
426427msgid "No available networks."
427−msgstr ""
428+msgstr "هیچ شبکه‌ای موجود نیست."
428429
429430#: qml/Wizard/Pages/50-location.qml:27
430431msgid "Location"
431−msgstr ""
432+msgstr "موقعیت"
432433
433434#: qml/Wizard/Pages/50-location.qml:62
434435msgid "Let the phone detect your location:"
435−msgstr ""
436+msgstr "اجازه به تلفن برای تشخیص موقعیّتتان:"
436437
437438#: qml/Wizard/Pages/50-location.qml:69
438439msgid "Using GPS only (less accurate)"
439−msgstr ""
440+msgstr "فقط با استفاده از جی‌پی‌اس (دقّت کم‌تر)"
440441
441442#: qml/Wizard/Pages/50-location.qml:86
442443msgid "Using GPS, anonymized Wi-Fi and cellular network info (recommended)"
443444msgstr ""
445+"با استفاده از جی‌پی‌اس، بی‌سیم ناشناس و اطّلاعات شبکه‌ی سلّولی (پیشنهاد شده)"
444446
445447#. TRANSLATORS: HERE is a trademark for Nokia's location service, you probably shouldn't translate it
446448#: qml/Wizard/Pages/50-location.qml:103
@@ -448,81 +450,87 @@ msgid ""
448450"By selecting this option you agree to the Nokia HERE <a href='#'>terms and "
449451"conditions</a>."
450452msgstr ""
453+"با انتخاب این گزینه، با <a href='#'>شرایط و ضوابط</a> HERE نوکیا موافقت "
454+"می‌کنید."
451455
452456#: qml/Wizard/Pages/50-location.qml:112
453457msgid "Not at all"
454−msgstr ""
458+msgstr "به هیچ وجه"
455459
456460#: qml/Wizard/Pages/50-location.qml:124
457461msgid "You can change your mind later in <b>System Settings</b>."
458−msgstr ""
462+msgstr "می‌توانید بعدها نظرتان را در <b>تنظیمات سامانه</b> تغییر دهید."
459463
460464#: qml/Wizard/Pages/60-reporting.qml:24
461465msgid "Improving your experience"
462−msgstr ""
466+msgstr "ارتقای تجربه‌ی شما"
463467
464468#: qml/Wizard/Pages/60-reporting.qml:36
465469msgid ""
466470"Your phone is set up to automatically report errors to Canonical and its "
467471"partners, the makers of the operating system."
468472msgstr ""
473+"تلفن شما تنظیم شده تا خطاها را به صورت خودکار به سازندگان سیستم‌عامل یعنی "
474+"شرکت کنونیکال و شرکایش گزارش دهد."
469475
470476#: qml/Wizard/Pages/60-reporting.qml:43
471477msgid ""
472478"This can be disabled in <b>System Settings</b> under <b>Security &amp; "
473479"Privacy</b>"
474480msgstr ""
481+"این می‌تواند در <b>تنظیمات سامانه</b> ذیل <b>امنیت و محرمانگی</b> غیرفعَال "
482+"شود"
475483
476484#: qml/Wizard/Pages/80-finished.qml:24
477485msgid "All done"
478−msgstr ""
486+msgstr "همه‌چیز انجام شد"
479487
480488#: qml/Wizard/Pages/80-finished.qml:39
481489msgid "Nice work!"
482−msgstr ""
490+msgstr "عالی بود!"
483491
484492#: qml/Wizard/Pages/80-finished.qml:46
485493msgid "Your phone is now ready to use."
486−msgstr ""
494+msgstr "هم‌اکنون تلفن شما آماده‌ی استفاده است."
487495
488496#: qml/Wizard/Pages/80-finished.qml:53
489497msgid "Finish"
490−msgstr ""
498+msgstr "پایان"
491499
492500#: qml/Wizard/Pages/here-terms.qml:27
493501msgid "Terms & Conditions"
494−msgstr ""
502+msgstr "شرایط و ضوابط"
495503
496504#: qml/Wizard/Pages/passwd-confirm.qml:49
497505msgid "Confirm passphrase"
498−msgstr ""
506+msgstr "تأیید عبارت‌عبور"
499507
500508#: qml/Wizard/Pages/passwd-confirm.qml:50
501509msgid "Confirm passcode"
502−msgstr ""
510+msgstr "تأیید رمزعبور"
503511
504512#: qml/Wizard/Pages/passwd-confirm.qml:53
505513#: qml/Wizard/Pages/passwd-confirm.qml:54
506514msgid "Please try again."
507−msgstr ""
515+msgstr "لطفاً دوباره سعی کنید."
508516
509517#: qml/Wizard/Pages/passwd-set.qml:61
510518msgid "Choose your passcode"
511−msgstr ""
519+msgstr "رمزعبور خود را انتخاب کنید"
512520
513521#: qml/Wizard/Pages/passwd-set.qml:68
514522msgid "Passphrase must be 4 characters long"
515−msgstr ""
523+msgstr "عبارت‌عبور باید ۴ نویسه طول داشته باشد"
516524
517525#: qml/Wizard/StackButton.qml:39
518526#, qt-format
519527msgid "〈 %1"
520−msgstr ""
528+msgstr "〈 %1"
521529
522530#: qml/Wizard/StackButton.qml:42
523531#, qt-format
524532msgid "%1 〉"
525−msgstr ""
533+msgstr "%1 〉"
526534
527535#~ msgid "Type or say a command"
528536#~ msgstr "دستوری را بنویسید یا بگویید"
po/nl.po+49−42
@@ -8,15 +8,15 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2014-12-10 10:55+0100\n"
11−"PO-Revision-Date: 2014-11-05 08:19+0000\n"
11+"PO-Revision-Date: 2015-01-13 20:27+0000\n"
1212"Last-Translator: rob <linuxned@gmail.com>\n"
1313"Language-Team: Dutch <nl@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-12-13 07:11+0000\n"
19−"X-Generator: Launchpad (build 17286)\n"
18+"X-Launchpad-Export-Date: 2015-01-14 06:48+0000\n"
19+"X-Generator: Launchpad (build 17298)\n"
2020
2121#: plugins/LightDM/Greeter.cpp:130
2222msgid "Password: "
@@ -231,7 +231,7 @@ msgstr "Loslaten om te verversen…"
231231
232232#: qml/Dash/ScopesList.qml:63
233233msgid "Manage"
234−msgstr ""
234+msgstr "Beheren"
235235
236236#: qml/Dash/ScopesList.qml:107
237237msgid "Home"
@@ -239,7 +239,7 @@ msgstr ""
239239
240240#: qml/Dash/ScopesList.qml:108
241241msgid "Also installed"
242−msgstr ""
242+msgstr "Ook geïnstalleerd"
243243
244244#: qml/Greeter/Greeter.qml:174
245245msgid "Unlock"
@@ -353,98 +353,99 @@ msgstr ""
353353
354354#: qml/Wizard/Page.qml:89
355355msgid "Back"
356−msgstr ""
356+msgstr "Terug"
357357
358358#: qml/Wizard/Pages/10-welcome.qml:27
359359msgid "Hi!"
360−msgstr ""
360+msgstr "Hallo!"
361361
362362#: qml/Wizard/Pages/10-welcome.qml:44
363363msgid "Welcome to your Ubuntu phone."
364−msgstr ""
364+msgstr "Welkom bij uw Ubuntutelefoon."
365365
366366#: qml/Wizard/Pages/10-welcome.qml:52
367367msgid "Let’s get started."
368−msgstr ""
368+msgstr "Laten we beginnen."
369369
370370#: qml/Wizard/Pages/10-welcome.qml:88 qml/Wizard/Pages/30-passwd-type.qml:128
371371#: qml/Wizard/Pages/40-wifi.qml:197 qml/Wizard/Pages/50-location.qml:131
372372#: qml/Wizard/Pages/60-reporting.qml:50 qml/Wizard/Pages/passwd-confirm.qml:82
373373#: qml/Wizard/Pages/passwd-set.qml:90
374374msgid "Continue"
375−msgstr ""
375+msgstr "Doorgaan"
376376
377377#: qml/Wizard/Pages/20-sim.qml:25
378378msgid "Add a SIM card and restart your device"
379−msgstr ""
379+msgstr "Voeg een simkaart toe en herstart uw apparaat"
380380
381381#: qml/Wizard/Pages/20-sim.qml:55
382382msgid "Without it, you won’t be able to make calls or use text messaging."
383−msgstr ""
383+msgstr "Indien u dit niet doet, kunt u niet telefoneren of sms´en."
384384
385385#: qml/Wizard/Pages/20-sim.qml:69 qml/Wizard/Pages/40-wifi.qml:197
386386msgid "Skip"
387−msgstr ""
387+msgstr "Overslaan"
388388
389389#: qml/Wizard/Pages/30-passwd-type.qml:39
390390msgid "Lock security"
391−msgstr ""
391+msgstr "Vergrendelbeveiliging"
392392
393393#: qml/Wizard/Pages/30-passwd-type.qml:74
394394msgid "Please select how you’d like to unlock your phone."
395−msgstr ""
395+msgstr "Selecteer a.u.b. hoe u uw telefoon wilt ontgrendelen."
396396
397397#: qml/Wizard/Pages/30-passwd-type.qml:97
398398msgid "Swipe"
399−msgstr ""
399+msgstr "Vegen"
400400
401401#: qml/Wizard/Pages/30-passwd-type.qml:98
402402msgid "No security"
403−msgstr ""
403+msgstr "Geen beveiliging"
404404
405405#: qml/Wizard/Pages/30-passwd-type.qml:100
406406msgid "Passcode"
407−msgstr ""
407+msgstr "Toegangscode"
408408
409409#: qml/Wizard/Pages/30-passwd-type.qml:101
410410msgid "4 digits only"
411−msgstr ""
411+msgstr "Uitsluitend 4 cijfers"
412412
413413#: qml/Wizard/Pages/30-passwd-type.qml:103
414414msgid "Passphrase"
415−msgstr ""
415+msgstr "Wachtwoordzin"
416416
417417#: qml/Wizard/Pages/30-passwd-type.qml:104
418418msgid "Numbers and letters"
419−msgstr ""
419+msgstr "Cijfers en letters"
420420
421421#: qml/Wizard/Pages/40-wifi.qml:28
422422msgid "Connect to Wi‑Fi"
423−msgstr ""
423+msgstr "Verbinden met Wifi"
424424
425425#: qml/Wizard/Pages/40-wifi.qml:147
426426msgid "Available networks…"
427−msgstr ""
427+msgstr "Beschikbare netwerken…"
428428
429429#: qml/Wizard/Pages/40-wifi.qml:148
430430msgid "No available networks."
431−msgstr ""
431+msgstr "Geen netwerken beschikbaar."
432432
433433#: qml/Wizard/Pages/50-location.qml:27
434434msgid "Location"
435−msgstr ""
435+msgstr "Locatie"
436436
437437#: qml/Wizard/Pages/50-location.qml:62
438438msgid "Let the phone detect your location:"
439−msgstr ""
439+msgstr "Laat de telefoon uw locatie detecteren:"
440440
441441#: qml/Wizard/Pages/50-location.qml:69
442442msgid "Using GPS only (less accurate)"
443−msgstr ""
443+msgstr "Alleen GPS gebruiken (minder nauwkeurig)"
444444
445445#: qml/Wizard/Pages/50-location.qml:86
446446msgid "Using GPS, anonymized Wi-Fi and cellular network info (recommended)"
447447msgstr ""
448+"Met behulp van GPS, geanonimiseerde Wi-Fi en mobiele netwerkinfo (aanbevolen)"
448449
449450#. TRANSLATORS: HERE is a trademark for Nokia's location service, you probably shouldn't translate it
450451#: qml/Wizard/Pages/50-location.qml:103
@@ -452,81 +453,87 @@ msgid ""
452453"By selecting this option you agree to the Nokia HERE <a href='#'>terms and "
453454"conditions</a>."
454455msgstr ""
456+"Door deze optie te selecteren gaat u akkoord met de Nokia HERE <a "
457+"href='#'>Algemene Voorwaarden</a>."
455458
456459#: qml/Wizard/Pages/50-location.qml:112
457460msgid "Not at all"
458−msgstr ""
461+msgstr "Helemaal niet"
459462
460463#: qml/Wizard/Pages/50-location.qml:124
461464msgid "You can change your mind later in <b>System Settings</b>."
462−msgstr ""
465+msgstr "U kunt later van gedachten veranderen in <b>Systeeminstellingen</b>."
463466
464467#: qml/Wizard/Pages/60-reporting.qml:24
465468msgid "Improving your experience"
466−msgstr ""
469+msgstr "Uw ervaring verbeteren"
467470
468471#: qml/Wizard/Pages/60-reporting.qml:36
469472msgid ""
470473"Your phone is set up to automatically report errors to Canonical and its "
471474"partners, the makers of the operating system."
472475msgstr ""
476+"Uw telefoon is ingesteld om fouten automatisch te rapporteren aan Canonical "
477+"en partners, de makers van het besturingssysteem."
473478
474479#: qml/Wizard/Pages/60-reporting.qml:43
475480msgid ""
476481"This can be disabled in <b>System Settings</b> under <b>Security &amp; "
477482"Privacy</b>"
478483msgstr ""
484+"Dit kan uitgeschakeld worden bij de <b>Systeeminstellingen</b> onder "
485+"<b>Beveiliging &amp; Privacy</b>"
479486
480487#: qml/Wizard/Pages/80-finished.qml:24
481488msgid "All done"
482−msgstr ""
489+msgstr "Alles klaar"
483490
484491#: qml/Wizard/Pages/80-finished.qml:39
485492msgid "Nice work!"
486−msgstr ""
493+msgstr "Mooi werk!"
487494
488495#: qml/Wizard/Pages/80-finished.qml:46
489496msgid "Your phone is now ready to use."
490−msgstr ""
497+msgstr "Uw telefoon is nu klaar voor gebruik."
491498
492499#: qml/Wizard/Pages/80-finished.qml:53
493500msgid "Finish"
494−msgstr ""
501+msgstr "Voltooien"
495502
496503#: qml/Wizard/Pages/here-terms.qml:27
497504msgid "Terms & Conditions"
498−msgstr ""
505+msgstr "Algemene voorwaarden"
499506
500507#: qml/Wizard/Pages/passwd-confirm.qml:49
501508msgid "Confirm passphrase"
502−msgstr ""
509+msgstr "Wachtwoordzin bevestigen"
503510
504511#: qml/Wizard/Pages/passwd-confirm.qml:50
505512msgid "Confirm passcode"
506−msgstr ""
513+msgstr "Toegangscode bevestigen"
507514
508515#: qml/Wizard/Pages/passwd-confirm.qml:53
509516#: qml/Wizard/Pages/passwd-confirm.qml:54
510517msgid "Please try again."
511−msgstr ""
518+msgstr "Probeer het opnieuw."
512519
513520#: qml/Wizard/Pages/passwd-set.qml:61
514521msgid "Choose your passcode"
515−msgstr ""
522+msgstr "Kies uw toegangscode"
516523
517524#: qml/Wizard/Pages/passwd-set.qml:68
518525msgid "Passphrase must be 4 characters long"
519−msgstr ""
526+msgstr "De wachtwoordzin moet 4 tekens lang zijn"
520527
521528#: qml/Wizard/StackButton.qml:39
522529#, qt-format
523530msgid "〈 %1"
524−msgstr ""
531+msgstr "〈 %1"
525532
526533#: qml/Wizard/StackButton.qml:42
527534#, qt-format
528535msgid "%1 〉"
529−msgstr ""
536+msgstr "%1 〉"
530537
531538#~ msgid "Confirm"
532539#~ msgstr "Bevestigen"
qml/Dash/Dash.qml+6−12
@@ -36,9 +36,8 @@ Showable {
3636 dashContent.setCurrentScopeAtIndex(index, animate, isSwipe)
3737 // Close dash overview and nested temp scopes in it
3838 if (bottomEdgeController.progress != 0) {
39− bottomEdgeController.enableAnimation = window.active && !scopesOverview.showingNonFavoriteScope;
39+ bottomEdgeController.enableAnimation = window.active;
4040 bottomEdgeController.progress = 0;
41− scopesOverview.closeTempScope();
4241 }
4342 // Close normal temp scopes (e.g. App Store)
4443 if (scopeItem.scope) {
@@ -305,8 +304,8 @@ Showable {
305304 Image {
306305 source: "graphics/overview_hint.png"
307306 anchors.horizontalCenter: parent.horizontalCenter
308− opacity: (scopeItem.scope ? scopeItem.pageHeaderTotallyVisible : scopes.count == 0 || dashContent.pageHeaderTotallyVisible) &&
309− (overviewDragHandle.enabled || bottomEdgeController.progress != 0) ? 1 : 0
307+ opacity: !scopeItem.scope && (scopes.count == 0 || dashContent.pageHeaderTotallyVisible) &&
308+ (overviewDragHandle.enabled || overviewDragHandle.status.progress != 0) ? 1 : 0
310309 Behavior on opacity {
311310 enabled: bottomEdgeController.progress == 0
312311 UbuntuNumberAnimation {}
@@ -335,28 +334,23 @@ Showable {
335334 height: units.gu(2)
336335
337336 onSceneDistanceChanged: {
338− if (status == DirectionalDragArea.Recognized && initialSceneDistance != -1) {
337+ if (status == DirectionalDragArea.Recognized) {
339338 bottomEdgeController.enableAnimation = false;
340− var deltaDistance = sceneDistance - initialSceneDistance;
341− bottomEdgeController.progress = Math.max(0, Math.min(1, deltaDistance / fullMovement));
339+ bottomEdgeController.progress = Math.max(0, Math.min(1, sceneDistance / fullMovement));
342340 }
343341 }
344342
345343 property int previousStatus: -1
346344 property int currentStatus: DirectionalDragArea.WaitingForTouch
347− property real initialSceneDistance: -1
348345
349346 onStatusChanged: {
350347 previousStatus = currentStatus;
351348 currentStatus = status;
352349
353− if (status == DirectionalDragArea.Recognized) {
354− initialSceneDistance = sceneDistance;
355− } else if (status == DirectionalDragArea.WaitingForTouch &&
350+ if (status == DirectionalDragArea.WaitingForTouch &&
356351 previousStatus == DirectionalDragArea.Recognized) {
357352 bottomEdgeController.enableAnimation = true;
358353 bottomEdgeController.progress = (bottomEdgeController.progress > 0.2) ? 1 : 0;
359− initialSceneDistance = -1;
360354 }
361355 }
362356 }
qml/Dash/DashContent.qml+2−2
@@ -113,7 +113,7 @@ Item {
113113 objectName: "dashContentList"
114114
115115 interactive: !dashContent.forceNonInteractive && dashContent.scopes.loaded && currentItem
116− && !currentItem.moving && !currentItem.navigationShown && !currentItem.subPageShown
116+ && !currentItem.moving && !currentItem.navigationDisableParentInteractive && !currentItem.subPageShown
117117 anchors.fill: parent
118118 orientation: ListView.Horizontal
119119 boundsBehavior: Flickable.DragAndOvershootBounds
@@ -175,7 +175,7 @@ Item {
175175 objectName: "scopeLoader" + index
176176
177177 readonly property bool moving: item ? item.moving : false
178− readonly property bool navigationShown: item ? item.navigationShown : false
178+ readonly property bool navigationDisableParentInteractive: item ? item.navigationDisableParentInteractive : false
179179 readonly property bool subPageShown: item ? item.subPageShown : false
180180 readonly property var categoryView: item ? item.categoryView : null
181181 readonly property var theScope: scope
qml/Dash/DashNavigation.qml+4
@@ -33,6 +33,10 @@ Item {
3333 if (altNavigationButton.showList) return altNavigationButton.listView;
3434 return null;
3535 }
36+ readonly property bool disableParentInteractive: {
37+ return navigationButton.showList || altNavigationButton.showList ||
38+ navigationButton.inverseMousePressed || altNavigationButton.inverseMousePressed;
39+ }
3640
3741 // FIXME this is only here for highlight purposes (see Background.qml, too)
3842 readonly property var background: backgroundItem
qml/Dash/DashNavigationButton.qml+2
@@ -31,6 +31,7 @@ AbstractButton {
3131 // Used by parent
3232 readonly property var currentNavigation: scope && scope[hasNavigation] ? getNavigation(scope[currentNavigationId]) : null
3333 readonly property alias listView: navigationListView
34+ readonly property bool inverseMousePressed: inverseMouseArea.pressed
3435 property bool showList: false
3536
3637 // Internal
@@ -210,6 +211,7 @@ AbstractButton {
210211 onCurrentNavigationChanged: setNewNavigation();
211212
212213 InverseMouseArea {
214+ id: inverseMouseArea
213215 anchors.fill: navigationListView
214216 enabled: root.showList
215217 onPressed: root.showList = false
qml/Dash/GenericScopeView.qml+33−5
@@ -25,10 +25,10 @@ import "../Components/ListItems" as ListItems
2525FocusScope {
2626 id: scopeView
2727
28− readonly property bool navigationShown: pageHeaderLoader.item ? pageHeaderLoader.item.bottomItem[0].openList : false
28+ readonly property bool navigationDisableParentInteractive: pageHeaderLoader.item ? pageHeaderLoader.item.bottomItem[0].disableParentInteractive : false
2929 property bool forceNonInteractive: false
3030 property var scope: null
31− property SortFilterProxyModel categories: categoryFilter
31+ property UnitySortFilterProxyModel categories: categoryFilter
3232 property bool isCurrent: false
3333 property alias moving: categoryView.moving
3434 property bool hasBackAction: false
@@ -41,6 +41,7 @@ FocusScope {
4141 property bool visibleToParent: false
4242 property alias pageHeaderTotallyVisible: categoryView.pageHeaderTotallyVisible
4343 property var holdingList: null
44+ property bool wasCurrentOnMoveStart: false
4445
4546 property var scopeStyle: ScopeStyle {
4647 style: scope ? scope.customizations : {}
@@ -106,7 +107,7 @@ FocusScope {
106107 value: isCurrent && !subPageLoader.open
107108 }
108109
109− SortFilterProxyModel {
110+ UnitySortFilterProxyModel {
110111 id: categoryFilter
111112 model: scope ? scope.categories : null
112113 dynamicSortFilter: true
@@ -116,6 +117,9 @@ FocusScope {
116117 }
117118
118119 onIsCurrentChanged: {
120+ if (!holdingList || !holdingList.moving) {
121+ wasCurrentOnMoveStart = scopeView.isCurrent;
122+ }
119123 if (pageHeaderLoader.item && showPageHeader) {
120124 pageHeaderLoader.item.resetSearch();
121125 }
@@ -142,6 +146,15 @@ FocusScope {
142146 onHideDash: subPageLoader.closeSubPage()
143147 }
144148
149+ Connections {
150+ target: holdingList
151+ onMovingChanged: {
152+ if (!moving) {
153+ wasCurrentOnMoveStart = scopeView.isCurrent;
154+ }
155+ }
156+ }
157+
145158 Rectangle {
146159 anchors.fill: parent
147160 color: scopeView.scopeStyle ? scopeView.scopeStyle.background : "transparent"
@@ -367,7 +380,11 @@ FocusScope {
367380
368381 function updateRanges() {
369382 // Don't want to create stress by requesting more items during scope
370− // changes so unless you're not part of the visible scopes just return
383+ // changes so unless you're not part of the visible scopes just return.
384+ // For the visible scopes we need to do some work, the previously non visible
385+ // scope needs to adjust its ranges so that we define the new visible range,
386+ // that still means no creation/destruction of delegates, it's just about changing
387+ // the culling of the items so they are actually visible
371388 if (holdingList && holdingList.moving && !scopeView.visibleToParent) {
372389 return;
373390 }
@@ -412,7 +429,18 @@ FocusScope {
412429 if (scopeView.isCurrent || scopeView.visibleToParent) {
413430 item.displayMarginBeginning = displayMarginBeginning;
414431 item.displayMarginEnd = displayMarginEnd;
415− item.cacheBuffer = scopeView.isCurrent ? categoryView.height * 1.5 : 0;
432+ if (holdingList && holdingList.moving) {
433+ // If we are moving we need to reset the cache buffer of the
434+ // view that was not visible (i.e. !wasCurrentOnMoveStart) to 0 since
435+ // otherwise the cache buffer we had set to preload the items of the
436+ // visible range will trigger some item creations and we want move to
437+ // be as smooth as possible meaning no need creations
438+ if (!wasCurrentOnMoveStart) {
439+ item.cacheBuffer = 0;
440+ }
441+ } else {
442+ item.cacheBuffer = categoryView.height * 1.5;
443+ }
416444 } else {
417445 var visibleRange = baseItem.height + displayMarginEnd + displayMarginBeginning;
418446 if (visibleRange < 0) {
qml/Dash/ScopesList.qml+1
@@ -65,6 +65,7 @@ Item {
6565 objectName: "pageHeader"
6666 title: i18n.tr("Manage")
6767 width: parent.width
68+ clip: true
6869 showBackButton: true
6970 backIsClose: root.state == "edit"
7071 storeEntryEnabled: root.state == "browse"
qml/Greeter/Clock.qml+1−1
@@ -53,7 +53,7 @@ Item {
5353 menuObjectPath: clock.visible ? "/com/canonical/indicator/datetime/phone" : ""
5454 }
5555
56− Indicators.RootActionState {
56+ Indicators.ModelActionRootState {
5757 menu: timeModel.model
5858 onUpdated: {
5959 if (timeLabel.text != rightLabel) {
qml/Greeter/Infographics.qml+9−7
@@ -127,7 +127,7 @@ Item {
127127
128128 index: model.index
129129 count: pastCircles.count
130− radius: parent.width / 2
130+ radius: dataCircle.width / 2
131131 halfSize: pastCircle.width / 2
132132 posOffset: 0.0
133133
@@ -187,7 +187,7 @@ Item {
187187
188188 index: model.index
189189 count: presentCircles.count
190− radius: parent.width / 2
190+ radius: dataCircle.width / 2
191191 halfSize: presentCircle.width / 2
192192 posOffset: 0.0
193193
@@ -255,14 +255,16 @@ Item {
255255 interval: animDuration * 0.5; running: false; repeat: true
256256 onTriggered: {
257257 if (dotCounter < dots.count) {
258− var nextDot = dots.itemAt(dotCounter++)
259− nextDot.unlockAnimation.start()
258+ var nextDot = dots.itemAt(dotCounter);
259+ if (nextDot) {
260+ nextDot.unlockAnimation.start();
261+ if (++dotCounter == Math.round(dots.count / 2)) {
262+ circleChangeAnimTimer.startFromBeginning();
263+ }
264+ }
260265 } else {
261266 stop()
262267 }
263− if (dotCounter == Math.round(dots.count / 2)) {
264− circleChangeAnimTimer.startFromBeginning()
265− }
266268 }
267269
268270 function startFromBeginning() {
qml/Greeter/NarrowGreeter.qml+1−1
@@ -126,7 +126,7 @@ Item {
126126
127127 function maybeShow() {
128128 if (!greeter.forcedUnlock) {
129− show();
129+ showNow();
130130 }
131131 }
132132 }
qml/Notifications/Notifications.qml+1−1
@@ -29,7 +29,7 @@ ListView {
2929 property real margin
3030 property bool useModal: snapDecisionProxyModel.count > 0
3131
32− SortFilterProxyModel {
32+ UnitySortFilterProxyModel {
3333 id: snapDecisionProxyModel
3434 objectName: "snapDecisionProxyModel"
3535
qml/Panel/IndicatorItem.qml−8
@@ -45,14 +45,6 @@ IndicatorDelegate {
4545 onClicked: parent.clicked()
4646 }
4747
48− // FIXME: For now we will enable led indicator support only for messaging indicator
49− // in the future we should export a led API insted of doing that,
50− Loader {
51− id: indicatorLed
52− // only load source Component if the icons contains the new message icon
53− source: (root.icons && (String(root.icons).indexOf("indicator-messages-new") != -1)) ? Qt.resolvedUrl("Indicators/IndicatorsLight.qml") : ""
54− }
55−
5648 Item {
5749 id: mainItems
5850 anchors.centerIn: parent
qml/Panel/Indicators/IndicatorBase.qml+1−1
@@ -40,7 +40,7 @@ Item {
4040 menuObjectPath: indicatorItem.menuObjectPath
4141 }
4242
43− RootActionState {
43+ ModelActionRootState {
4444 id: rootAction
4545 menu: menuModel ? menuModel : null
4646 onUpdated: indicatorItem.rootActionStateChanged()
qml/Panel/Indicators/IndicatorsLight.qml+19−1
@@ -20,16 +20,34 @@
2020import QtQuick 2.0
2121import Powerd 0.1
2222import Lights 0.1
23+import QMenuModel 0.1 as QMenuModel
24+import Unity.Indicators 0.1 as Indicators
2325
2426QtObject {
2527 id: root
2628
29+ property var _actionGroup: QMenuModel.QDBusActionGroup {
30+ busType: 1
31+ busName: "com.canonical.indicator.messages"
32+ objectPath: "/com/canonical/indicator/messages"
33+ }
34+
35+ property var _rootState: Indicators.ActionRootState {
36+ actionGroup: _actionGroup
37+ actionName: "messages"
38+ Component.onCompleted: actionGroup.start()
39+
40+ property bool hasMessages: valid && (String(icons).indexOf("indicator-messages-new") != -1)
41+ }
42+
2743 Component.onDestruction: Lights.state = Lights.Off
2844
2945 // QtObject does not have children
3046 property var _binding: Binding {
3147 target: Lights
3248 property: "state"
33− value: (Powerd.status === Powerd.Off) ? Lights.On : Lights.Off
49+ value: {
50+ return (Powerd.status === Powerd.Off && _rootState.hasMessages) ? Lights.On : Lights.Off
51+ }
3452 }
3553}
qml/Panel/Indicators/VisibleIndicators.qml+2−2
@@ -22,13 +22,13 @@ import Unity.Indicators 0.1 as Indicators
2222import Utils 0.1
2323
2424Item {
25− property SortFilterProxyModel model: filterModel
25+ property UnitySortFilterProxyModel model: filterModel
2626
2727 function initialise(profile) {
2828 indicatorsModel.load(profile);
2929 }
3030
31− SortFilterProxyModel {
31+ UnitySortFilterProxyModel {
3232 id: filterModel
3333 filterRole: Indicators.IndicatorsModelRole.IsVisible
3434 filterRegExp: RegExp("^true$")
qml/Panel/IndicatorsMenu.qml+5
@@ -18,6 +18,7 @@ import QtQuick 2.2
1818import Ubuntu.Components 1.1
1919import Ubuntu.Gestures 0.1
2020import "../Components"
21+import "Indicators"
2122
2223Showable {
2324 id: root
@@ -60,6 +61,10 @@ Showable {
6061 onUnitProgressChanged: d.updateState()
6162 clip: root.partiallyOpened
6263
64+ IndicatorsLight {
65+ id: indicatorLights
66+ }
67+
6368 // eater
6469 MouseArea {
6570 anchors.fill: parent
qml/Shell.qml+20−2
@@ -296,7 +296,7 @@ Item {
296296 id: inputMethod
297297 objectName: "inputMethod"
298298 anchors { fill: parent; topMargin: panel.panelHeight }
299− z: notifications.useModal || panel.indicators.shown ? overlay.z + 1 : overlay.z - 1
299+ z: notifications.useModal || panel.indicators.shown || wizard.active ? overlay.z + 1 : overlay.z - 1
300300 }
301301
302302 Connections {
@@ -355,6 +355,15 @@ Item {
355355
356356 onEmergencyCall: startLockedApp("dialer-app")
357357
358+ Timer {
359+ // See powerConnection for why this is useful
360+ id: showGreeterDelayed
361+ interval: 1
362+ onTriggered: {
363+ greeter.showNow();
364+ }
365+ }
366+
358367 Binding {
359368 target: ApplicationManager
360369 property: "suspended"
@@ -388,7 +397,16 @@ Item {
388397 onStatusChanged: {
389398 if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity &&
390399 !callManager.hasCalls && !edgeDemo.running) {
391− greeter.showNow()
400+ // We don't want to simply call greeter.showNow() here, because
401+ // that will take too long. Qt will delay button event
402+ // handling until the greeter is done loading and may think the
403+ // user held down the power button the whole time, leading to a
404+ // power dialog being shown. Instead, delay showing the
405+ // greeter until we've finished handling the event. We could
406+ // make the greeter load asynchronously instead, but that
407+ // introduces a whole host of timing issues, especially with
408+ // its animations. So this is simpler.
409+ showGreeterDelayed.start();
392410 }
393411 }
394412 }
src/libunity8-private/abstractdbusservicemonitor.cpp+21−8
@@ -32,19 +32,20 @@ AbstractDBusServiceMonitor::AbstractDBusServiceMonitor(const QString &service, c
3232 , m_service(service)
3333 , m_path(path)
3434 , m_interface(interface)
35+ , m_bus(bus)
3536 , m_watcher(new QDBusServiceWatcher(service,
3637 (bus == SystemBus) ? QDBusConnection::systemBus()
3738 : QDBusConnection::sessionBus()))
3839 , m_dbusInterface(nullptr)
3940{
40− connect(m_watcher, &QDBusServiceWatcher::serviceRegistered, this, &AbstractDBusServiceMonitor::createInterface);
41− connect(m_watcher, &QDBusServiceWatcher::serviceUnregistered, this, &AbstractDBusServiceMonitor::destroyInterface);
41+ connect(m_watcher, &QDBusServiceWatcher::serviceRegistered, this, &AbstractDBusServiceMonitor::onServiceRegistered);
42+ connect(m_watcher, &QDBusServiceWatcher::serviceUnregistered, this, &AbstractDBusServiceMonitor::onServiceUnregistered);
4243
4344 // Connect to the service if it's up already
4445 QDBusConnectionInterface* sessionBus = QDBusConnection::sessionBus().interface();
4546 QDBusReply<bool> reply = sessionBus->isServiceRegistered(m_service);
4647 if (reply.isValid() && reply.value()) {
47− createInterface(m_service);
48+ onServiceRegistered(m_service);
4849 }
4950}
5051
@@ -54,19 +55,31 @@ AbstractDBusServiceMonitor::~AbstractDBusServiceMonitor()
5455 delete m_dbusInterface;
5556}
5657
57−void AbstractDBusServiceMonitor::createInterface(const QString &)
58+void AbstractDBusServiceMonitor::onServiceRegistered(const QString &)
5859{
5960 if (m_dbusInterface != nullptr) {
6061 delete m_dbusInterface;
6162 m_dbusInterface = nullptr;
6263 }
6364
64− m_dbusInterface = new QDBusInterface(m_service, m_path, m_interface,
65− QDBusConnection::sessionBus());
65+ m_dbusInterface = createInterface(m_service, m_path, m_interface,
66+ (m_bus == SystemBus) ? QDBusConnection::systemBus()
67+ : QDBusConnection::sessionBus());
6668 Q_EMIT serviceAvailableChanged(true);
6769}
6870
69−void AbstractDBusServiceMonitor::destroyInterface(const QString &)
71+/*
72+ * Default implementation creates a QDBusInterface. This performs blocking introspection of the
73+ * service at initialization, which may be undesirable if the service is slow/blocked.
74+ */
75+QDBusAbstractInterface*
76+AbstractDBusServiceMonitor::createInterface(const QString &service, const QString &path,
77+ const QString &interface, const QDBusConnection &connection)
78+{
79+ return new QDBusInterface(service, path, interface, connection);
80+}
81+
82+void AbstractDBusServiceMonitor::onServiceUnregistered(const QString &)
7083{
7184 if (m_dbusInterface != nullptr) {
7285 delete m_dbusInterface;
@@ -76,7 +89,7 @@ void AbstractDBusServiceMonitor::destroyInterface(const QString &)
7689 Q_EMIT serviceAvailableChanged(false);
7790}
7891
79−QDBusInterface* AbstractDBusServiceMonitor::dbusInterface() const
92+QDBusAbstractInterface* AbstractDBusServiceMonitor::dbusInterface() const
8093{
8194 return m_dbusInterface;
8295}
src/libunity8-private/abstractdbusservicemonitor.h+9−5
@@ -24,7 +24,7 @@
2424#include <QString>
2525#include <QDBusConnection>
2626
27−class QDBusInterface;
27+class QDBusAbstractInterface;
2828class QDBusServiceWatcher;
2929
3030class Q_DECL_EXPORT AbstractDBusServiceMonitor : public QObject
@@ -44,7 +44,7 @@ public:
4444 QObject *parent = 0);
4545 ~AbstractDBusServiceMonitor();
4646
47− QDBusInterface* dbusInterface() const;
47+ QDBusAbstractInterface* dbusInterface() const;
4848
4949 bool serviceAvailable() const;
5050
@@ -52,15 +52,19 @@ Q_SIGNALS:
5252 void serviceAvailableChanged(bool available);
5353
5454private Q_SLOTS:
55− void createInterface(const QString &service);
56− void destroyInterface(const QString &service);
55+ void onServiceRegistered(const QString &service);
56+ void onServiceUnregistered(const QString &service);
5757
5858protected:
59+ virtual QDBusAbstractInterface* createInterface(const QString &service, const QString &path,
60+ const QString &interface, const QDBusConnection &connection);
61+
5962 const QString m_service;
6063 const QString m_path;
6164 const QString m_interface;
65+ const Bus m_bus;
6266 QDBusServiceWatcher* m_watcher;
63− QDBusInterface* m_dbusInterface;
67+ QDBusAbstractInterface* m_dbusInterface;
6468};
6569
6670#endif // ABSTRACTDBUSSERVICEMONITOR_H
src/main.cpp−6
@@ -147,12 +147,6 @@ Load the testability driver");
147147 view->setSource(source);
148148 QObject::connect(view->engine(), SIGNAL(quit()), application, SLOT(quit()));
149149
150− if (!isMirServer && qEnvironmentVariableIsSet("UNITY_MIR_EMITS_SIGSTOP")) {
151− // Emit SIGSTOP as expected by upstart, under Mir it's qtmir that will raise it.
152− // see http://upstart.ubuntu.com/cookbook/#expect-stop
153− raise(SIGSTOP);
154− }
155−
156150 if (isMirServer || parser.isSet(fullscreenOption)) {
157151 view->showFullScreen();
158152 } else {
tests/autopilot/unity8/shell/emulators/create_interactive_notification.py−1
@@ -88,7 +88,6 @@ if __name__ == '__main__':
8888 action_id,
8989 action_label,
9090 action_callback,
91− None,
9291 None
9392 )
9493
tests/autopilot/unity8/shell/emulators/edges_demo.pynew file+140
@@ -0,0 +1,140 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2014 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+import logging
21+import time
22+
23+import ubuntuuitoolkit
24+
25+import autopilot
26+from autopilot import introspection
27+
28+
29+logger = logging.getLogger(__name__)
30+
31+
32+class RightEdgeDemoOverlay(
33+ ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
34+
35+ @classmethod
36+ def validate_dbus_object(cls, path, state):
37+ name = introspection.get_classname_from_path(path)
38+ if name == b'EdgeDemoOverlay':
39+ if state['edge'][1] == 'right':
40+ return True
41+ return False
42+
43+ @autopilot.logging.log_action(logger.info)
44+ def swipe(self):
45+ """Swipe to the left to complete this demo step."""
46+ x, y, width, height = self.globalRect
47+ start_x = x + width
48+ stop_x = x
49+ start_y = stop_y = y + height // 2
50+ self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
51+ return self.get_root_instance().wait_select_single(
52+ edge='top', active=True)
53+
54+
55+class TopEdgeDemoOverlay(
56+ ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
57+
58+ @classmethod
59+ def validate_dbus_object(cls, path, state):
60+ name = introspection.get_classname_from_path(path)
61+ if name == b'EdgeDemoOverlay':
62+ if state['edge'][1] == 'top':
63+ return True
64+ return False
65+
66+ @autopilot.logging.log_action(logger.info)
67+ def swipe(self):
68+ """Swipe to the bottom to complete this demo step."""
69+ x, y, width, height = self.globalRect
70+ start_x = stop_x = x + width // 2
71+ start_y = y
72+ stop_y = y + height
73+ self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
74+ return self.get_root_instance().wait_select_single(
75+ edge='bottom', active=True)
76+
77+
78+class BottomEdgeDemoOverlay(
79+ ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
80+
81+ @classmethod
82+ def validate_dbus_object(cls, path, state):
83+ name = introspection.get_classname_from_path(path)
84+ if name == b'EdgeDemoOverlay':
85+ if state['edge'][1] == 'bottom':
86+ return True
87+ return False
88+
89+ @autopilot.logging.log_action(logger.info)
90+ def swipe(self):
91+ """Swipe to the top to complete this demo step."""
92+ x, y, width, height = self.globalRect
93+ start_x = stop_x = x + width // 2
94+ start_y = y + height
95+ stop_y = y
96+ self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
97+ return self.get_root_instance().wait_select_single(
98+ edge='left', active=True)
99+
100+
101+class LeftEdgeDemoOverlay(
102+ ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
103+
104+ @classmethod
105+ def validate_dbus_object(cls, path, state):
106+ name = introspection.get_classname_from_path(path)
107+ if name == b'EdgeDemoOverlay':
108+ if state['edge'][1] == 'left':
109+ return True
110+ return False
111+
112+ @autopilot.logging.log_action(logger.info)
113+ def swipe(self):
114+ """Swipe to the right to complete this demo step."""
115+ x, y, width, height = self.globalRect
116+ start_x = x
117+ stop_x = x + width
118+ start_y = stop_y = y + height // 2
119+ self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
120+ return self.get_root_instance().wait_select_single(
121+ edge='none', active=True)
122+
123+
124+class FinalEdgeDemoOverlay(
125+ ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
126+
127+ @classmethod
128+ def validate_dbus_object(cls, path, state):
129+ name = introspection.get_classname_from_path(path)
130+ if name == b'EdgeDemoOverlay':
131+ if state['edge'][1] == 'none':
132+ return True
133+ return False
134+
135+ @autopilot.logging.log_action(logger.info)
136+ def tap_to_start(self):
137+ """Tap to finish the demo and start using the Ubuntu Touch."""
138+ time.sleep(1)
139+ self.pointing_device.click_object(self)
140+ self.shown.wait_for(False)
tests/autopilot/unity8/shell/fixture_setup.py+38
@@ -20,6 +20,7 @@
2020"""Set up and clean up fixtures for the Unity acceptance tests."""
2121
2222import os
23+import subprocess
2324import sysconfig
2425
2526import fixtures
@@ -51,3 +52,40 @@ class FakeScopes(fixtures.Fixture):
5152 'Expected library path does not exists: %s.' % (
5253 ld_library_path))
5354 return ld_library_path
55+
56+
57+class EdgesDemo(fixtures.Fixture):
58+
59+ def __init__(self, enable):
60+ super().__init__()
61+ self.enable = enable
62+
63+ def setUp(self):
64+ super().setUp()
65+ original_state = self._is_edges_demo_enabled()
66+ if self.enable != original_state:
67+ self.addCleanup(self._set_edges_demo, original_state)
68+ self._set_edges_demo(self.enable)
69+
70+ def _is_edges_demo_enabled(self):
71+ command = [
72+ 'dbus-send', '--system', '--print-reply',
73+ '--dest=org.freedesktop.Accounts',
74+ '/org/freedesktop/Accounts/User32011',
75+ 'org.freedesktop.DBus.Properties.Get',
76+ 'string:com.canonical.unity.AccountsService',
77+ 'string:demo-edges'
78+ ]
79+ output = subprocess.check_output(command, universal_newlines=True)
80+ return True if output.count('true') else False
81+
82+ def _set_edges_demo(self, value):
83+ value_string = 'true' if value else 'false'
84+ command = [
85+ 'dbus-send', '--system', '--print-reply',
86+ '--dest=com.canonical.PropertyService',
87+ '/com/canonical/PropertyService',
88+ 'com.canonical.PropertyService.SetProperty',
89+ 'string:edge', 'boolean:{}'.format(value_string)
90+ ]
91+ subprocess.check_output(command)
tests/autopilot/unity8/shell/tests/test_edges_demo.pynew file+52
@@ -0,0 +1,52 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2014 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+from autopilot.matchers import Eventually
21+from testtools.matchers import Equals
22+
23+from unity8.shell import (
24+ fixture_setup,
25+ tests
26+)
27+# unused import to load the edge emulators custom proxy objects.
28+from unity8.shell.emulators import edges_demo # NOQA
29+
30+
31+class EdgesDemoTestCase(tests.UnityTestCase):
32+
33+ def setUp(self):
34+ super(EdgesDemoTestCase, self).setUp()
35+ self._qml_mock_enabled = False
36+ self._data_dirs_mock_enabled = False
37+ self._lightdm_mock_type = False
38+
39+ self.useFixture(fixture_setup.EdgesDemo(True))
40+ self.unity = self.launch_unity()
41+
42+ def test_complete_edge_demo(self):
43+ edge_demo = self.unity.select_single('EdgeDemo')
44+ self.assertThat(edge_demo.running, Eventually(Equals(True)))
45+ right_edge_overlay = self.unity.wait_select_single(
46+ edge='right', active=True)
47+ top_edge_overlay = right_edge_overlay.swipe()
48+ bottom_edge_overlay = top_edge_overlay.swipe()
49+ left_edge_overlay = bottom_edge_overlay.swipe()
50+ final_overlay = left_edge_overlay.swipe()
51+ final_overlay.tap_to_start()
52+ self.assertThat(edge_demo.running, Eventually(Equals(False)))
tests/mocks/CMakeLists.txt+1
@@ -32,6 +32,7 @@ add_subdirectory(AccountsService)
3232add_subdirectory(GSettings.1.0)
3333add_subdirectory(libusermetrics)
3434add_subdirectory(LightDM)
35+add_subdirectory(Lights)
3536add_subdirectory(MeeGo)
3637add_subdirectory(Powerd)
3738add_subdirectory(QMenuModel)
tests/mocks/LightDM/CMakeLists.txt+1−1
@@ -24,7 +24,7 @@ set(QMLPLUGIN_SRC
2424 ${CMAKE_SOURCE_DIR}/plugins/LightDM/Greeter.cpp
2525 ${CMAKE_SOURCE_DIR}/plugins/LightDM/plugin.cpp
2626 ${CMAKE_SOURCE_DIR}/plugins/LightDM/UsersModel.cpp
27− ${CMAKE_SOURCE_DIR}/plugins/Utils/qsortfilterproxymodelqml.cpp
27+ ${CMAKE_SOURCE_DIR}/plugins/Utils/unitysortfilterproxymodelqml.cpp
2828 )
2929
3030add_library(MockLightDM-qml MODULE
tests/mocks/LightDM/Greeter.cpp+6
@@ -129,6 +129,12 @@ void Greeter::authenticate(const QString &username)
129129 d->authenticated = false;
130130 d->authenticationUser = username;
131131 d->twoFactorDone = false;
132+ QTimer::singleShot(0, this, SLOT(delayedAuthentication()));
133+}
134+
135+void Greeter::delayedAuthentication()
136+{
137+ Q_D(Greeter);
132138 d->handleAuthenticate();
133139}
134140
tests/mocks/LightDM/Greeter.h+3
@@ -99,6 +99,9 @@ Q_SIGNALS:
9999protected:
100100 void sendAuthenticationComplete();
101101
102+private Q_SLOTS:
103+ void delayedAuthentication();
104+
102105private:
103106 GreeterPrivate *d_ptr;
104107 Q_DECLARE_PRIVATE(Greeter)
tests/mocks/LightDM/demo/CMakeLists.txt+1
@@ -28,6 +28,7 @@ target_link_libraries(MockLightDM-demo-shared
2828qt5_use_modules(MockLightDM-demo Concurrent Gui)
2929qt5_use_modules(MockLightDM-demo-shared Concurrent Gui)
3030
31+set_target_properties(MockLightDM-demo PROPERTIES COMPILE_FLAGS -fPIC)
3132set_target_properties(MockLightDM-demo-shared PROPERTIES
3233 OUTPUT_NAME lightdm-qt5-2)
3334
tests/mocks/Lights/CMakeLists.txtnew file+8
@@ -0,0 +1,8 @@
1+add_library(MockLights-qml MODULE
2+ plugin.cpp
3+ Lights.cpp
4+ )
5+
6+qt5_use_modules(MockLights-qml Qml Gui)
7+
8+add_unity8_mock(Lights 0.1 Lights TARGETS MockLights-qml)
tests/mocks/Lights/Lights.cppnew file+84
@@ -0,0 +1,84 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "Lights.h"
18+
19+#include <QDebug>
20+
21+Lights::Lights(QObject* parent)
22+ : QObject(parent),
23+ m_color("blue"),
24+ m_state(Lights::Off),
25+ m_onMs(1000),
26+ m_offMs(3000)
27+{
28+}
29+
30+Lights::~Lights()
31+{
32+}
33+
34+void Lights::setState(Lights::State newState)
35+{
36+ if (m_state != newState) {
37+ m_state = newState;
38+ Q_EMIT stateChanged(m_state);
39+ }
40+}
41+
42+Lights::State Lights::state() const
43+{
44+ return m_state;
45+}
46+
47+void Lights::setColor(const QColor &color)
48+{
49+ if (m_color != color) {
50+ m_color = color;
51+ Q_EMIT colorChanged(m_color);
52+ }
53+}
54+
55+QColor Lights::color() const
56+{
57+ return m_color;
58+}
59+
60+int Lights::onMillisec() const
61+{
62+ return m_onMs;
63+}
64+
65+void Lights::setOnMillisec(int onMs)
66+{
67+ if (m_onMs != onMs) {
68+ m_onMs = onMs;
69+ Q_EMIT onMillisecChanged(m_onMs);
70+ }
71+}
72+
73+int Lights::offMillisec() const
74+{
75+ return m_offMs;
76+}
77+
78+void Lights::setOffMillisec(int offMs)
79+{
80+ if (m_offMs != offMs) {
81+ m_offMs = offMs;
82+ Q_EMIT offMillisecChanged(m_offMs);
83+ }
84+}
tests/mocks/Lights/Lights.hnew file+66
@@ -0,0 +1,66 @@
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+#ifndef UNITY_MOCK_LIGHTS_H
18+#define UNITY_MOCK_LIGHTS_H
19+
20+#include <QtCore/QObject>
21+#include <QtGui/QColor>
22+
23+class Lights: public QObject
24+{
25+ Q_OBJECT
26+ Q_ENUMS(State)
27+ Q_PROPERTY(State state READ state WRITE setState NOTIFY stateChanged)
28+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
29+ Q_PROPERTY(int onMillisec READ onMillisec WRITE setOnMillisec NOTIFY onMillisecChanged)
30+ Q_PROPERTY(int offMillisec READ offMillisec WRITE setOffMillisec NOTIFY offMillisecChanged)
31+
32+public:
33+ enum State {
34+ Off,
35+ On,
36+ };
37+
38+ explicit Lights(QObject *parent = 0);
39+ ~Lights();
40+
41+ void setState(State newState);
42+ State state() const;
43+
44+ void setColor(const QColor &color);
45+ QColor color() const;
46+
47+ int onMillisec() const;
48+ void setOnMillisec(int onMs);
49+
50+ int offMillisec() const;
51+ void setOffMillisec(int offMs);
52+
53+Q_SIGNALS:
54+ void stateChanged(State newState);
55+ void colorChanged(const QColor &color);
56+ void onMillisecChanged(int onMs);
57+ void offMillisecChanged(int offMs);
58+
59+private:
60+ QColor m_color;
61+ State m_state;
62+ int m_onMs;
63+ int m_offMs;
64+};
65+
66+#endif
tests/mocks/Lights/Lights.qmltypesnew file+45
@@ -0,0 +1,45 @@
1+import QtQuick.tooling 1.1
2+
3+// This file describes the plugin-supplied types contained in the library.
4+// It is used for QML tooling purposes only.
5+//
6+// This file was auto-generated by:
7+// 'qmlplugindump -notrelocatable Lights 0.1 tests/mocks'
8+
9+Module {
10+ Component {
11+ name: "Lights"
12+ prototype: "QObject"
13+ exports: ["Lights/Lights 0.1"]
14+ isCreatable: false
15+ isSingleton: true
16+ exportMetaObjectRevisions: [0]
17+ Enum {
18+ name: "State"
19+ values: {
20+ "Off": 0,
21+ "On": 1
22+ }
23+ }
24+ Property { name: "state"; type: "State" }
25+ Property { name: "color"; type: "QColor" }
26+ Property { name: "onMillisec"; type: "int" }
27+ Property { name: "offMillisec"; type: "int" }
28+ Signal {
29+ name: "stateChanged"
30+ Parameter { name: "newState"; type: "State" }
31+ }
32+ Signal {
33+ name: "colorChanged"
34+ Parameter { name: "color"; type: "QColor" }
35+ }
36+ Signal {
37+ name: "onMillisecChanged"
38+ Parameter { name: "onMs"; type: "int" }
39+ }
40+ Signal {
41+ name: "offMillisecChanged"
42+ Parameter { name: "offMs"; type: "int" }
43+ }
44+ }
45+}
tests/mocks/Lights/plugin.cppnew file+33
@@ -0,0 +1,33 @@
1+/*
2+ * Copyright (C) 2012,2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "plugin.h"
18+#include "Lights.h"
19+
20+#include <QtQml/qqml.h>
21+
22+static QObject *lights_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
23+{
24+ Q_UNUSED(engine)
25+ Q_UNUSED(scriptEngine)
26+ return new Lights();
27+}
28+
29+void PowerdPlugin::registerTypes(const char *uri)
30+{
31+ Q_ASSERT(uri == QLatin1String("Lights"));
32+ qmlRegisterSingletonType<Lights>(uri, 0, 1, "Lights", lights_provider);
33+}
tests/mocks/Lights/plugin.hnew file+32
@@ -0,0 +1,32 @@
1+/*
2+ * Copyright (C) 2012,2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef MOCK_POWER_PLUGIN_H
18+#define MOCK_POWER_PLUGIN_H
19+
20+#include <QtQml/QQmlEngine>
21+#include <QtQml/QQmlExtensionPlugin>
22+
23+class PowerdPlugin : public QQmlExtensionPlugin
24+{
25+ Q_OBJECT
26+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
27+
28+public:
29+ void registerTypes(const char *uri);
30+};
31+
32+#endif
tests/mocks/Lights/qmldirnew file+3
@@ -0,0 +1,3 @@
1+module Lights
2+plugin MockLights-qml
3+typeinfo Lights.qmltypes
tests/mocks/QMenuModel/CMakeLists.txt+1
@@ -4,6 +4,7 @@ include_directories(
44)
55
66set(QMenuModelQml_SOURCES
7+ actiondata.h
78 actionstateparser.cpp
89 dbus-enums.h
910 plugin.cpp
tests/mocks/QMenuModel/QDBusActionGroup.qml+20−67
@@ -19,81 +19,34 @@
1919
2020import QtQuick 2.0
2121import Ubuntu.Settings.Menus 0.1 as Menus
22+import QMenuModel 0.1
2223
2324QtObject {
2425 id: actionGroup
2526 property int busType
2627 property string busName
2728 property string objectPath
29+ property var actions: ActionData ? ActionData.data : undefined
30+
31+ signal dataChanged
32+
2833 function start() {}
34+
2935 function action(actionName) {
30− switch (actionName) {
31− case "transfer-state.queued":
32− return {
33− 'valid': true,
34− 'state': {
35− 'state': Menus.TransferState.Queued,
36− 'percent': 0.0
37− }
38− }
39− case "transfer-state.running":
40− return {
41− 'valid': true,
42− 'state': {
43− 'state': Menus.TransferState.Running,
44− 'seconds-left': 100,
45− 'percent': 0.1
46− }
47− }
48− case "transfer-state.paused":
49− return {
50− 'valid': true,
51− 'state': {
52− 'state': Menus.TransferState.Paused,
53− 'seconds-left': 100,
54− 'percent': 0.5
55− }
56− }
57− case "transfer-state.cancelled":
58− return {
59− 'valid': true,
60− 'state': {
61− 'state': Menus.TransferState.Canceled,
62− 'percent': 0.4
63− }
64− }
65− case "transfer-state.finished": return {
66− 'valid': true,
67− 'state': {
68− 'state': Menus.TransferState.Finished,
69− 'seconds-left': 0,
70− 'percent': 1.0
71− }
72− }
73− case "transfer-state.error":
74− return {
75− 'valid': true,
76− 'state': {
77− 'state': Menus.TransferState.Error,
78− 'seconds-left': 100,
79− 'percent': 0.0
80− }
81− }
82− case "gps-detection-enabled":
83− case "location-detection-enabled":
84− return Qt.createQmlObject("
85−import QtQuick 2.3
86−QtObject {
87− property bool valid: true
88− property bool state: false
89− function activate() {
90− state = !state;
91− }
92−}", actionGroup);
93− default:
94− break;
95− }
36+ return Qt.createQmlObject("
37+ import QtQuick 2.3
38+ import QMenuModel 0.1
39+
40+ QtObject {
41+ signal activated
42+
43+ property string actionName: \"" + actionName + "\"
44+ property bool valid: ActionData.data[actionName] != undefined ? ActionData.data[actionName].valid : false
45+ property var state: ActionData.data[actionName] != undefined ? ActionData.data[actionName].state : undefined
9646
97− return null;
47+ function activate() {
48+ activated();
49+ }
50+ }", actionGroup);
9851 }
9952}
tests/mocks/QMenuModel/actiondata.hnew file+52
@@ -0,0 +1,52 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Nick Dedekind <nick.dedekind@canonical.com>
17+ */
18+
19+#ifndef ACTIONDATA_H
20+#define ACTIONDATA_H
21+
22+#include <QObject>
23+#include <QVariant>
24+
25+typedef struct _GVariant GVariant;
26+
27+class Q_DECL_EXPORT ActionData : public QObject
28+{
29+ Q_OBJECT
30+ Q_PROPERTY(QVariant data READ data WRITE setData NOTIFY dataChanged)
31+public:
32+ ActionData(QObject* parent = 0)
33+ : QObject(parent)
34+ {}
35+
36+ QVariant data() const { return m_data; }
37+ void setData(const QVariant& data)
38+ {
39+ if (m_data != data) {
40+ m_data = data;
41+ Q_EMIT dataChanged();
42+ }
43+ }
44+
45+Q_SIGNALS:
46+ void dataChanged();
47+
48+private:
49+ QVariant m_data;
50+};
51+
52+#endif // ACTIONDATA_H
tests/mocks/QMenuModel/plugin.cpp+10
@@ -18,11 +18,19 @@
1818
1919#include "plugin.h"
2020#include "unitymenumodel.h"
21+#include "actiondata.h"
2122#include "actionstateparser.h"
2223#include "dbus-enums.h"
2324
2425#include <QtQml/qqml.h>
2526
27+static QObject* actionDataSingleton(QQmlEngine* engine, QJSEngine* scriptEngine)
28+{
29+ Q_UNUSED(engine);
30+ Q_UNUSED(scriptEngine);
31+ return new ActionData;
32+}
33+
2634void QMenuModelPlugin::registerTypes(const char *uri)
2735{
2836 Q_ASSERT(uri == QLatin1String("QMenuModel"));
@@ -30,4 +38,6 @@ void QMenuModelPlugin::registerTypes(const char *uri)
3038 "DBus is only a namespace");
3139 qmlRegisterType<UnityMenuModel>(uri, 0, 1, "UnityMenuModel");
3240 qmlRegisterType<ActionStateParser>(uri, 0, 1, "ActionStateParser");
41+
42+ qmlRegisterSingletonType<ActionData>(uri, 0, 1, "ActionData", actionDataSingleton);
3343}
tests/mocks/Unity/Indicators/ActionRootState.qmlnew file+46
@@ -0,0 +1,46 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Nick Dedekind <nick.dedekind@canonical.com>
18+ */
19+
20+import QtQuick 2.0
21+
22+QtObject {
23+ property var actionGroup
24+ property var actionName
25+
26+ property var action: actionGroup ? actionGroup.actions[actionName] : undefined
27+ property var state: action && action.hasOwnProperty("state") ? action.state : undefined
28+
29+ property bool valid: action && action.hasOwnProperty("valid") ? action.valid : false
30+ property string title: state && state.hasOwnProperty("title") ? state["title"] : ""
31+ property string leftLabel: state && state.hasOwnProperty("pre-label") ? state["pre-label"] : ""
32+ property string rightLabel: state && state.hasOwnProperty("label") ? state["label"] : ""
33+ property var icons: state && state.hasOwnProperty("icons") ? state["icons"] : []
34+ property string accessibleName: state && state.hasOwnProperty("accessible-desc") ? state["accessible-desc"] : ""
35+ property bool visible: state && state.hasOwnProperty("visible") ? state["visible"] : true
36+
37+ signal updated
38+
39+ onValidChanged: updated()
40+ onTitleChanged: updated()
41+ onLeftLabelChanged: updated()
42+ onRightLabelChanged: updated()
43+ onIconsChanged: updated()
44+ onAccessibleNameChanged: updated()
45+ onVisibleChanged: updated()
46+}
tests/mocks/Unity/Indicators/RootActionState.qml → tests/mocks/Unity/Indicators/ModelActionRootState.qmlrenamed

The content is the same.

tests/mocks/Unity/Indicators/qmldir+2−1
@@ -2,5 +2,6 @@ module Unity.Indicators
22plugin IndicatorsFakeQml
33typeinfo Indicators.qmltypes
44
5+ActionRootState 0.1 ActionRootState.qml
56IndicatorsModel 0.1 IndicatorsModel.qml
6−RootActionState 0.1 RootActionState.qml
7+ModelActionRootState 0.1 ModelActionRootState.qml
tests/plugins/LightDM/CMakeLists.txt+4−8
@@ -1,8 +1,8 @@
1−add_executable(test-lightdm-dbus
1+add_executable(GreeterDBusTestExec
22 dbus.cpp
33 ${CMAKE_SOURCE_DIR}/plugins/LightDM/Greeter.cpp
44 )
5−qt5_use_modules(test-lightdm-dbus Core DBus Quick Test)
5+qt5_use_modules(GreeterDBusTestExec Core DBus Quick Test)
66
77include_directories(
88 ${CMAKE_CURRENT_BINARY_DIR}
@@ -11,15 +11,11 @@ include_directories(
1111 ${LIBLIGHTDM_INCLUDE_DIRS}
1212 )
1313
14−add_dependencies(test-lightdm-dbus MockLightDM-full)
15−target_link_libraries(test-lightdm-dbus
14+target_link_libraries(GreeterDBusTestExec
1615 -L${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full
1716 -llightdm-qt5-2
1817 )
1918
2019add_definitions(-DCURRENT_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
2120
22−add_custom_target(testLightDMDBus xvfb-run --server-args "-screen 0 1024x768x24" --auto-servernum dbus-launch env QML2_IMPORT_PATH=${CMAKE_BINARY_DIR}/tests/mocks LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full ${CMAKE_CURRENT_BINARY_DIR}/test-lightdm-dbus)
23−add_dependencies(testLightDMDBus test-lightdm-dbus)
24−
25−add_dependencies(qmluitests testLightDMDBus)
21+add_binary_qml_test(GreeterDBus "${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full" MockLightDM-full "QML2_IMPORT_PATH=${CMAKE_BINARY_DIR}/tests/mocks")
tests/plugins/LightDM/dbus.cpp+11−2
@@ -16,6 +16,7 @@
1616
1717#include "Greeter.h"
1818
19+#include <QCoreApplication>
1920#include <QDBusInterface>
2021#include <QDBusReply>
2122#include <QSignalSpy>
@@ -149,9 +150,11 @@ private Q_SLOTS:
149150 QVERIFY(dbusList->property("EntryIsLocked").toBool());
150151
151152 greeter->authenticate("no-password");
153+ QCoreApplication::processEvents(); // wait for auth to finish
152154 QVERIFY(!dbusList->property("EntryIsLocked").toBool());
153155
154156 greeter->authenticate("has-password");
157+ QCoreApplication::processEvents(); // wait for auth to finish
155158 QVERIFY(dbusList->property("EntryIsLocked").toBool());
156159 }
157160
@@ -159,10 +162,16 @@ private Q_SLOTS:
159162 {
160163 QSignalSpy spy(this, SIGNAL(PropertiesChangedRelay(QString, QVariantMap, QStringList)));
161164 greeter->authenticate("no-password");
165+
166+ // Two property changed signals will be emitted, one for the IsLocked
167+ // property, one for the ActiveEntry; the first will be IsLocked.
162168 spy.wait();
169+ if (spy.count() < 2) {
170+ spy.wait();
171+ }
172+ QCOMPARE(spy.count(), 2);
163173
164− QCOMPARE(spy.count(), 2); // once for locked, once for user; first will be locked mode
165− QList<QVariant> arguments = spy.takeFirst();
174+ QList<QVariant> arguments = spy.takeLast();
166175 QVERIFY(arguments.at(0).toString() == "com.canonical.UnityGreeter.List");
167176 QVERIFY(arguments.at(1).toMap().contains("EntryIsLocked"));
168177 QVERIFY(arguments.at(1).toMap()["EntryIsLocked"] == false);
tests/plugins/Unity/Indicators/rootactionstatetest.cpp+4−4
@@ -17,7 +17,7 @@
1717 * Nick Dedekind <nick.dedekind@canonical.com>
1818 */
1919
20−#include "rootactionstate.h"
20+#include "modelactionrootstate.h"
2121
2222#include <unitymenumodel.h>
2323#include <QtTest>
@@ -32,7 +32,7 @@ private Q_SLOTS:
3232 {
3333 UnityMenuModel* menuModel = new UnityMenuModel();
3434 ActionStateParser* originalParser = menuModel->actionStateParser();
35− RootActionState* rootState = new RootActionState();
35+ ModelActionRootState* rootState = new ModelActionRootState();
3636
3737 rootState->setMenu(menuModel);
3838
@@ -44,7 +44,7 @@ private Q_SLOTS:
4444 void testDeleteUnityMenuModel()
4545 {
4646 UnityMenuModel* menuModel = new UnityMenuModel();
47− RootActionState* rootState = new RootActionState();
47+ ModelActionRootState* rootState = new ModelActionRootState();
4848
4949 rootState->setMenu(menuModel);
5050
@@ -77,7 +77,7 @@ private Q_SLOTS:
7777
7878 GVariant* params = g_variant_builder_end (&builderParams);
7979
80− RootActionState rootState;
80+ RootStateParser rootState;
8181 QVariant result = rootState.toQVariant(params);
8282 g_variant_unref(params);
8383
tests/plugins/Utils/CMakeLists.txt+1−1
@@ -23,7 +23,7 @@ endmacro(run_tests)
2323
2424run_tests(
2525 qlimitproxymodeltest
26− qsortfilterproxymodeltest
26+ unitysortfilterproxymodeltest
2727 timeformattertest
2828 )
2929
tests/plugins/Utils/qsortfilterproxymodeltest.cpp → tests/plugins/Utils/unitysortfilterproxymodeltest.cpprenamed+14−14
@@ -18,7 +18,7 @@
1818 */
1919
2020// local
21−#include "qsortfilterproxymodelqml.h"
21+#include "unitysortfilterproxymodelqml.h"
2222#include "modeltest.h"
2323
2424// Qt
@@ -91,7 +91,7 @@ private:
9191 QHash<int, QByteArray> m_roles;
9292};
9393
94−class QSortFilterProxyModelTest : public QObject
94+class UnitySortFilterProxyModelTest : public QObject
9595{
9696 Q_OBJECT
9797
@@ -103,7 +103,7 @@ private Q_SLOTS:
103103
104104 void testRoleNamesSetAfter()
105105 {
106− QSortFilterProxyModelQML proxy;
106+ UnitySortFilterProxyModelQML proxy;
107107 MockListModel model;
108108 QHash<int, QByteArray> roles;
109109
@@ -117,7 +117,7 @@ private Q_SLOTS:
117117
118118 void testRoleNamesSetBefore()
119119 {
120− QSortFilterProxyModelQML proxy;
120+ UnitySortFilterProxyModelQML proxy;
121121 MockListModel model;
122122 QHash<int, QByteArray> roles;
123123
@@ -131,7 +131,7 @@ private Q_SLOTS:
131131
132132 void testCountSetAfter()
133133 {
134− QSortFilterProxyModelQML proxy;
134+ UnitySortFilterProxyModelQML proxy;
135135 MockListModel model;
136136 model.insertRows(0, 5);
137137
@@ -144,7 +144,7 @@ private Q_SLOTS:
144144
145145 void testCountInsert()
146146 {
147− QSortFilterProxyModelQML proxy;
147+ UnitySortFilterProxyModelQML proxy;
148148 MockListModel model;
149149
150150 proxy.setModel(&model);
@@ -158,7 +158,7 @@ private Q_SLOTS:
158158
159159 void testCountRemove()
160160 {
161− QSortFilterProxyModelQML proxy;
161+ UnitySortFilterProxyModelQML proxy;
162162 MockListModel model;
163163 model.insertRows(0, 5);
164164
@@ -173,7 +173,7 @@ private Q_SLOTS:
173173 }
174174
175175 void testInvertMatch() {
176− QSortFilterProxyModelQML proxy;
176+ UnitySortFilterProxyModelQML proxy;
177177 MockListModel model;
178178
179179 proxy.setModel(&model);
@@ -215,7 +215,7 @@ private Q_SLOTS:
215215 }
216216
217217 void testNestedProxyRoleNames() {
218− QSortFilterProxyModelQML proxy1, proxy2;
218+ UnitySortFilterProxyModelQML proxy1, proxy2;
219219 MockListModel model;
220220 QHash<int, QByteArray> roles;
221221 roles[0] = "role0";
@@ -229,7 +229,7 @@ private Q_SLOTS:
229229 }
230230
231231 void testModelTest() {
232− QSortFilterProxyModelQML proxy;
232+ UnitySortFilterProxyModelQML proxy;
233233 MockListModel model;
234234
235235 proxy.setModel(&model);
@@ -246,7 +246,7 @@ private Q_SLOTS:
246246 }
247247
248248 void testModelChanged() {
249− QSortFilterProxyModelQML proxy;
249+ UnitySortFilterProxyModelQML proxy;
250250 MockListModel model, model2;
251251
252252 QSignalSpy spyOnModelChanged(&proxy, SIGNAL(modelChanged()));
@@ -265,7 +265,7 @@ private Q_SLOTS:
265265 }
266266
267267 void testData() {
268− QSortFilterProxyModelQML proxy;
268+ UnitySortFilterProxyModelQML proxy;
269269 MockListModel model, model2;
270270
271271 QStringList rows;
@@ -285,6 +285,6 @@ private Q_SLOTS:
285285 }
286286};
287287
288−QTEST_GUILESS_MAIN(QSortFilterProxyModelTest)
288+QTEST_GUILESS_MAIN(UnitySortFilterProxyModelTest)
289289
290−#include "qsortfilterproxymodeltest.moc"
290+#include "unitysortfilterproxymodeltest.moc"
tests/qmltests/CMakeLists.txt+1
@@ -79,6 +79,7 @@ add_qml_test(Panel IndicatorsMenu ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DI
7979add_qml_test(Panel MenuContent ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
8080add_qml_test(Panel Panel ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
8181add_qml_test(Panel SearchIndicator)
82+add_qml_test(Panel/Indicators IndicatorsLight ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
8283# These MenuItemFactory tests need the test/mocks/ to come before plugins/
8384add_qml_test(Panel/Indicators MenuItemFactory IMPORT_PATHS ${CMAKE_BINARY_DIR}/tests/mocks ${qmltest_DEFAULT_IMPORT_PATHS})
8485add_qml_test(Panel/Indicators MessageMenuItemFactory IMPORT_PATHS ${CMAKE_BINARY_DIR}/tests/mocks ${qmltest_DEFAULT_IMPORT_PATHS})
tests/qmltests/Components/tst_Carousel.qml+5−5
@@ -274,20 +274,20 @@ Item {
274274
275275 spy.signalName = "clicked";
276276 spy.target = carouselItem;
277− mouseClick(carouselItem, carouselItem.width / 2, carouselItem.height / 2);
277+ mouseClick(carouselItem);
278278 tryCompare(carouselList, "moving", false);
279279 tryCompare(carouselItem, "explicitlyScaled", true);
280− mouseClick(carouselItem, carouselItem.width / 2, carouselItem.height / 2);
280+ mouseClick(carouselItem);
281281 spy.wait();
282282
283283 spy.signalName = "pressAndHold";
284284 spy.target = carouselItem;
285− mouseClick(carouselItem, carouselItem.width / 2, carouselItem.height / 2);
285+ mouseClick(carouselItem);
286286 tryCompare(carouselList, "moving", false);
287287 tryCompare(carouselItem, "explicitlyScaled", true);
288− mousePress(carouselItem, carouselItem.width / 2, carouselItem.height / 2);
288+ mousePress(carouselItem);
289289 spy.wait();
290− mouseRelease(carouselItem, carouselItem.width / 2, carouselItem.height / 2);
290+ mouseRelease(carouselItem);
291291 }
292292 }
293293}
tests/qmltests/Components/tst_Lockscreen.qml+1−1
@@ -421,7 +421,7 @@ Rectangle {
421421 signalSpy.clear();
422422
423423 var okButton = findChild(root, "infoPopupOkButton");
424− mouseClick(okButton, okButton.width / 2, okButton.height / 2);
424+ mouseClick(okButton);
425425
426426 tryCompareFunction(function() { return findChild(root, "infoPopup") === null}, true);
427427
tests/qmltests/Components/tst_ResponsiveVerticalJournal.qml+1−1
@@ -79,7 +79,7 @@ Item {
7979 ListElement { name: "U" }
8080 }
8181
82− SortFilterProxyModel {
82+ UnitySortFilterProxyModel {
8383 id: wrappedFakeModel
8484 model: fakeModel
8585 }
tests/qmltests/Dash/Previews/tst_PreviewActions.qml+3−3
@@ -104,7 +104,7 @@ Rectangle {
104104 var button = findChild(root, "button" + id);
105105 verify(button != null);
106106 spy.target = target;
107− mouseClick(button, button.width / 2, button.height / 2);
107+ mouseClick(button);
108108 compare(spy.count, 1);
109109 compare(spy.signalArguments[0][0], target.widgetId);
110110 compare(spy.signalArguments[0][1], id);
@@ -137,11 +137,11 @@ Rectangle {
137137 var buttonColumn = findChild(root, "buttonColumn");
138138 verify(button != null);
139139 var twoActionsY = twoActions.y
140− mouseClick(button, button.width / 2, button.height / 2);
140+ mouseClick(button);
141141 tryCompareFunction(function () { return twoActions.y <= twoActionsY; }, false);
142142 tryCompare(buttonColumn, "height", buttonColumn.implicitHeight);
143143 checkButtonPressSignal(buttonAndCombo, data.id, data.buttonNumber);
144− mouseClick(button, button.width / 2, button.height / 2);
144+ mouseClick(button);
145145 tryCompare(twoActions, "y", twoActionsY);
146146 }
147147 }
tests/qmltests/Dash/Previews/tst_PreviewAudioPlayback.qml+5−5
@@ -131,7 +131,7 @@ Rectangle {
131131 compare(track2ProgressBar.visible, false);
132132
133133 // Playing track 0 should make progress bar 0 visible
134− mouseClick(track0PlayButton, track0PlayButton.width / 2, track0PlayButton.height / 2);
134+ mouseClick(track0PlayButton);
135135
136136 tryCompare(audio, "playbackState", Audio.PlayingState);
137137 checkPlayerSource(0);
@@ -141,18 +141,18 @@ Rectangle {
141141 tryCompare(track2ProgressBar, "visible", false);
142142
143143 // Clicking the button again should pause it. The progress bar should stay visible
144− mouseClick(track0PlayButton, track0PlayButton.width / 2, track0PlayButton.height / 2);
144+ mouseClick(track0PlayButton);
145145 tryCompare(audio, "playbackState", Audio.PausedState);
146146 checkPlayerSource(0);
147147 tryCompare(track0ProgressBar, "visible", true);
148148
149149 // Continue playback
150− mouseClick(track0PlayButton, track0PlayButton.width / 2, track0PlayButton.height / 2);
150+ mouseClick(track0PlayButton);
151151 tryCompare(audio, "playbackState", Audio.PlayingState);
152152 checkPlayerSource(0);
153153
154154 // Playing track 1 should make progress bar 1 visible and hide progress bar 0 again
155− mouseClick(track1PlayButton, track1PlayButton.width / 2, track1PlayButton.height / 2);
155+ mouseClick(track1PlayButton);
156156
157157 tryCompare(audio, "playbackState", Audio.PlayingState);
158158 checkPlayerSource(1);
@@ -162,7 +162,7 @@ Rectangle {
162162 tryCompare(track2ProgressBar, "visible", false);
163163
164164 // Playing track 2 should make progress bar 1 visible and hide progress bar 0 again
165− mouseClick(track2PlayButton, track2PlayButton.width / 2, track2PlayButton.height / 2);
165+ mouseClick(track2PlayButton);
166166
167167 tryCompare(audio, "playbackState", Audio.PlayingState);
168168 checkPlayerSource(2);
tests/qmltests/Dash/Previews/tst_PreviewExpandable.qml+2−2
@@ -85,7 +85,7 @@ Rectangle {
8585
8686 function test_expand_collapse() {
8787 var expandButton = findChild(previewExpandable, "expandButton")
88− mouseClick(expandButton, expandButton.width / 2, expandButton.height / 2);
88+ mouseClick(expandButton);
8989
9090 var repeater = findChild(previewExpandable, "repeater")
9191 compare(repeater.count, 4)
@@ -99,7 +99,7 @@ Rectangle {
9999 compare (repeater.itemAt(2).expanded, true);
100100 compare (repeater.itemAt(3).expanded, true);
101101
102− mouseClick(expandButton, expandButton.width / 2, expandButton.height / 2);
102+ mouseClick(expandButton);
103103
104104 checkInitialState();
105105 }
tests/qmltests/Dash/Previews/tst_PreviewImageGallery.qml+6−6
@@ -67,23 +67,23 @@ Rectangle {
6767
6868 function test_overlayOpenClose() {
6969 var image0 = findChild(imageGallery, "previewImage0");
70− mouseClick(image0, image0.width / 2, image0.height / 2);
70+ mouseClick(image0);
7171 tryCompare(overlay, "visible", true);
7272 tryCompare(overlay, "scale", 1.0);
7373 tryCompare(overlayCloseButton, "visible", true);
74− mouseClick(overlayCloseButton, overlayCloseButton.width / 2, overlayCloseButton.height / 2);
74+ mouseClick(overlayCloseButton);
7575 tryCompare(overlay, "visible", false);
7676 }
7777
7878 function test_overlayShowHideHeader() {
7979 var image0 = findChild(imageGallery, "previewImage0");
80− mouseClick(image0, image0.width / 2, image0.height / 2);
80+ mouseClick(image0);
8181 tryCompare(overlay, "visible", true);
8282 tryCompare(overlay, "scale", 1.0);
8383 tryCompare(overlayCloseButton, "visible", true);
84− mouseClick(overlay, overlay.width / 2, overlay.height / 2);
84+ mouseClick(overlay);
8585 tryCompare(overlayCloseButton, "visible", false);
86− mouseClick(overlay, overlay.width / 2, overlay.height / 2);
86+ mouseClick(overlay);
8787 tryCompare(overlayCloseButton, "visible", true);
8888 }
8989
@@ -97,7 +97,7 @@ Rectangle {
9797
9898 function test_overlayOpenCorrectImage(data) {
9999 var image = findChild(imageGallery, "previewImage" + data.index);
100− mouseClick(image, image.width / 2, image.height / 2);
100+ mouseClick(image);
101101 tryCompare(overlay, "visible", true);
102102 tryCompare(overlay, "scale", 1.0);
103103 tryCompare(overlayListView, "currentIndex", data.index);
tests/qmltests/Dash/Previews/tst_PreviewPayments.qml+5−5
@@ -84,7 +84,7 @@ Rectangle {
8484 var button = findChild(previewPayments, "paymentButton");
8585 verify(button, "Button not found.");
8686
87− mouseClick(button, button.width / 2, button.height / 2);
87+ mouseClick(button);
8888
8989 paymentClient.process();
9090 spy.wait();
@@ -107,7 +107,7 @@ Rectangle {
107107 tryCompare(button, "visible", true);
108108 tryCompare(button, "opacity", 1);
109109
110− mouseClick(button, button.width / 2, button.height / 2);
110+ mouseClick(button);
111111
112112 paymentClient.process();
113113 spy.wait();
@@ -130,7 +130,7 @@ Rectangle {
130130 tryCompare(button, "visible", true);
131131 tryCompare(button, "opacity", 1);
132132
133− mouseClick(button, button.width / 2, button.height / 2);
133+ mouseClick(button);
134134
135135 tryCompare(progress, "visible", true);
136136 tryCompare(progress, "opacity", 1);
@@ -154,7 +154,7 @@ Rectangle {
154154 var button = findChild(previewPayments, "paymentButton");
155155 verify(button, "Button not found.");
156156
157− mouseClick(button, button.width / 2, button.height / 2);
157+ mouseClick(button);
158158
159159 paymentClient.process();
160160 spy.wait();
@@ -175,7 +175,7 @@ Rectangle {
175175 verify(button, "Button not found.");
176176 verify(progress, "Progress not found.");
177177
178− mouseClick(button, button.width / 2, button.height / 2);
178+ mouseClick(button);
179179
180180 tryCompare(progress, "visible", true);
181181 tryCompare(progress, "opacity", 1);
tests/qmltests/Dash/Previews/tst_PreviewRatingDisplay.qml+1−1
@@ -118,7 +118,7 @@ Rectangle {
118118 compare(rating.value, reviewsModel1["reviews"][1]["rating"]);
119119
120120 // Tap on first star
121− mouseClick(rating, 0, 0);
121+ mouseClick(rating);
122122 compare(rating.value, reviewsModel1["reviews"][1]["rating"]);
123123 }
124124 }
tests/qmltests/Dash/Previews/tst_PreviewRatingInput.qml+2−2
@@ -139,7 +139,7 @@ Rectangle {
139139 verify(reviewTextArea.visible === true);
140140
141141 reviewTextArea.text = data.inputText;
142− mouseClick(submitButton, submitButton.width / 2, submitButton.height / 2);
142+ mouseClick(submitButton);
143143 switch (data.widgetData["required"]) {
144144 case "rating": {
145145 if (rating.visible === false || data.inputRating < 0) {
@@ -187,7 +187,7 @@ Rectangle {
187187 if (data.inputRating > 0) rating.value = data.inputRating;
188188 if (data.inputText !== "") {
189189 reviewTextArea.text = data.inputText;
190− mouseClick(submitButton, submitButton.width / 2, submitButton.height / 2);
190+ mouseClick(submitButton);
191191 }
192192
193193 compare(spy.count, 1);
tests/qmltests/Dash/Previews/tst_PreviewZoomableImage.qml+2−2
@@ -72,11 +72,11 @@ Rectangle {
7272
7373 function test_zoomableImageOpenClose() {
7474 var overlayCloseButton = findChild(overlay, "overlayCloseButton");
75− mouseClick(lazyImage, lazyImage.width / 2, lazyImage.height / 2);
75+ mouseClick(lazyImage);
7676 tryCompare(overlay, "visible", true);
7777 tryCompare(overlay, "scale", 1.0);
7878 tryCompare(overlayCloseButton, "visible", true);
79− mouseClick(overlayCloseButton, overlayCloseButton.width / 2, overlayCloseButton.height / 2);
79+ mouseClick(overlayCloseButton);
8080 tryCompare(overlay, "visible", false);
8181 }
8282 }
tests/qmltests/Dash/ScopeSettings/tst_ScopeSettingBoolean.qml+2−2
@@ -49,12 +49,12 @@ Rectangle {
4949
5050 function test_updated() {
5151 var control = findChild(scopeSetting, "control");
52− mouseClick(control, control.width / 2, control.height / 2);
52+ mouseClick(control);
5353 spy.wait();
5454 compare(spy.signalArguments[0][0], false);
5555
5656 spy.clear();
57− mouseClick(scopeSetting, scopeSetting.width / 2, scopeSetting.height / 2);
57+ mouseClick(scopeSetting);
5858 spy.wait();
5959 compare(spy.signalArguments[0][0], true);
6060 }
tests/qmltests/Dash/ScopeSettings/tst_ScopeSettingNumber.qml+3−3
@@ -57,7 +57,7 @@ Rectangle {
5757 }
5858
5959 function test_updated_on_unfocus() {
60− mouseClick(control, control.width / 2, control.height / 2);
60+ mouseClick(control);
6161 control.selectAll();
6262 control.cut();
6363 control.insert(0, newNumber);
@@ -67,7 +67,7 @@ Rectangle {
6767 }
6868
6969 function test_updated_on_accepted() {
70− mouseClick(control, control.width / 2, control.height / 2);
70+ mouseClick(control);
7171 control.selectAll();
7272 control.cut();
7373 control.insert(0, newNumber);
@@ -86,7 +86,7 @@ Rectangle {
8686 }
8787
8888 function test_unacceptable_input() {
89− mouseClick(control, control.width / 2, control.height / 2);
89+ mouseClick(control);
9090 control.selectAll();
9191 control.cut();
9292 control.insert(0, "not valid");
tests/qmltests/Dash/ScopeSettings/tst_ScopeSettingString.qml+2−2
@@ -57,7 +57,7 @@ Rectangle {
5757 }
5858
5959 function test_updated_on_unfocus() {
60− mouseClick(control, control.width / 2, control.height / 2);
60+ mouseClick(control);
6161 control.selectAll();
6262 control.cut();
6363 control.insert(0, newText);
@@ -67,7 +67,7 @@ Rectangle {
6767 }
6868
6969 function test_updated_on_accepted() {
70− mouseClick(control, control.width / 2, control.height / 2);
70+ mouseClick(control);
7171 control.selectAll();
7272 control.cut();
7373 control.insert(0, newText);
tests/qmltests/Dash/tst_Card.qml+4−4
@@ -61,7 +61,7 @@ Rectangle {
6161 },
6262 {
6363 "name": "Art, header, summary - horizontal",
64− "layout": { "template": { "card-layout": "horizontal" },
64+ "layout": { "template": { "card-layout": "horizontal", "card-background": { "type": "gradient", "elements": ["grey", "white"] } },
6565 "components": JSON.parse(Helpers.fullMapping) }
6666 },
6767 {
@@ -407,7 +407,7 @@ Rectangle {
407407 return [
408408 { tag: "Art and summary", visible: true, color: "#ffffff", index: 0 },
409409 { tag: "No Summary", visible: false, index: 6 },
410− { tag: "Horizontal", visible: false, index: 5 },
410+ { tag: "Horizontal", visible: true, color: "#808080", index: 5 },
411411 { tag: "Grey background", visible: true, color: "#808080", index: 10 },
412412 { tag: "Overriden Gradient background", visible: true, color: "#808080", gradientColor: "#ffffff",
413413 background: {type: "color", elements: ["grey", "white"]}, index: 10 },
@@ -539,9 +539,9 @@ Rectangle {
539539 var touchdown = findChild(card, "touchdown");
540540
541541 compare(touchdown.visible, false);
542− mousePress(card, card.width/2, card.height/2);
542+ mousePress(card);
543543 compare(touchdown.visible, true);
544− mouseRelease(card, card.width/2, card.height/2);
544+ mouseRelease(card);
545545 compare(touchdown.visible, false);
546546 }
547547
tests/qmltests/Dash/tst_Dash.qml+42−25
@@ -89,8 +89,8 @@ Item {
8989 // Go back
9090 var scopesList = findChild(dash, "scopesList");
9191 var scopesListPageHeader = findChild(scopesList, "pageHeader");
92− var backButton = findChild(findChild(scopesListPageHeader, "innerPageHeader"), "backButton");
93− mouseClick(backButton, 0, 0);
92+ var backButton = findChild(findChild(scopesListPageHeader, "innerPageHeader"), "customBackButton");
93+ mouseClick(backButton);
9494 tryCompare(bottomEdgeController, "progress", 0);
9595 }
9696
@@ -106,7 +106,7 @@ Item {
106106 tryCompare(favScopesListCategoryList, "currentIndex", 0);
107107
108108 // Click in first item
109− mouseClick(favScopesListCategoryList.currentItem, 0, 0);
109+ mouseClick(favScopesListCategoryList.currentItem);
110110
111111 // Make sure animation went back
112112 tryCompare(bottomEdgeController, "progress", 0);
@@ -128,7 +128,7 @@ Item {
128128
129129 // Click in second item
130130 favScopesListCategoryList.currentIndex = 1;
131− mouseClick(favScopesListCategoryList.currentItem, 0, 0);
131+ mouseClick(favScopesListCategoryList.currentItem);
132132
133133 // Make sure animation went back
134134 tryCompare(bottomEdgeController, "progress", 0);
@@ -148,7 +148,7 @@ Item {
148148 tryCompare(nonfavScopesListCategoryList, "currentIndex", 0);
149149
150150 // Click on a non favorite scope
151− mouseClick(nonfavScopesListCategoryList.currentItem, 0, 0);
151+ mouseClick(nonfavScopesListCategoryList.currentItem);
152152
153153 // Check the bottom edge (manage dash) is disabled from temp scope
154154 var overviewDragHandle = findChild(dash, "overviewDragHandle");
@@ -164,8 +164,8 @@ Item {
164164
165165 // Go back
166166 var dashTempScopeItemHeader = findChild(dashTempScopeItem, "scopePageHeader");
167− var backButton = findChild(findChild(dashTempScopeItemHeader, "innerPageHeader"), "backButton");
168− mouseClick(backButton, 0, 0);
167+ var backButton = findChild(findChild(dashTempScopeItemHeader, "innerPageHeader"), "customBackButton");
168+ mouseClick(backButton);
169169
170170 // Check temp scope is gone
171171 tryCompare(dashTempScopeItem, "x", dash.width);
@@ -189,7 +189,7 @@ Item {
189189 var scopesList = findChild(dash, "scopesList");
190190 var scopesListPageHeader = findChild(scopesList, "pageHeader");
191191 var searchButton = findChild(scopesListPageHeader, "search_header_button");
192− mouseClick(searchButton, 0, 0);
192+ mouseClick(searchButton);
193193
194194 // Type something
195195 keyClick(Qt.Key_H);
@@ -201,7 +201,7 @@ Item {
201201 var cardTempScope = findChild(dashCategorysearchA, "delegate2");
202202
203203 waitForRendering(cardTempScope);
204− mouseClick(cardTempScope, cardTempScope.width / 2, cardTempScope.height / 2);
204+ mouseClick(cardTempScope);
205205
206206 // Check the bottom edge (overview) is disabled from temp scope
207207 var overviewDragHandle = findChild(dash, "overviewDragHandle");
@@ -217,8 +217,8 @@ Item {
217217
218218 // Go back
219219 var dashTempScopeItemHeader = findChild(dashTempScopeItem, "scopePageHeader");
220− var backButton = findChild(findChild(dashTempScopeItemHeader, "innerPageHeader"), "backButton");
221− mouseClick(backButton, 0, 0);
220+ var backButton = findChild(findChild(dashTempScopeItemHeader, "innerPageHeader"), "customBackButton");
221+ mouseClick(backButton);
222222
223223 // Check temp scope is gone
224224 tryCompare(dashTempScopeItem, "x", dash.width);
@@ -243,8 +243,8 @@ Item {
243243 // Go back
244244 var scopesList = findChild(dash, "scopesList");
245245 var scopesListPageHeader = findChild(scopesList, "pageHeader");
246− var backButton = findChild(findChild(scopesListPageHeader, "innerPageHeader"), "backButton");
247− mouseClick(backButton, 0, 0);
246+ var backButton = findChild(findChild(scopesListPageHeader, "innerPageHeader"), "customBackButton");
247+ mouseClick(backButton);
248248 tryCompare(bottomEdgeController, "progress", 0);
249249 }
250250
@@ -272,7 +272,7 @@ Item {
272272 var scopeLoader0 = findChild(dashContent, "scopeLoader0");
273273 var dashCategory0 = findChild(scopeLoader0, "dashCategory0");
274274 var delegate0 = findChild(dashCategory0, "delegate0");
275− mouseClick(delegate0, delegate0.width / 2, delegate0.height / 2);
275+ mouseClick(delegate0);
276276
277277 tryCompare(dashContent, "subPageShown", true)
278278 waitForRendering(dash);
@@ -320,7 +320,7 @@ Item {
320320 // Click on the store
321321 var scopesListPageHeader = findChild(scopesList, "pageHeader");
322322 var searchButton = findChild(scopesListPageHeader, "store_header_button");
323− mouseClick(searchButton, 0, 0);
323+ mouseClick(searchButton);
324324
325325 spy.wait();
326326 compare(spy.signalArguments[0][0], "scope://com.canonical.scopes.clickstore");
@@ -345,9 +345,9 @@ Item {
345345 // Enter edit mode
346346 var scopesList = findChild(dash, "scopesList");
347347 var clickScope = findChild(favScopesListCategoryList, "delegateclickscope");
348− mousePress(clickScope, 0, 0);
348+ mousePress(clickScope);
349349 tryCompare(scopesList, "state", "edit");
350− mouseRelease(clickScope, 0, 0);
350+ mouseRelease(clickScope);
351351
352352 var starArea = findChild(clickScope, "starArea");
353353 touchFlick(starArea, 0, 0, 0, -units.gu(10));
@@ -355,9 +355,9 @@ Item {
355355 // Exit edit mode and go back
356356 var scopesList = findChild(dash, "scopesList");
357357 var scopesListPageHeader = findChild(scopesList, "pageHeader");
358− var backButton = findChild(findChild(scopesListPageHeader, "innerPageHeader"), "backButton");
359− mouseClick(backButton, 0, 0);
360− mouseClick(backButton, 0, 0);
358+ var backButton = findChild(findChild(scopesListPageHeader, "innerPageHeader"), "customBackButton");
359+ mouseClick(backButton);
360+ mouseClick(backButton);
361361 tryCompare(bottomEdgeController, "progress", 0);
362362
363363 tryCompare(dashContentList, "currentIndex", 0);
@@ -387,9 +387,9 @@ Item {
387387 // Enter edit mode
388388 var scopesList = findChild(dash, "scopesList");
389389 var clickScope = findChild(favScopesListCategoryList, "delegateclickscope");
390− mousePress(clickScope, 0, 0);
390+ mousePress(clickScope);
391391 tryCompare(scopesList, "state", "edit");
392− mouseRelease(clickScope, 0, 0);
392+ mouseRelease(clickScope);
393393
394394 var starArea = findChild(clickScope, "starArea");
395395 touchFlick(starArea, 0, 0, 0, -units.gu(10));
@@ -400,16 +400,33 @@ Item {
400400 // Exit edit mode
401401 var scopesList = findChild(dash, "scopesList");
402402 var scopesListPageHeader = findChild(scopesList, "pageHeader");
403− var backButton = findChild(findChild(scopesListPageHeader, "innerPageHeader"), "backButton");
404− mouseClick(backButton, 0, 0);
403+ var backButton = findChild(findChild(scopesListPageHeader, "innerPageHeader"), "customBackButton");
404+ mouseClick(backButton);
405405
406406 // Click on third scope
407407 var mockScope5 = findChild(favScopesListCategoryList, "delegateMockScope5");
408408 waitForRendering(mockScope5)
409− mouseClick(mockScope5, 0, 0);
409+ mouseClick(mockScope5);
410410 tryCompare(bottomEdgeController, "progress", 0);
411411 tryCompare(dashContentList, "currentIndex", 2);
412412 compare(dashContentList.currentItem.scopeId, "MockScope5");
413413 }
414+
415+ function test_manage_dash_close_dashCommunicator() {
416+ var dashContentList = findChild(dash, "dashContentList");
417+ compare(dashContentList.currentIndex, 0);
418+ compare(dashContentList.currentItem.scopeId, "MockScope1");
419+
420+ // Show the manage dash
421+ touchFlick(dash, dash.width / 2, dash.height - 1, dash.width / 2, units.gu(2));
422+ var bottomEdgeController = findInvisibleChild(dash, "bottomEdgeController");
423+ tryCompare(bottomEdgeController, "progress", 1);
424+
425+ var dashCommunicatorService = findInvisibleChild(dash, "dashCommunicatorService");
426+ dashCommunicatorService.mockSetCurrentScope(1, true, false);
427+
428+ tryCompare(bottomEdgeController, "progress", 0);
429+ tryCompare(dashContentList, "currentIndex", 1)
430+ }
414431 }
415432}
tests/qmltests/Dash/tst_DashContent.qml+105−27
@@ -288,7 +288,7 @@ Item {
288288 var dashNavigationButton = findChild(dashContentList.currentItem, "navigationButton");
289289 compare(dashNavigationButton.showList, false);
290290 waitForRendering(dashNavigationButton);
291− mouseClick(dashNavigationButton, dashNavigationButton.width / 2, dashNavigationButton.height / 2);
291+ mouseClick(dashNavigationButton);
292292 compare(dashNavigationButton.showList, true);
293293
294294 var navigationListView = findChild(dashNavigationButton, "navigationListView");
@@ -304,30 +304,30 @@ Item {
304304 compare(allButton.visible, false);
305305
306306 var navigation = findChild(dashNavigationButton, "navigation0child3");
307− mouseClick(navigation, 0, 0);
307+ mouseClick(navigation);
308308 compare(dashNavigationButton.showList, false);
309309 tryCompare(dashNavigationButton.currentNavigation, "navigationId", "middle3");
310310 tryCompare(navigationListView.currentItem.navigation, "navigationId", "root");
311311
312− mouseClick(dashNavigationButton, 0, 0);
312+ mouseClick(dashNavigationButton);
313313 compare(dashNavigationButton.showList, true);
314314 waitForRendering(navigationListView);
315315 waitForRendering(navigationListView.currentItem);
316316 compare(allButton.visible, true);
317317
318− mouseClick(allButton, 0, 0);
318+ mouseClick(allButton);
319319 compare(dashNavigationButton.showList, false);
320320 tryCompare(dashNavigationButton.currentNavigation, "navigationId", "root");
321321 tryCompare(navigationListView.currentItem.navigation, "navigationId", "root");
322322
323− mouseClick(dashNavigationButton, 0, 0);
323+ mouseClick(dashNavigationButton);
324324 compare(dashNavigationButton.showList, true);
325325 waitForRendering(navigationListView);
326326 waitForRendering(navigationListView.currentItem);
327327 compare(allButton.visible, false);
328328
329329 navigation = findChild(dashNavigationButton, "navigation0child2");
330− mouseClick(navigation, 0, 0);
330+ mouseClick(navigation);
331331 compare(dashNavigationButton.showList, true);
332332 tryCompare(dashNavigationButton.currentNavigation, "navigationId", "middle2");
333333 tryCompare(navigationListView.currentItem.navigation, "navigationId", "middle2");
@@ -340,12 +340,12 @@ Item {
340340
341341 tryCompare(navigationListView, "contentX", navigationList1.x);
342342 waitForRendering(navigationListView);
343− mouseClick(allButton, 0, 0);
343+ mouseClick(allButton);
344344 compare(dashNavigationButton.showList, false);
345345 tryCompare(dashNavigationButton.currentNavigation, "navigationId", "middle2");
346346 tryCompare(navigationListView.currentItem.navigation, "navigationId", "middle2");
347347
348− mouseClick(dashNavigationButton, 0, 0);
348+ mouseClick(dashNavigationButton);
349349 compare(dashNavigationButton.showList, true);
350350 waitForRendering(navigationListView);
351351 waitForRendering(navigationListView.currentItem);
@@ -354,47 +354,47 @@ Item {
354354
355355 tryCompare(navigationList1.navigation, "loaded", true);
356356 navigation = findChild(dashNavigationButton, "navigation1child2");
357− mouseClick(navigation, 0, 0);
357+ mouseClick(navigation);
358358 compare(dashNavigationButton.showList, false);
359359 tryCompare(dashNavigationButton.currentNavigation, "navigationId", "childmiddle22");
360360 tryCompare(navigationListView.currentItem.navigation, "navigationId", "middle2");
361361
362− mouseClick(dashNavigationButton, 0, 0);
362+ mouseClick(dashNavigationButton);
363363 compare(dashNavigationButton.showList, true);
364364 waitForRendering(navigationListView);
365365 waitForRendering(navigationListView.currentItem);
366366
367367 tryCompare(navigationList1.navigation, "loaded", true);
368368 navigation = findChild(dashNavigationButton, "navigation1child3");
369− mouseClick(navigation, 0, 0);
369+ mouseClick(navigation);
370370 compare(dashNavigationButton.showList, false);
371371 tryCompare(dashNavigationButton.currentNavigation, "navigationId", "childmiddle23");
372372 tryCompare(navigationListView.currentItem.navigation, "navigationId", "middle2");
373373
374− mouseClick(dashNavigationButton, 0, 0);
374+ mouseClick(dashNavigationButton);
375375 compare(dashNavigationButton.showList, true);
376376 waitForRendering(navigationListView);
377377 waitForRendering(navigationListView.currentItem);
378− mouseClick(backButton, 0, 0);
378+ mouseClick(backButton);
379379
380380 tryCompare(dashNavigationButton.currentNavigation, "navigationId", "root");
381381 tryCompare(navigationListView.currentItem.navigation, "navigationId", "root");
382382 compare(dashNavigationButton.showList, true);
383− mouseClick(dashNavigationButton, 0, 0);
383+ mouseClick(dashNavigationButton);
384384 compare(dashNavigationButton.showList, false);
385385
386− mouseClick(dashNavigationButton, 0, 0);
386+ mouseClick(dashNavigationButton);
387387 compare(dashNavigationButton.showList, true);
388388 tryCompare(navigationListView.currentItem.navigation, "loaded", true);
389389 navigation = findChild(dashNavigationButton, "navigation0child2");
390− mouseClick(navigation, 0, 0);
390+ mouseClick(navigation);
391391 compare(dashNavigationButton.showList, true);
392392 navigationList1 = findChild(dashNavigationButton, "navigation1");
393393 compare(navigationList1.navigation.loaded, false);
394394 tryCompare(dashNavigationButton.currentNavigation, "navigationId", "middle2");
395395 allButton = findChild(navigationList1, "allButton");
396396 tryCompare(dashNavigationButton.currentNavigation, "navigationId", "middle2");
397− mouseClick(allButton, 0, 0);
397+ mouseClick(allButton);
398398 tryCompare(dashNavigationButton.currentNavigation, "navigationId", "middle2");
399399 }
400400
@@ -408,7 +408,7 @@ Item {
408408
409409 compare(dashNavigationButton.showList, false);
410410 waitForRendering(dashNavigationButton);
411− mouseClick(dashNavigationButton, 0, 0);
411+ mouseClick(dashNavigationButton);
412412 compare(dashNavigationButton.showList, true);
413413
414414 var navigationListView = findChild(dashNavigationButton, "navigationListView");
@@ -429,24 +429,24 @@ Item {
429429 compare(backButton.visible, false);
430430
431431 var navigation = findChild(dashNavigationButton, "navigation0child3");
432− mouseClick(navigation, 0, 0);
432+ mouseClick(navigation);
433433 compare(dashNavigationButton.showList, false);
434434 tryCompare(dashNavigationButton.currentNavigation, "navigationId", "altrootChild3");
435435 tryCompare(navigationListView.currentItem.navigation, "navigationId", "altroot");
436436
437− mouseClick(dashNavigationButton, 0, 0);
437+ mouseClick(dashNavigationButton);
438438 compare(dashNavigationButton.showList, true);
439439 waitForRendering(navigationListView);
440440 waitForRendering(navigationListView.currentItem);
441441 compare(allButton.visible, false);
442442
443443 navigation = findChild(dashNavigationButton, "navigation0child2");
444− mouseClick(navigation, 0, 0);
444+ mouseClick(navigation);
445445 compare(dashNavigationButton.showList, false);
446446 tryCompare(dashNavigationButton.currentNavigation, "navigationId", "altrootChild2");
447447 tryCompare(navigationListView.currentItem.navigation, "navigationId", "altroot");
448448
449− mouseClick(dashNavigationButton, 0, 0);
449+ mouseClick(dashNavigationButton);
450450 compare(dashNavigationButton.showList, true);
451451 waitForRendering(navigationListView);
452452 waitForRendering(navigationListView.currentItem);
@@ -454,7 +454,7 @@ Item {
454454
455455 compare(navigationListView.count, 1, "There should be no second-level navigation");
456456
457− mouseClick(dashNavigationButton, 0, 0);
457+ mouseClick(dashNavigationButton);
458458 compare(dashNavigationButton.showList, false);
459459 }
460460
@@ -474,7 +474,7 @@ Item {
474474 compare(dashNavigationButton.showList, false);
475475 compare(dashAltNavigationButton.showList, false);
476476
477− mouseClick(dashNavigation, 0, 0);
477+ mouseClick(dashAltNavigationButton);
478478 compare(dashNavigationButton.showList, false);
479479 compare(dashAltNavigationButton.showList, true);
480480
@@ -487,24 +487,45 @@ Item {
487487 var blackRect = findChild(dashNavigation, "blackRect");
488488 tryCompare(blackRect, "opacity", 0.5);
489489
490− mouseClick(dashNavigation, dashNavigationButton.x, 0);
490+ mouseClick(dashNavigationButton);
491491 compare(dashNavigationButton.showList, false);
492492 compare(dashAltNavigationButton.showList, false);
493493
494494 tryCompare(navigationListView, "visible", false);
495495
496− mouseClick(dashNavigation, dashNavigationButton.x, 0);
496+ mouseClick(dashNavigationButton);
497497 compare(dashNavigationButton.showList, true);
498498 compare(dashAltNavigationButton.showList, false);
499499
500500 navigationListView = findChild(dashNavigationButton, "navigationListView");
501501 tryCompare(navigationListView.currentItem.navigation, "loaded", true);
502502
503− mouseClick(dashNavigation, 0, 0);
503+ mouseClick(dashAltNavigationButton);
504504 compare(dashNavigationButton.showList, false);
505505 compare(dashAltNavigationButton.showList, false);
506506 }
507507
508+ function test_navigationsSwipeToNextScope() {
509+ var dashContentList = findChild(dashContent, "dashContentList");
510+ tryCompareFunction(function() { return findChild(dashContentList.currentItem, "dashNavigation") != null; }, true);
511+ var dashNavigation = findChild(dashContentList.currentItem, "dashNavigation");
512+ tryCompare(dashNavigation, "visible", true);
513+ var dashNavigationButton = findChild(dashContentList.currentItem, "altNavigationButton");
514+ verify(dashNavigationButton, "Can't find navigation button");
515+
516+ compare(dashNavigationButton.showList, false);
517+ waitForRendering(dashNavigationButton);
518+ mouseClick(dashNavigationButton, 0, 0);
519+ compare(dashNavigationButton.showList, true);
520+
521+ mouseFlick(dashNavigationButton, dashNavigationButton.width - units.gu(1), units.gu(1), units.gu(1), units.gu(1));
522+ compare(dashNavigationButton.showList, false);
523+
524+ var dashContentList = findChild(dashContent, "dashContentList");
525+ expectFail("", "should not change the parent list.");
526+ tryCompare(dashContentList, "currentIndex", 1);
527+ }
528+
508529 function test_searchHint() {
509530 var dashContentList = findChild(dashContent, "dashContentList");
510531 verify(dashContentList !== null);
@@ -516,5 +537,62 @@ Item {
516537
517538 compare(categoryListView.pageHeader.item.searchHint, "Search People");
518539 }
540+
541+ function compareArrays(a, b) {
542+ if (a.length != b.length) return false;
543+ for (var i in a) {
544+ if (a[i] != b[i]) return false;
545+ }
546+ return true;
547+ }
548+
549+ function getSettledButtons() {
550+ var buttons = findChildsByType(dashContent, "AbstractButton");
551+ wait(2500);
552+ var aux = findChildsByType(dashContent, "AbstractButton");
553+ while (!compareArrays(aux, buttons)) {
554+ buttons = aux;
555+ wait(2500);
556+ aux = findChildsByType(dashContent, "AbstractButton");
557+ }
558+ return buttons;
559+ }
560+
561+ function test_noDelegateCreationDestructionOnMove() {
562+ // Our cards are of type AbstractButton as defined in CardCreator.js
563+ // This gives also other things that are not cards but for our purpose it
564+ // does not matter
565+
566+ // Wait for the buttons to settle
567+ var buttons = getSettledButtons();
568+
569+ // Move the scopes so that the item on the right is the current one
570+ // without releasing the button
571+ mouseFlick(dashContent, dashContent.width - units.gu(1), units.gu(1), units.gu(1), units.gu(1), true, false);
572+
573+ // Make sure we have changed to a new scope
574+ compare(dashContent.currentIndex, 1);
575+
576+ // Wait for the buttons to settle
577+ var buttons2 = getSettledButtons();
578+
579+ // Verify we have exactly the same buttons as before starting to move
580+ verify(compareArrays(buttons2, buttons));
581+
582+ // Release the mouse
583+ mouseRelease(dashContent, units.gu(1), units.gu(1));
584+
585+ // Wait for the scopes list to stop moving
586+ var dashContentList = findChild(dashContent, "dashContentList");
587+ tryCompare(dashContentList, "moving", false);
588+ compare(dashContent.currentIndex, 1);
589+
590+ // Wait for the buttons to settle
591+ var buttons3 = getSettledButtons();
592+
593+ // Verify we have a different set of buttons now
594+ expectFail("", "There has to be new cards after releasing the list is not moving anymore");
595+ verify(compareArrays(buttons3, buttons));
596+ }
519597 }
520598}
tests/qmltests/Dash/tst_GenericScopeView.qml+26−26
@@ -163,12 +163,12 @@ Item {
163163 verify(!category.expanded);
164164
165165 var initialHeight = category.height;
166− mouseClick(seeAll, seeAll.width / 2, seeAll.height / 2);
166+ mouseClick(seeAll);
167167 verify(category.expanded);
168168 tryCompare(category, "height", category.item.expandedHeight + seeAll.height);
169169
170170 waitForRendering(seeAll);
171− mouseClick(seeAll, seeAll.width / 2, seeAll.height / 2);
171+ mouseClick(seeAll);
172172 verify(!category.expanded);
173173 }
174174
@@ -186,17 +186,17 @@ Item {
186186 verify(category2.expandable);
187187 verify(!category2.expanded);
188188
189− mouseClick(seeAll2, seeAll2.width / 2, seeAll2.height / 2);
189+ mouseClick(seeAll2);
190190 tryCompare(category2, "expanded", true);
191191
192192 categoryListView.positionAtBeginning();
193193
194194 var category0 = findChild(genericScopeView, "dashCategory0")
195195 var seeAll0 = findChild(category0, "seeAll")
196− mouseClick(seeAll0, seeAll0.width / 2, seeAll0.height / 2);
196+ mouseClick(seeAll0);
197197 tryCompare(category0, "expanded", true);
198198 tryCompare(category2, "expanded", false);
199− mouseClick(seeAll0, seeAll0.width / 2, seeAll0.height / 2);
199+ mouseClick(seeAll0);
200200 tryCompare(category0, "expanded", false);
201201 tryCompare(category2, "expanded", false);
202202 }
@@ -208,7 +208,7 @@ Item {
208208 spy.target = genericScopeView.scope;
209209 spy.signalName = "performQuery";
210210
211− mouseClick(header, header.width / 2, header.height / 2);
211+ mouseClick(header);
212212
213213 spy.wait();
214214 compare(spy.signalArguments[0][0], genericScopeView.scope.categories.data(1, Categories.RoleHeaderLink));
@@ -248,13 +248,13 @@ Item {
248248 categoryListView.contentY = units.gu(20);
249249 var seeAll = findChild(category, "seeAll");
250250 var floatingSeeLess = findChild(genericScopeView, "floatingSeeLess");
251− mouseClick(seeAll, seeAll.width / 2, seeAll.height / 2);
251+ mouseClick(seeAll);
252252 tryCompare(category, "expanded", true);
253253 tryCompareFunction(function() {
254254 return category.item.height + floatingSeeLess.height ==
255255 genericScopeView.height - category.item.displayMarginBeginning - category.item.displayMarginEnd;
256256 }, true);
257− mouseClick(floatingSeeLess, floatingSeeLess.width / 2, floatingSeeLess.height / 2);
257+ mouseClick(floatingSeeLess);
258258 tryCompare(category, "expanded", false);
259259 }
260260
@@ -295,7 +295,7 @@ Item {
295295 true);
296296 var tile = findChild(findChild(genericScopeView, "dashCategory"+category), "delegate"+delegate);
297297 waitForRendering(tile);
298− mouseClick(tile, tile.width / 2, tile.height / 2);
298+ mouseClick(tile);
299299 tryCompare(testCase.subPageLoader, "open", true);
300300 tryCompare(testCase.subPageLoader, "x", 0);
301301 tryCompare(findChild(genericScopeView, "categoryListView"), "visible", false);
@@ -340,15 +340,15 @@ Item {
340340 tryCompare(testCase.subPageLoader, "open", false);
341341 tryCompare(testCase.subPageLoader, "visible", false);
342342
343− mouseClick(tile, tile.width / 2, tile.height / 2);
343+ mouseClick(tile);
344344
345345 tryCompare(testCase.subPageLoader, "open", false);
346346 tryCompare(testCase.subPageLoader, "visible", false);
347347
348− mousePress(tile, tile.width / 2, tile.height / 2);
348+ mousePress(tile);
349349 tryCompare(testCase.subPageLoader, "open", false);
350350 tryCompare(testCase.subPageLoader, "visible", false);
351− mouseRelease(tile, tile.width / 2, tile.height / 2);
351+ mouseRelease(tile);
352352 }
353353
354354 function test_showPreviewCarousel() {
@@ -359,18 +359,18 @@ Item {
359359 var tile = findChild(category, "carouselDelegate1");
360360 verify(tile, "Could not find delegate");
361361
362− mouseClick(tile, tile.width / 2, tile.height / 2);
362+ mouseClick(tile);
363363 tryCompare(tile, "explicitlyScaled", true);
364− mouseClick(tile, tile.width / 2, tile.height / 2);
364+ mouseClick(tile);
365365 tryCompare(testCase.subPageLoader, "open", true);
366366 tryCompare(testCase.subPageLoader, "x", 0);
367367
368368 closePreview();
369369
370− mousePress(tile, tile.width / 2, tile.height / 2);
370+ mousePress(tile);
371371 tryCompare(testCase.subPageLoader, "open", true);
372372 tryCompare(testCase.subPageLoader, "x", 0);
373− mouseRelease(tile, tile.width / 2, tile.height / 2);
373+ mouseRelease(tile);
374374
375375 closePreview();
376376 }
@@ -383,16 +383,16 @@ Item {
383383 var tile = findChild(category, "delegate1");
384384 verify(tile, "Could not find delegate");
385385
386− mouseClick(tile, tile.width / 2, tile.height / 2);
386+ mouseClick(tile);
387387 tryCompare(testCase.subPageLoader, "open", true);
388388 tryCompare(testCase.subPageLoader, "x", 0);
389389
390390 closePreview();
391391
392− mousePress(tile, tile.width / 2, tile.height / 2);
392+ mousePress(tile);
393393 tryCompare(testCase.subPageLoader, "open", true);
394394 tryCompare(testCase.subPageLoader, "x", 0);
395− mouseRelease(tile, tile.width / 2, tile.height / 2);
395+ mouseRelease(tile);
396396
397397 closePreview();
398398 }
@@ -429,7 +429,7 @@ Item {
429429 tryCompare(testCase.subPageLoader, "open", false);
430430 tryCompare(testCase.subPageLoader, "visible", false);
431431 var settings = findChild(innerHeader, "settings_header_button");
432− mouseClick(settings, settings.width / 2, settings.height / 2);
432+ mouseClick(settings);
433433 tryCompare(testCase.subPageLoader, "open", true);
434434 tryCompareFunction(function() { return (String(subPageLoader.source)).indexOf("ScopeSettingsPage.qml") != -1; }, true);
435435 tryCompare(genericScopeView, "subPageShown", true);
@@ -496,7 +496,7 @@ Item {
496496 verify(category0.expandable);
497497 verify(!category0.expanded);
498498
499− mouseClick(seeAll0, seeAll0.width / 2, seeAll0.height / 2);
499+ mouseClick(seeAll0);
500500 verify(category0.expanded);
501501 tryCompare(category0, "height", category0.item.expandedHeight + seeAll0.height);
502502 tryCompare(genericScopeView.categoryView, "contentY", units.gu(14));
@@ -509,7 +509,7 @@ Item {
509509 verify(category1.expandable);
510510 verify(!category1.expanded);
511511
512− mouseClick(seeAll1, seeAll1.width / 2, seeAll1.height / 2);
512+ mouseClick(seeAll1);
513513 verify(!category0.expanded);
514514 verify(category1.expanded);
515515 tryCompare(category1, "height", category1.item.expandedHeight + seeAll1.height);
@@ -539,7 +539,7 @@ Item {
539539 verify(category0.expandable);
540540 verify(!category0.expanded);
541541
542− mouseClick(seeAll0, seeAll0.width / 2, seeAll0.height / 2);
542+ mouseClick(seeAll0);
543543 verify(category0.expanded);
544544 tryCompare(category0, "height", category0.item.expandedHeight + seeAll0.height);
545545
@@ -550,7 +550,7 @@ Item {
550550 verify(category1.expandable);
551551 verify(!category1.expanded);
552552
553− mouseClick(seeAll1, seeAll1.width / 2, seeAll1.height / 2);
553+ mouseClick(seeAll1);
554554 verify(!category0.expanded);
555555 verify(category1.expanded);
556556 tryCompare(category1, "height", category1.item.expandedHeight + seeAll1.height);
@@ -578,7 +578,7 @@ Item {
578578 expectFail("Apps", "Click scope should not have a favorite button");
579579 var favoriteAction = findChild(innerHeader, "favorite_header_button");
580580 verify(favoriteAction, "Could not find the favorite action.");
581− mouseClick(favoriteAction, favoriteAction.width / 2, favoriteAction.height / 2);
581+ mouseClick(favoriteAction);
582582
583583 tryCompare(genericScopeView.scope, "favorite", !data.favorite);
584584
@@ -629,7 +629,7 @@ Item {
629629 var touchdown = findChild(item0, "touchdown");
630630
631631 compare(touchdown.visible, false);
632− mouseClick(item0, item0.width / 2, item0.height / 2);
632+ mouseClick(item0);
633633 compare(touchdown.visible, false);
634634
635635 cardTool.template["non-interactive"] = false;
tests/qmltests/Dash/tst_PageHeader.qml+1−1
@@ -157,7 +157,7 @@ Item {
157157 var recentSearches = findChild(headerContainer.popover, "recentSearches");
158158 verify(recentSearches, "Could not find recent searches in the popover");
159159 waitForRendering(recentSearches);
160− mouseClick(recentSearches.itemAt(0), 0, 0);
160+ mouseClick(recentSearches.itemAt(0));
161161
162162 compare(pageHeader.searchQuery, "Search2");
163163 tryCompareFunction(function() { return headerContainer.popover === null; }, true);
tests/qmltests/Dash/tst_PreviewListView.qml+2−2
@@ -73,7 +73,7 @@ Rectangle {
7373
7474 function test_notProcessing() {
7575 expectFail("", "processingMouseArea should not receive the click.");
76− mouseClick(listView, listView.width / 2, listView.height / 2);
76+ mouseClick(listView);
7777 clickedSpy.wait();
7878 }
7979
@@ -83,7 +83,7 @@ Rectangle {
8383
8484 tryCompare(listView, "processing", true);
8585
86− mouseClick(listView, listView.width / 2, listView.height / 2);
86+ mouseClick(listView);
8787 clickedSpy.wait();
8888 }
8989
tests/qmltests/Launcher/tst_Launcher.qml+8−8
@@ -154,7 +154,7 @@ Item {
154154 dragLauncherIntoView()
155155
156156 // tapping on the center of the screen should dismiss the launcher
157− mouseClick(launcher, launcher.width/2, launcher.height/2)
157+ mouseClick(launcher)
158158
159159 // should eventually get fully retracted (hidden)
160160 tryCompare(panel, "x", -launcher.panelWidth, 1000)
@@ -175,7 +175,7 @@ Item {
175175
176176 verify(appIcon != undefined)
177177
178− mouseClick(appIcon, appIcon.width/2, appIcon.height/2)
178+ mouseClick(appIcon)
179179
180180 tryCompare(launcher, "lastSelectedApplication",
181181 "dialer-app")
@@ -194,7 +194,7 @@ Item {
194194 var dashIcon = findChild(launcher, "dashItem")
195195 verify(dashIcon != undefined)
196196
197− mouseClick(dashIcon, dashIcon.width/2, dashIcon.height/2)
197+ mouseClick(dashIcon)
198198
199199 tryCompare(launcher, "showDashHome_count", 1)
200200
@@ -413,7 +413,7 @@ Item {
413413 compare(quickListShape.visible, false)
414414
415415 // Doing longpress
416− mousePress(draggedItem, draggedItem.width / 2, draggedItem.height / 2)
416+ mousePress(draggedItem)
417417 tryCompare(fakeDragItem, "visible", true) // Wait longpress happening
418418 tryCompare(quickListShape, "visible", true)
419419
@@ -448,7 +448,7 @@ Item {
448448 }
449449
450450 // Doing longpress
451− mousePress(draggedItem, draggedItem.width / 2, draggedItem.height / 2);
451+ mousePress(draggedItem);
452452 tryCompare(quickListShape, "opacity", 0.96);
453453 mouseRelease(draggedItem);
454454
@@ -481,7 +481,7 @@ Item {
481481 tryCompare(quickListShape, "visible", false)
482482
483483 // Doing longpress
484− mousePress(clickedItem, clickedItem.width / 2, clickedItem.height / 2)
484+ mousePress(clickedItem)
485485 tryCompare(clickedItem, "itemOpacity", 0) // Wait for longpress to happen
486486 verify(quickListShape.visible, "QuickList must be visible")
487487
@@ -492,7 +492,7 @@ Item {
492492 signalSpy.clear();
493493 signalSpy.signalName = "quickListTriggered"
494494
495− mouseClick(quickListEntry, quickListEntry.width / 2, quickListEntry.height / 2)
495+ mouseClick(quickListEntry)
496496
497497 if (data.clickable) {
498498 // QuickList needs to be closed when some clickable item is clicked
@@ -524,7 +524,7 @@ Item {
524524 tryCompare(quickList, "state", "")
525525
526526 // Doing longpress
527− mousePress(clickedItem, clickedItem.width / 2, clickedItem.height / 2)
527+ mousePress(clickedItem)
528528 tryCompare(clickedItem, "itemOpacity", 0) // Wait for longpress to happen
529529 verify(quickList, "state", "open")
530530
tests/qmltests/Notifications/tst_Notifications.qml+6−6
@@ -547,7 +547,7 @@ Item {
547547 compare(valueLabel.visible, data.valueLabelVisible, "value-label visibility is incorrect")
548548
549549 // test input does not fall through
550− mouseClick(notification, notification.width / 2, notification.height / 2)
550+ mouseClick(notification)
551551 if(data.type == Notification.Interactive) {
552552 actionSpy.wait()
553553 compare(actionSpy.signalArguments[0][0], data.actions[0]["id"], "got wrong id for interactive action")
@@ -568,7 +568,7 @@ Item {
568568
569569 // only test the left/cancel-button if two actions have been passed in
570570 if (data.actions.length == 2) {
571− tryCompareFunction(function() { mouseClick(buttonCancel, buttonCancel.width / 2, buttonCancel.height / 2); return actionSpy.signalArguments.length > 0; }, true);
571+ tryCompareFunction(function() { mouseClick(buttonCancel); return actionSpy.signalArguments.length > 0; }, true);
572572 compare(actionSpy.signalArguments[0][0], data.actions[1]["id"], "got wrong id for negative action")
573573 actionSpy.clear()
574574 }
@@ -577,7 +577,7 @@ Item {
577577 verify(buttonAccept.color === data.buttonTinted ? "#3fb24f" : "#dddddd", "button has the wrong color-tint")
578578
579579 // click the positive/right button
580− tryCompareFunction(function() { mouseClick(buttonAccept, buttonAccept.width / 2, buttonAccept.height / 2); return actionSpy.signalArguments.length > 0; }, true);
580+ tryCompareFunction(function() { mouseClick(buttonAccept); return actionSpy.signalArguments.length > 0; }, true);
581581 compare(actionSpy.signalArguments[0][0], data.actions[0]["id"], "got wrong id positive action")
582582 actionSpy.clear()
583583 waitForRendering (notification)
@@ -592,19 +592,19 @@ Item {
592592
593593 // try clicking on choices in expanded comboList
594594 var choiceButton1 = findChild(notification, "notify_button3")
595− tryCompareFunction(function() { mouseClick(choiceButton1, choiceButton1.width / 2, choiceButton1.height / 2); return actionSpy.signalArguments.length > 0; }, true);
595+ tryCompareFunction(function() { mouseClick(choiceButton1); return actionSpy.signalArguments.length > 0; }, true);
596596 compare(actionSpy.signalArguments[0][0], data.actions[3]["id"], "got wrong id choice action 1")
597597 actionSpy.clear()
598598
599599 var choiceButton2 = findChild(notification, "notify_button4")
600− tryCompareFunction(function() { mouseClick(choiceButton2, choiceButton2.width / 2, choiceButton2.height / 2); return actionSpy.signalArguments.length > 0; }, true);
600+ tryCompareFunction(function() { mouseClick(choiceButton2); return actionSpy.signalArguments.length > 0; }, true);
601601 compare(actionSpy.signalArguments[0][0], data.actions[4]["id"], "got wrong id choice action 2")
602602 actionSpy.clear()
603603
604604 // click to collapse
605605 //tryCompareFunction(function() { mouseClick(comboButton, comboButton.width - comboButton.__styleInstance.dropDownWidth / 2, comboButton.height / 2); return comboButton.expanded == false; }, true);
606606 } else {
607− mouseClick(buttonCancel, buttonCancel.width / 2, buttonCancel.height / 2)
607+ mouseClick(buttonCancel)
608608 compare(actionSpy.signalArguments[0][0], data.actions[1]["id"], "got wrong id for negative action")
609609 }
610610 }
tests/qmltests/Notifications/tst_OptionToggle.qml+7−7
@@ -223,7 +223,7 @@ Row {
223223 }
224224
225225 // test input does not fall through
226− mouseClick(notification, notification.width / 2, notification.height / 2)
226+ mouseClick(notification)
227227 if(data.type == Notification.Interactive) {
228228 actionSpy.wait()
229229 compare(actionSpy.signalArguments[0][0], data.actions[0]["id"], "got wrong id for interactive action")
@@ -244,7 +244,7 @@ Row {
244244
245245 // only test the left/cancel-button if two actions have been passed in
246246 if (data.actions.length == 2) {
247− tryCompareFunction(function() { mouseClick(buttonCancel, buttonCancel.width / 2, buttonCancel.height / 2); return actionSpy.signalArguments.length > 0; }, true);
247+ tryCompareFunction(function() { mouseClick(buttonCancel); return actionSpy.signalArguments.length > 0; }, true);
248248 compare(actionSpy.signalArguments[0][0], data.actions[1]["id"], "got wrong id for negative action")
249249 actionSpy.clear()
250250 }
@@ -253,7 +253,7 @@ Row {
253253 verify(buttonAccept.color === data.buttonTinted ? "#3fb24f" : "#dddddd", "button has the wrong color-tint")
254254
255255 // click the positive/right button
256− tryCompareFunction(function() { mouseClick(buttonAccept, buttonAccept.width / 2, buttonAccept.height / 2); return actionSpy.signalArguments.length > 0; }, true);
256+ tryCompareFunction(function() { mouseClick(buttonAccept); return actionSpy.signalArguments.length > 0; }, true);
257257 compare(actionSpy.signalArguments[0][0], data.actions[0]["id"], "got wrong id positive action")
258258 actionSpy.clear()
259259 waitForRendering(notification)
@@ -264,20 +264,20 @@ Row {
264264 tryCompareFunction(function() { return optionToggle.expanded == false; }, true);
265265
266266 // click to expand
267− tryCompareFunction(function() { mouseClick(optionToggle, optionToggle.width / 2, optionToggle.height / 2); return optionToggle.expanded == true; }, true);
267+ tryCompareFunction(function() { mouseClick(optionToggle); return optionToggle.expanded == true; }, true);
268268
269269 // try clicking on choices in expanded comboList
270270 var choiceButton1 = findChild(notification, "notify_button3")
271− tryCompareFunction(function() { mouseClick(choiceButton1, choiceButton1.width / 2, choiceButton1.height / 2); return actionSpy.signalArguments.length > 0; }, true);
271+ tryCompareFunction(function() { mouseClick(choiceButton1); return actionSpy.signalArguments.length > 0; }, true);
272272 compare(actionSpy.signalArguments[0][0], data.actions[3]["id"], "got wrong id choice action 1")
273273 actionSpy.clear()
274274
275275 var choiceButton2 = findChild(notification, "notify_button4")
276− tryCompareFunction(function() { mouseClick(choiceButton2, choiceButton2.width / 2, choiceButton2.height / 2); return actionSpy.signalArguments.length > 0; }, true);
276+ tryCompareFunction(function() { mouseClick(choiceButton2); return actionSpy.signalArguments.length > 0; }, true);
277277 compare(actionSpy.signalArguments[0][0], data.actions[4]["id"], "got wrong id choice action 2")
278278 actionSpy.clear()
279279 } else {
280− mouseClick(buttonCancel, buttonCancel.width / 2, buttonCancel.height / 2)
280+ mouseClick(buttonCancel)
281281 compare(actionSpy.signalArguments[0][0], data.actions[1]["id"], "got wrong id for negative action")
282282 }
283283 }
tests/qmltests/Notifications/tst_SwipeToAct.qml+1−1
@@ -240,7 +240,7 @@ Item {
240240 }
241241
242242 // test input does not fall through
243− mouseClick(notification, notification.width / 2, notification.height / 2)
243+ mouseClick(notification)
244244 if(data.type == Notification.Interactive) {
245245 actionSpy.wait()
246246 compare(actionSpy.signalArguments[0][0], data.actions[0]["id"], "got wrong id for interactive action")
tests/qmltests/Notifications/tst_VisualSnapDecisionsQueue.qml+2−2
@@ -214,7 +214,7 @@ Row {
214214
215215 // click/tap on each snap-decision and verify only one is in expanded-state at any time
216216 for (var index = 0; index < snap_decision.length; index++) {
217− mouseClick(snap_decision[index], snap_decision[index].width / 2, snap_decision[index].height / 2)
217+ mouseClick(snap_decision[index])
218218 for (var kindex = 0; kindex < snap_decision.length; kindex++) {
219219 if (kindex == index) {
220220 compare(snap_decision[kindex].state, "expanded", "state of "+ kindex + ".snap-decision is not expanded");
@@ -227,7 +227,7 @@ Row {
227227 // remove top-most and verify one of the remaining ones is still getting expanded
228228
229229 // make first snap-decision expand
230− mouseClick(snap_decision[0], snap_decision[0].width / 2, snap_decision[0].height / 2);
230+ mouseClick(snap_decision[0]);
231231
232232 for (var index = 1; index < snap_decision.length; index++) {
233233 removeTopMostNotification();
tests/qmltests/Panel/Indicators/tst_IndicatorsLight.qmlnew file+129
@@ -0,0 +1,129 @@
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 QtQuick.Layouts 1.1
19+import Unity.Test 0.1 as UT
20+import Unity.Indicators 0.1 as Indicators
21+import Ubuntu.Components 1.1
22+import Powerd 0.1
23+import Lights 0.1
24+import QMenuModel 0.1
25+import "../../../../qml/Panel/Indicators"
26+
27+Item {
28+ id: root
29+ width: units.gu(30)
30+ height: units.gu(30)
31+
32+ property var newMessage: {
33+ "messages" : {
34+ 'valid': true,
35+ 'state': {
36+ 'icons': [ 'indicator-messages-new' ]
37+ }
38+ }
39+ };
40+ property var noNewMessage: {
41+ "messages" : {
42+ 'valid': true,
43+ 'state': {
44+ 'icons': [ 'indicator-messages' ]
45+ }
46+ }
47+ };
48+
49+ Component {
50+ id: light
51+ IndicatorsLight {}
52+ }
53+
54+ Loader {
55+ id: loader
56+ sourceComponent: light
57+ }
58+
59+ Component.onCompleted: {
60+ ActionData.data = newMessage;
61+ Powerd.status = Powerd.On
62+ }
63+
64+ RowLayout {
65+ anchors.fill: parent
66+ anchors.margins: units.gu(1)
67+
68+ Item {
69+ Layout.fillWidth: true
70+ Layout.fillHeight: true
71+
72+ Rectangle {
73+ width: units.gu(4)
74+ height: width
75+ radius: width / 2
76+ anchors.centerIn: parent
77+
78+ color: Lights.state === Lights.On ? Lights.color : "transparent"
79+
80+ border.color: "black"
81+ border.width: 1
82+ }
83+ }
84+
85+ ColumnLayout {
86+ Layout.alignment: Qt.AlignTop
87+ Layout.fillWidth: false
88+ Layout.preferredWidth: units.gu(15)
89+
90+ Button {
91+ Layout.fillWidth: true
92+ text: Powerd.status === Powerd.On ? "Power Off" : "Power On"
93+ onClicked: {
94+ if (Powerd.status === Powerd.On) Powerd.status = Powerd.Off;
95+ else Powerd.status = Powerd.On;
96+ }
97+ }
98+ }
99+ }
100+
101+ UT.UnityTestCase {
102+ name: "IndicatorsLight"
103+ when: windowShown
104+
105+ function init() {
106+ // reload
107+ ActionData.data = noNewMessage;
108+ loader.sourceComponent = undefined;
109+ loader.sourceComponent = light;
110+ Powerd.status = Powerd.On
111+ }
112+
113+ function test_LightsStatus_data() {
114+ return [
115+ { tag: "Powerd.On with No Message", powerd: Powerd.On, actionData: noNewMessage, expected: Lights.Off },
116+ { tag: "Powerd.Off with No Message", powerd: Powerd.Off, actionData: noNewMessage, expected: Lights.Off },
117+ { tag: "Powerd.On with New Message", powerd: Powerd.On, actionData: newMessage, expected: Lights.Off },
118+ { tag: "Powerd.Off with New Message", powerd: Powerd.Off, actionData: newMessage, expected: Lights.On },
119+ ]
120+ }
121+
122+ function test_LightsStatus(data) {
123+ Powerd.status = data.powerd;
124+ ActionData.data = data.actionData;
125+
126+ compare(Lights.state, data.expected, "Light does not match expected value");
127+ }
128+ }
129+}
tests/qmltests/Panel/Indicators/tst_MenuItemFactory.qml+52−1
@@ -17,6 +17,7 @@
1717import QtQuick 2.0
1818import QtTest 1.0
1919import Unity.Test 0.1 as UT
20+import Ubuntu.Settings.Menus 0.1 as Menus
2021import QMenuModel 0.1
2122import Utils 0.1 as Utils
2223import "../../../../qml/Panel/Indicators"
@@ -448,9 +449,59 @@ Item {
448449 }
449450
450451 function test_create_transferMenu(data) {
452+ ActionData.data = {
453+ "transfer-state.queued": {
454+ 'valid': true,
455+ 'state': {
456+ 'state': Menus.TransferState.Queued,
457+ 'percent': data.progress
458+ }
459+ },
460+ "transfer-state.running": {
461+ 'valid': true,
462+ 'state': {
463+ 'state': Menus.TransferState.Running,
464+ 'seconds-left': 100,
465+ 'percent': data.progress
466+ }
467+ },
468+ "transfer-state.paused": {
469+ 'valid': true,
470+ 'state': {
471+ 'state': Menus.TransferState.Paused,
472+ 'seconds-left': 100,
473+ 'percent': data.progress
474+ }
475+ },
476+ "transfer-state.cancelled": {
477+ 'valid': true,
478+ 'state': {
479+ 'state': Menus.TransferState.Canceled,
480+ 'percent': data.progress
481+ }
482+ },
483+ "transfer-state.finished": {
484+ 'valid': true,
485+ 'state': {
486+ 'state': Menus.TransferState.Finished,
487+ 'seconds-left': 0,
488+ 'percent': data.progress
489+ }
490+ },
491+ "transfer-state.error": {
492+ 'valid': true,
493+ 'state': {
494+ 'state': Menus.TransferState.Error,
495+ 'seconds-left': 100,
496+ 'percent': data.progress
497+ }
498+ }
499+ };
500+
451501 menuData.type = "com.canonical.indicator.transfer";
452502 menuData.label = data.label;
453503 menuData.sensitive = data.enabled;
504+ menuData.isToggled = data.active;
454505 menuData.icon = data.icon;
455506 menuData.ext = {
456507 'xCanonicalUid': data.tag
@@ -464,7 +515,7 @@ Item {
464515 compare(loader.item.text, data.label, "Label does not match data");
465516 compare(loader.item.iconSource, data.icon, "Icon does not match data");
466517 compare(loader.item.enabled, data.enabled, "Enabled does not match data");
467− compare(loader.item.progress, data.progress, "Icon does not match data");
518+ compare(loader.item.progress, data.progress, "Progress does not match data");
468519 compare(loader.item.active, data.active, "Active does not match data");
469520 compare(loader.item.stateText, data.stateText, "State text does not match data");
470521 }
tests/qmltests/Panel/tst_IndicatorsBar.qml+1−1
@@ -197,7 +197,7 @@ IndicatorTest {
197197 if (indicatorsBar.mapFromItem(dataItem, dataItem.width/2, dataItem.height/2).x < 0) {
198198 skip("Out of bounds");
199199 }
200− mouseClick(dataItem, dataItem.width/2, dataItem.height/2);
200+ mouseClick(dataItem);
201201 verify(dataItem.selected === true);
202202 }
203203
tests/qmltests/Stages/tst_PhoneStage.qml+2
@@ -205,6 +205,7 @@ Item {
205205
206206 if (data.targetPhase == 2) {
207207 var app2 = findChild(spreadView, "appDelegate2");
208+ tryCompare(app2, "swipeToCloseEnabled", true);
208209 mouseClick(app2, units.gu(1), units.gu(1));
209210 }
210211
@@ -249,6 +250,7 @@ Item {
249250 }
250251
251252 console.log("clicking app", data.index, "(", appId, ")")
253+ tryCompare(tile, "swipeToCloseEnabled", true);
252254 mouseClick(spreadView, tile.mapToItem(spreadView).x + units.gu(1), spreadView.height / 2)
253255 tryCompare(ApplicationManager, "focusedApplicationId", appId);
254256 tryCompare(spreadView, "phase", 0);
tests/qmltests/Wizard/tst_Wizard.qml+36−12
@@ -18,6 +18,7 @@ import QtQuick 2.3
1818import QtTest 1.0
1919import AccountsService 0.1
2020import MeeGo.QOfono 0.2
21+import QMenuModel 0.1
2122import Ubuntu.Components 1.1
2223import Ubuntu.SystemSettings.SecurityPrivacy 1.0
2324import Unity.Test 0.1 as UT
@@ -58,6 +59,16 @@ Item {
5859 signalName: "setSecurityCalled"
5960 }
6061
62+ SignalSpy {
63+ id: activateLocationSpy
64+ signalName: "activated"
65+ }
66+
67+ SignalSpy {
68+ id: activateGPSSpy
69+ signalName: "activated"
70+ }
71+
6172 function setup() {
6273 AccountsService.hereEnabled = false;
6374 AccountsService.hereLicensePath = Qt.resolvedUrl("licenses");
@@ -68,6 +79,19 @@ Item {
6879
6980 updateSessionLanguageSpy.clear();
7081 setSecuritySpy.clear();
82+ activateLocationSpy.clear();
83+ activateGPSSpy.clear();
84+
85+ ActionData.data = {
86+ "location-detection-enabled": {
87+ 'valid': true,
88+ 'state': false
89+ },
90+ "gps-detection-enabled": {
91+ 'valid': true,
92+ 'state': false
93+ }
94+ };
7195 }
7296
7397 Component.onCompleted: {
@@ -360,8 +384,8 @@ Item {
360384 var nopeCheck = findChild(page, "nopeCheck");
361385
362386 var locationActionGroup = findInvisibleChild(page, "locationActionGroup");
363− tryCompare(locationActionGroup.location, "state", false);
364− tryCompare(locationActionGroup.gps, "state", false);
387+ activateLocationSpy.target = locationActionGroup.location;
388+ activateGPSSpy.target = locationActionGroup.gps;
365389
366390 tap(gpsCheck);
367391 tryCompare(gpsCheck, "checked", true);
@@ -370,8 +394,8 @@ Item {
370394
371395 tap(findChild(page, "forwardButton"));
372396 tryCompare(AccountsService, "hereEnabled", false);
373− tryCompare(locationActionGroup.location, "state", true);
374− tryCompare(locationActionGroup.gps, "state", true);
397+ tryCompare(activateLocationSpy, "count", 1)
398+ tryCompare(activateGPSSpy, "count", 1)
375399 }
376400
377401 function test_locationNope() {
@@ -381,8 +405,8 @@ Item {
381405 var nopeCheck = findChild(page, "nopeCheck");
382406
383407 var locationActionGroup = findInvisibleChild(page, "locationActionGroup");
384− tryCompare(locationActionGroup.location, "state", false);
385− tryCompare(locationActionGroup.gps, "state", false);
408+ activateLocationSpy.target = locationActionGroup.location;
409+ activateGPSSpy.target = locationActionGroup.gps;
386410
387411 tap(nopeCheck);
388412 tryCompare(gpsCheck, "checked", false);
@@ -391,8 +415,8 @@ Item {
391415
392416 tap(findChild(page, "forwardButton"));
393417 tryCompare(AccountsService, "hereEnabled", false);
394− tryCompare(locationActionGroup.location, "state", false);
395− tryCompare(locationActionGroup.gps, "state", false);
418+ tryCompare(activateLocationSpy, "count", 0)
419+ tryCompare(activateGPSSpy, "count", 0)
396420 }
397421
398422 function test_locationHere() {
@@ -402,8 +426,8 @@ Item {
402426 var nopeCheck = findChild(page, "nopeCheck");
403427
404428 var locationActionGroup = findInvisibleChild(page, "locationActionGroup");
405− tryCompare(locationActionGroup.location, "state", false);
406− tryCompare(locationActionGroup.gps, "state", false);
429+ activateLocationSpy.target = locationActionGroup.location;
430+ activateGPSSpy.target = locationActionGroup.gps;
407431
408432 // no tap because HERE is the default
409433 tryCompare(gpsCheck, "checked", false);
@@ -412,8 +436,8 @@ Item {
412436
413437 tap(findChild(page, "forwardButton"));
414438 tryCompare(AccountsService, "hereEnabled", true);
415− tryCompare(locationActionGroup.location, "state", true);
416− tryCompare(locationActionGroup.gps, "state", true);
439+ tryCompare(activateLocationSpy, "count", 1)
440+ tryCompare(activateGPSSpy, "count", 1)
417441 }
418442
419443 function test_locationHereTerms() {
tests/qmltests/tst_Shell.qml+3−3
@@ -222,7 +222,7 @@ Item {
222222
223223 notifications.model = mockNotificationsModel;
224224
225− // FIXME: Hack: SortFilterProxyModelQML doesn't work with QML ListModels which we use
225+ // FIXME: Hack: UnitySortFilterProxyModelQML doesn't work with QML ListModels which we use
226226 // for mocking here (RoleType can't be found in the QML model). As we only need to show
227227 // one SnapDecision lets just disable the filtering and make appear any notification as a
228228 // SnapDecision.
@@ -245,7 +245,7 @@ Item {
245245
246246 // Clicking the button should dismiss the notification and return focus
247247 var buttonAccept = findChild(notification, "notify_button0");
248− mouseClick(buttonAccept, buttonAccept.width / 2, buttonAccept.height / 2);
248+ mouseClick(buttonAccept);
249249
250250 // Make sure we're back to normal
251251 tryCompare(app.session.surface, "activeFocus", true);
@@ -463,7 +463,7 @@ Item {
463463 var launcher = findChild(shell, "launcherPanel")
464464 tryCompareFunction(function() {return launcher.x === 0 || launcher.x === -launcher.width;}, true);
465465 if (launcher.x === 0) {
466− mouseClick(shell, shell.width / 2, shell.height / 2)
466+ mouseClick(shell)
467467 }
468468 tryCompare(launcher, "x", -launcher.width)
469469
tests/qmltests/tst_ShellWithPin.qml+31
@@ -119,6 +119,12 @@ Item {
119119 signalName: "resettingDevice"
120120 }
121121
122+ SignalSpy {
123+ id: promptSpy
124+ target: LightDM.Greeter
125+ signalName: "showPrompt"
126+ }
127+
122128 Telephony.CallEntry {
123129 id: phoneCall
124130 phoneNumber: "+447812221111"
@@ -481,5 +487,30 @@ Item {
481487
482488 }
483489
490+ /* We had a bug (1395075) where if a user kept swiping as the greeter
491+ loaded, they would be able to get into the session before the
492+ lockscreen appeared. Make sure that doesn't happen. */
493+ function test_earlyDisable() {
494+ // Kill current shell
495+ shellLoader.itemDestroyed = false;
496+ shellLoader.active = false;
497+ tryCompare(shellLoader, "itemDestroyed", true);
498+ LightDM.Greeter.authenticate(""); // reset greeter
499+
500+ // Create new shell
501+ promptSpy.clear();
502+ shellLoader.active = true;
503+ tryCompareFunction(function() {return shell !== null}, true);
504+
505+ // Confirm that we start disabled
506+ compare(promptSpy.count, 0);
507+ verify(!shell.enabled);
508+
509+ // And that we only become enabled once the lockscreen is up
510+ tryCompare(shell, "enabled", true);
511+ verify(promptSpy.count > 0);
512+ var lockscreen = findChild(shell, "lockscreen");
513+ verify(lockscreen.shown);
514+ }
484515 }
485516}
tests/qmltests/tst_TabletShell.qml+1−1
@@ -214,7 +214,7 @@ Item {
214214 tryCompare(passwordMouseArea, "enabled", isButton)
215215
216216 var passwordInput = findChild(shell, "passwordInput")
217− mouseClick(passwordInput, passwordInput.width / 2, passwordInput.height / 2)
217+ mouseClick(passwordInput)
218218 }
219219
220220 function confirmLoggedIn(loggedIn) {
tests/utils/modules/Unity/Test/UnityTestCase.qml+88−69
@@ -37,6 +37,71 @@ TestCase {
3737 this.getCurrentTimeMs = function() {return this.currentTimeMs}
3838 }
3939
40+ // TODO This function can be removed altogether once we use Qt 5.5 which has the same feature
41+ function mouseClick(item, x, y, button, modifiers, delay) {
42+ if (button === undefined)
43+ button = Qt.LeftButton;
44+ if (modifiers === undefined)
45+ modifiers = Qt.NoModifier;
46+ if (delay === undefined)
47+ delay = -1;
48+ if (x === undefined)
49+ x = item.width / 2;
50+ if (y === undefined)
51+ y = item.height / 2;
52+ if (!qtest_events.mouseClick(item, x, y, button, modifiers, delay))
53+ qtest_fail("window not shown", 2);
54+ }
55+
56+ // TODO This function can be removed altogether once we use Qt 5.5 which has the same feature
57+ function mouseDoubleClick(item, x, y, button, modifiers, delay) {
58+ if (button === undefined)
59+ button = Qt.LeftButton;
60+ if (modifiers === undefined)
61+ modifiers = Qt.NoModifier;
62+ if (delay === undefined)
63+ delay = -1;
64+ if (x === undefined)
65+ x = item.width / 2;
66+ if (y === undefined)
67+ y = item.height / 2;
68+ if (!qtest_events.mouseDoubleClick(item, x, y, button, modifiers, delay))
69+ qtest_fail("window not shown", 2)
70+ }
71+
72+ // TODO This function can be removed altogether once we use Qt 5.5 which has the same feature
73+ function mousePress(item, x, y, button, modifiers, delay) {
74+ if (button === undefined)
75+ button = Qt.LeftButton;
76+ if (modifiers === undefined)
77+ modifiers = Qt.NoModifier;
78+ if (delay === undefined)
79+ delay = -1;
80+ if (x === undefined)
81+ x = item.width / 2;
82+ if (y === undefined)
83+ y = item.height / 2;
84+ if (!qtest_events.mousePress(item, x, y, button, modifiers, delay))
85+ qtest_fail("window not shown", 2)
86+ }
87+
88+ // TODO This function can be removed altogether once we use Qt 5.5 which has the same feature
89+ function mouseRelease(item, x, y, button, modifiers, delay) {
90+ if (button === undefined)
91+ button = Qt.LeftButton;
92+ if (modifiers === undefined)
93+ modifiers = Qt.NoModifier;
94+ if (delay === undefined)
95+ delay = -1;
96+ if (x === undefined)
97+ x = item.width / 2;
98+ if (y === undefined)
99+ y = item.height / 2;
100+ if (!qtest_events.mouseRelease(item, x, y, button, modifiers, delay))
101+ qtest_fail("window not shown", 2)
102+ }
103+
104+
40105 // Flickable won't recognise a single mouse move as dragging the flickable.
41106 // Use 5 steps because it's what
42107 // Qt uses in QQuickViewTestUtil::flick
@@ -109,78 +174,22 @@ TestCase {
109174 return null;
110175 }
111176
177+ function findChildsByType(obj, typeName) {
178+ var res = new Array(0);
179+ for (var i in obj.children) {
180+ var c = obj.children[i];
181+ if (UT.Util.isInstanceOf(c, typeName)) {
182+ res.push(c)
183+ }
184+ res = res.concat(findChildsByType(c, typeName));
185+ }
186+ return res;
187+ }
188+
112189 // Type a full string instead of keyClick letter by letter
113− // TODO: this is not ugly, this is uber-ugly and does not support
114− // any special character. Remove the keyMap once keyClick(obj, char)
115− // has landed in upstream Qt.
116190 function typeString(str) {
117− var keyMap = {
118− "a": Qt.Key_A,
119− "b": Qt.Key_B,
120− "c": Qt.Key_C,
121− "d": Qt.Key_D,
122− "e": Qt.Key_E,
123− "f": Qt.Key_F,
124− "g": Qt.Key_G,
125− "h": Qt.Key_H,
126− "i": Qt.Key_I,
127− "j": Qt.Key_J,
128− "k": Qt.Key_K,
129− "l": Qt.Key_L,
130− "m": Qt.Key_M,
131− "n": Qt.Key_N,
132− "o": Qt.Key_O,
133− "p": Qt.Key_P,
134− "q": Qt.Key_Q,
135− "r": Qt.Key_R,
136− "s": Qt.Key_S,
137− "t": Qt.Key_T,
138− "u": Qt.Key_U,
139− "v": Qt.Key_V,
140− "w": Qt.Key_W,
141− "x": Qt.Key_X,
142− "y": Qt.Key_Y,
143− "z": Qt.Key_Z,
144− "A": Qt.Key_A,
145− "B": Qt.Key_B,
146− "C": Qt.Key_C,
147− "D": Qt.Key_D,
148− "E": Qt.Key_E,
149− "F": Qt.Key_F,
150− "G": Qt.Key_G,
151− "H": Qt.Key_H,
152− "I": Qt.Key_I,
153− "J": Qt.Key_J,
154− "K": Qt.Key_K,
155− "L": Qt.Key_L,
156− "M": Qt.Key_M,
157− "N": Qt.Key_N,
158− "O": Qt.Key_O,
159− "P": Qt.Key_P,
160− "Q": Qt.Key_Q,
161− "R": Qt.Key_R,
162− "S": Qt.Key_S,
163− "T": Qt.Key_T,
164− "U": Qt.Key_U,
165− "V": Qt.Key_V,
166− "W": Qt.Key_W,
167− "X": Qt.Key_X,
168− "Y": Qt.Key_Y,
169− "Z": Qt.Key_Z,
170− "0": Qt.Key_0,
171− "1": Qt.Key_1,
172− "2": Qt.Key_2,
173− "3": Qt.Key_3,
174− "4": Qt.Key_4,
175− "5": Qt.Key_5,
176− "6": Qt.Key_6,
177− "7": Qt.Key_7,
178− "8": Qt.Key_8,
179− "9": Qt.Key_9,
180− " ": Qt.Key_Space,
181− }
182191 for (var i = 0; i < str.length; i++) {
183− keyClick(keyMap[str[i]])
192+ keyClick(str[i])
184193 }
185194 }
186195
@@ -381,4 +390,14 @@ TestCase {
381390 }
382391 }
383392 }
393+
394+ // TODO This function can be removed altogether once we use Qt 5.5 which has the same feature
395+ function waitForRendering(item, timeout) {
396+ if (timeout === undefined)
397+ timeout = 5000;
398+ if (!item)
399+ qtest_fail("No item given to waitForRendering", 1);
400+ return qtest_results.waitForRendering(item, timeout);
401+ }
402+
384403}