on xenial help sign in
merged with trunk
commit1b40225d768334b05e2c4d20c3e5e1d8bf021bd8 authorNick Dedekind <nick.dedekind@canonical.com> dateWed 15 Apr 2015, 15:09 (12 years ago) parent0f63ce97478eb8
76 files changed+1837−476
CMakeLists.txt+2 CODING+1−1 data/CMakeLists.txt+2 data/indicators-client.desktop.in+9 data/unity-mock-indicator-service.conf+7 debian/changelog+53 debian/control+2−2 debian/indicators-client.install+1 debian/unity8-autopilot.install+3−1 include/paths.h.in+1−6 plugins/Greeter/Unity/Launcher/CMakeLists.txt−1 plugins/ScreenGrabber/screengrabber.cpp+1−1 plugins/Ubuntu/Gestures/TouchGate.cpp−2 plugins/Ubuntu/Gestures/TouchGate.h−2 plugins/Unity/Launcher/launchermodel.cpp+7−7 plugins/Utils/CMakeLists.txt+2 plugins/Utils/constants.cpp+27 plugins/Utils/constants.h+43 plugins/Utils/inputwatcher.cpp+118 plugins/Utils/inputwatcher.h+58 plugins/Utils/plugin.cpp+11 po/bg.po+38−39 po/en_AU.po+38−39 po/fa.po+38−39 po/sk.po+38−39 po/sr.po+33−32 qml/Components/Dialogs.qml+2 qml/Dash/Dash.qml+27−14 qml/Dash/DashContent.qml−5 qml/Dash/GenericScopeView.qml+1−2 qml/Panel/Indicators/MenuItemFactory.qml+48−52 qml/Panel/Indicators/client/IndicatorsList.qml+2−2 qml/Panel/IndicatorsMenu.qml+5−1 qml/Panel/Panel.qml+1 qml/Shell.qml+28−18 qml/Stages/SurfaceContainer.qml+12−9 qml/Tutorial/Tutorial.qml+7−14 qml/Tutorial/TutorialContent.qml+9−8 run.sh+1−1 src/Panel/Indicators/client/CMakeLists.txt−2 src/main.cpp+26 tests/autopilot/unity8/application_lifecycle/tests/test_application_lifecycle.py+2−4 tests/autopilot/unity8/fixture_setup.py+46−1 tests/autopilot/unity8/greeter/__init__.py tests/autopilot/unity8/greeter/tests/__init__.py+26 tests/autopilot/unity8/greeter/tests/test_args.py+52 tests/autopilot/unity8/indicators/__init__.py+89−10 tests/autopilot/unity8/indicators/tests/__init__.py+7 tests/autopilot/unity8/indicators/tests/test_action_latency.py+232 tests/autopilot/unity8/indicators/tests/test_display_indicator.py+3−1 tests/autopilot/unity8/indicators/tests/test_indicators.py+2−2 tests/autopilot/unity8/process_helpers.py+47−14 tests/autopilot/unity8/shell/tests/__init__.py+13−4 tests/autopilot/unity8/shell/tests/test_lock_screen.py+1−1 tests/mocks/CMakeLists.txt+1 tests/mocks/GSettings.1.0/fake_gsettings.cpp+47−50 tests/mocks/GSettings.1.0/fake_gsettings.h+14−20 tests/mocks/Unity/Application/MirSurfaceItem.cpp+6 tests/mocks/Unity/Application/MirSurfaceItem.h+5 tests/mocks/Unity/fake_scope.cpp+13−2 tests/mocks/Unity/fake_scope.h+4−2 tests/mocks/data/unity/indicators/com.canonical.indicator.mock+10 tests/mocks/indicator-service/CMakeLists.txt+20 tests/mocks/indicator-service/mock-indicator-service.c+261 tests/plugins/Unity/Indicators/indicatorsmanagertest.cpp−2 tests/plugins/Unity/Indicators/indicatorsmodeltest.cpp−2 tests/plugins/Unity/Launcher/launchermodeltest.cpp+57 tests/qmltests/Components/tst_Dialogs.qml+4−2 tests/qmltests/Dash/tst_Dash.qml+49−1 tests/qmltests/Dash/tst_GenericScopeView.qml+1−1 tests/qmltests/Dash/tst_PreviewListView.qml+1−1 tests/qmltests/Panel/Indicators/tst_MenuItemFactory.qml+5−1 tests/qmltests/Panel/tst_Panel.qml+52 tests/qmltests/Stages/tst_SurfaceContainer.qml+32−5 tests/qmltests/Tutorial/tst_Tutorial.qml+22−5 tests/qmltests/tst_Shell.qml+11−6
CMakeLists.txt+2
@@ -105,6 +105,8 @@ declare_autopilot_test(shell unity8.shell ${CMAKE_SOURCE_DIR}/tests/autopilot/)
105105set(SHELL_APP unity8)
106106set(DASH_APP unity8-dash)
107107set(SCOPE_TOOL unity-scope-tool)
108+set(INDICATORS_CLIENT_APP indicators-client)
109+set(MOCK_INDICATOR_SERVICE_APP unity-mock-indicator-service)
108110
109111include_directories(
110112 ${CMAKE_SOURCE_DIR}/include
CODING+1−1
@@ -186,7 +186,7 @@ $ make install
186186
187187To see the list of existing autopilot tests you can do
188188
189−$ PYTHONPATH=../tests/autopilot autopilot list unity8
189+$ PYTHONPATH=../tests/autopilot autopilot3 list unity8
190190
191191And then run a single test with
192192
data/CMakeLists.txt+2
@@ -1,11 +1,13 @@
11# generate desktop files
22configure_file(${SHELL_APP}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop @ONLY)
33configure_file(${DASH_APP}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${DASH_APP}.desktop @ONLY)
4+configure_file(${INDICATORS_CLIENT_APP}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${INDICATORS_CLIENT_APP}.desktop @ONLY)
45
56# install desktop files
67install(FILES
78 ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop
89 ${CMAKE_CURRENT_BINARY_DIR}/${DASH_APP}.desktop
10+ ${CMAKE_CURRENT_BINARY_DIR}/${INDICATORS_CLIENT_APP}.desktop
911 DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
1012 )
1113
data/indicators-client.desktop.innew file+9
@@ -0,0 +1,9 @@
1+[Desktop Entry]
2+Type=Application
3+Name=Indicators Client
4+Comment=Application for testing the Indicators system
5+Exec=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_BINDIR@/indicators-client
6+Terminal=false
7+Icon=
8+NoDisplay=false
9+X-Ubuntu-Touch=true
data/unity-mock-indicator-service.confnew file+7
@@ -0,0 +1,7 @@
1+description "Unity Shell v8 Mock Indicator"
2+author "Nick Dedekind <nick.dedekind@canonical.com>"
3+
4+respawn
5+respawn limit 2 10
6+
7+exec ${BINARY:-unity-mock-indicator-service} $ARGS
debian/changelog+53
@@ -1,3 +1,56 @@
1+unity8 (8.02+15.04.20150409.1-0ubuntu1) vivid; urgency=medium
2+
3+ [ Albert Astals Cid ]
4+ * Focus the shutdown dialog (LP: #1417991)
5+ * Make url-dispatching scope activation when the dash is not on the
6+ main scopes (LP: #1364306)
7+ * We use autopilot3 now
8+
9+ [ CI Train Bot ]
10+ * New rebuild forced.
11+ * Resync trunk. added: po/or.po
12+
13+ [ Daniel d'Andrada ]
14+ * Make tst_PreviewListView and tst_GenericScopeView work in out-of-
15+ source builds
16+ * MouseArea that shows the indicators panel should cover the
17+ indicators bar only (LP: #1439318)
18+ * Surface gets active focus also with mouse clicks
19+
20+ [ Josh Arenson ]
21+ * Add a mode option to unity8 for selecting greeter mode in the future
22+ * Remove PkgConfig include from Launcher plugin to fix cross-compile
23+ (LP: #1437702)
24+
25+ [ Leo Arias ]
26+ * Fixed the check for string in the lock screen test. (LP: #1434518)
27+
28+ [ Michael Terry ]
29+ * Make sure the edge tutorial is destroyed when we receive a call
30+ during the wizard. (LP: #1436349)
31+ * Skip parts of the edge tutorial that require a touch device (like
32+ spread and bottom edge). (LP: #1434712)
33+
34+ [ Michael Zanetti ]
35+ * Don't hide stages just because they're empty (LP: #1439615)
36+ * [Launcher] fix bug where an item would disappear even though the app
37+ is running (LP: #1438172)
38+
39+ [ Nick Dedekind ]
40+ * Fixed autopilot test failures related to udev input failure for
41+ power button.
42+ * Made improvements for laggy indicator backends (lp#1390136). (LP:
43+ #1390136)
44+
45+ [ Pete Woods ]
46+ * GPS only goes active when the Dash is in the foreground (LP:
47+ #1434379)
48+
49+ [ handsome_feng<445865575@qq.com> ]
50+ * Modified the wrong time format in ScreenGrabber (LP: #1436006)
51+
52+ -- CI Train Bot <ci-train-bot@canonical.com> Thu, 09 Apr 2015 14:01:11 +0000
53+
154unity8 (8.02+15.04.20150320-0ubuntu1) vivid; urgency=medium
255
356 [ Albert Astals Cid ]
debian/control+2−2
@@ -47,7 +47,7 @@ Build-Depends: cmake,
4747 qtdeclarative5-dev-tools,
4848 qtdeclarative5-private-dev (>= 5.2.1),
4949 qtdeclarative5-qtmultimedia-plugin,
50− qtdeclarative5-ubuntu-settings-components (>= 0.5),
50+ qtdeclarative5-ubuntu-settings-components (>= 0.6),
5151 qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.1.1239) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.1.1239),
5252 qtdeclarative5-ubuntu-web-plugin,
5353 ttf-ubuntu-font-family,
@@ -119,7 +119,7 @@ Description: Unity 8 shell
119119Package: unity8-common
120120Architecture: all
121121Depends: qml-module-qtquick-layouts,
122− qtdeclarative5-ubuntu-settings-components (>= 0.4),
122+ qtdeclarative5-ubuntu-settings-components (>= 0.6),
123123 qtdeclarative5-ubuntu-thumbnailer0.1 | ubuntu-thumbnailer-impl,
124124 qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.1.1239) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.1.1239),
125125 qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl,
debian/indicators-client.install+1
@@ -1 +1,2 @@
1+usr/share/applications/indicators-client.desktop
12/usr/bin/indicators-client
debian/unity8-autopilot.install+3−1
@@ -1,2 +1,4 @@
1+data/unity-mock-indicator-service.conf usr/share/upstart/sessions/
2+usr/bin/unity-mock-indicator-service
13usr/lib/python*/*/unity*
2−usr/share/unity8/unlock-device
4+usr/share/unity8/unlock-device
include/paths.h.in+1−6
@@ -92,12 +92,7 @@ inline QString mockPluginsDir() {
9292
9393inline QStringList shellDataDirs() {
9494 QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
95− if (!isRunningInstalled()) {
96− if (getenv("UNITY_TEST_ENV")==nullptr) {
97− dirs.prepend("@CMAKE_BINARY_DIR@/share");
98− }
99− }
100− else {
95+ if (isRunningInstalled()) {
10196 // append so by default we use xdg files.
10297 dirs.append(qmlDirectory());
10398 }
plugins/Greeter/Unity/Launcher/CMakeLists.txt−1
@@ -1,4 +1,3 @@
1−include(FindPkgConfig)
21pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
32pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=5)
43pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
plugins/ScreenGrabber/screengrabber.cpp+1−1
@@ -81,7 +81,7 @@ void ScreenGrabber::captureAndSave()
8181QString ScreenGrabber::makeFileName()
8282{
8383 QString fileName(fileNamePrefix);
84− fileName.append(QDateTime::currentDateTime().toString("yyyymmdd_hhmmsszzz"));
84+ fileName.append(QDateTime::currentDateTime().toString("yyyyMMdd_hhmmsszzz"));
8585 fileName.append(".");
8686 fileName.append(getFormat());
8787 return fileName;
plugins/Ubuntu/Gestures/TouchGate.cpp−2
@@ -53,8 +53,6 @@ void TouchGate::touchEvent(QTouchEvent *event)
5353 m_touchInfoMap[touchPoint.id()].ownership = OwnershipRequested;
5454 m_touchInfoMap[touchPoint.id()].ended = false;
5555 TouchRegistry::instance()->requestTouchOwnership(touchPoint.id(), this);
56−
57− Q_EMIT pressed();
5856 }
5957
6058 goodToGo &= m_touchInfoMap.contains(touchPoint.id())
plugins/Ubuntu/Gestures/TouchGate.h−2
@@ -53,8 +53,6 @@ public:
5353Q_SIGNALS:
5454 void targetItemChanged(QQuickItem *item);
5555
56− void pressed();
57−
5856protected:
5957 void touchEvent(QTouchEvent *event) override;
6058private:
plugins/Unity/Launcher/launchermodel.cpp+7−7
@@ -468,14 +468,14 @@ void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
468468 return;
469469 }
470470
471− bool found = false;
472− Q_FOREACH(LauncherItem *item, m_list) {
473− if (app->appId() == item->appId()) {
474− found = true;
475− break;
471+ int itemIndex = findApplication(app->appId());
472+ if (itemIndex != -1) {
473+ LauncherItem *item = m_list.at(itemIndex);
474+ if (!item->recent()) {
475+ item->setRecent(true);
476+ m_asAdapter->syncItems(m_list);
477+ Q_EMIT dataChanged(index(itemIndex), index(itemIndex), QVector<int>() << RoleRecent);
476478 }
477− }
478− if (found) {
479479 // Shall we paint some running/recent app highlight? If yes, do it here.
480480 } else {
481481 LauncherItem *item = new LauncherItem(app->appId(), app->name(), app->icon().toString(), this);
plugins/Utils/CMakeLists.txt+2
@@ -8,6 +8,8 @@ include_directories(
88)
99
1010set(QMLPLUGIN_SRC
11+ constants.cpp
12+ inputwatcher.cpp
1113 qlimitproxymodelqml.cpp
1214 unitysortfilterproxymodelqml.cpp
1315 relativetimeformatter.cpp
plugins/Utils/constants.cppnew file+27
@@ -0,0 +1,27 @@
1+/*
2+ * Copyright 2015 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 "constants.h"
18+
19+Constants::Constants(QObject *parent)
20+ : QObject(parent)
21+{
22+ if (qgetenv("QT_LOAD_TESTABILITY").isEmpty()) {
23+ m_indicatorValueTimeout = 30000;
24+ } else {
25+ m_indicatorValueTimeout = 5000;
26+ }
27+}
plugins/Utils/constants.hnew file+43
@@ -0,0 +1,43 @@
1+/*
2+ * Copyright 2015 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 CONSTANTS_H
18+#define CONSTANTS_H
19+
20+#include <QObject>
21+
22+/**
23+ * @brief The Constants class
24+ *
25+ * This singleton class exposes contants to Qml
26+ *
27+ */
28+
29+class Constants: public QObject
30+{
31+ Q_OBJECT
32+ Q_PROPERTY(int indicatorValueTimeout READ indicatorValueTimeout CONSTANT)
33+
34+public:
35+ Constants(QObject *parent = 0);
36+
37+ int indicatorValueTimeout() const { return m_indicatorValueTimeout; }
38+
39+private:
40+ int m_indicatorValueTimeout;
41+};
42+
43+#endif
plugins/Utils/inputwatcher.cppnew file+118
@@ -0,0 +1,118 @@
1+/*
2+ * Copyright (C) 2015 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+
18+#include "inputwatcher.h"
19+
20+#include <QMouseEvent>
21+
22+InputWatcher::InputWatcher(QObject *parent)
23+ : QObject(parent)
24+ , m_mousePressed(false)
25+ , m_touchPressed(false)
26+{
27+}
28+
29+QObject *InputWatcher::target() const
30+{
31+ return m_target;
32+}
33+
34+void InputWatcher::setTarget(QObject *value)
35+{
36+ if (m_target == value) {
37+ return;
38+ }
39+
40+ if (m_target) {
41+ m_target->removeEventFilter(this);
42+ }
43+
44+ setMousePressed(false);
45+ setTouchPressed(false);
46+
47+ m_target = value;
48+ if (m_target) {
49+ m_target->installEventFilter(this);
50+ }
51+
52+ Q_EMIT targetChanged(value);
53+}
54+
55+bool InputWatcher::targetPressed() const
56+{
57+ return m_mousePressed || m_touchPressed;
58+}
59+
60+bool InputWatcher::eventFilter(QObject* /*watched*/, QEvent *event)
61+{
62+ switch (event->type()) {
63+ case QEvent::TouchBegin:
64+ setTouchPressed(true);
65+ break;
66+ case QEvent::TouchEnd:
67+ setTouchPressed(false);
68+ break;
69+ case QEvent::MouseButtonPress:
70+ {
71+ QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
72+ if (mouseEvent->button() == Qt::LeftButton) {
73+ setMousePressed(true);
74+ }
75+ }
76+ break;
77+ case QEvent::MouseButtonRelease:
78+ {
79+ QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
80+ if (mouseEvent->button() == Qt::LeftButton) {
81+ setMousePressed(false);
82+ }
83+ }
84+ break;
85+ default:
86+ // Not interested
87+ break;
88+ }
89+
90+ // We never filter them out. We are just watching.
91+ return false;
92+}
93+
94+void InputWatcher::setMousePressed(bool value)
95+{
96+ if (value == m_mousePressed) {
97+ return;
98+ }
99+
100+ bool oldPressed = targetPressed();
101+ m_mousePressed = value;
102+ if (targetPressed() != oldPressed) {
103+ Q_EMIT targetPressedChanged(targetPressed());
104+ }
105+}
106+
107+void InputWatcher::setTouchPressed(bool value)
108+{
109+ if (value == m_touchPressed) {
110+ return;
111+ }
112+
113+ bool oldPressed = targetPressed();
114+ m_touchPressed = value;
115+ if (targetPressed() != oldPressed) {
116+ Q_EMIT targetPressedChanged(targetPressed());
117+ }
118+}
plugins/Utils/inputwatcher.hnew file+58
@@ -0,0 +1,58 @@
1+/*
2+ * Copyright (C) 2015 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+
18+#ifndef UNITY_INPUTWATCHER_H
19+#define UNITY_INPUTWATCHER_H
20+
21+#include <QObject>
22+#include <QPointer>
23+
24+/*
25+ Monitors the target object for input events to figure out whether it's pressed
26+ or not.
27+ */
28+class InputWatcher : public QObject
29+{
30+ Q_OBJECT
31+ Q_PROPERTY(QObject* target READ target WRITE setTarget NOTIFY targetChanged)
32+
33+ // Whether the target object is pressed (by either touch or mouse)
34+ Q_PROPERTY(bool targetPressed READ targetPressed NOTIFY targetPressedChanged)
35+public:
36+ InputWatcher(QObject *parent = nullptr);
37+
38+ QObject *target() const;
39+ void setTarget(QObject *value);
40+
41+ bool targetPressed() const;
42+
43+ bool eventFilter(QObject *watched, QEvent *event) override;
44+
45+Q_SIGNALS:
46+ void targetChanged(QObject *value);
47+ void targetPressedChanged(bool value);
48+
49+private:
50+ void setMousePressed(bool value);
51+ void setTouchPressed(bool value);
52+
53+ bool m_mousePressed;
54+ bool m_touchPressed;
55+ QPointer<QObject> m_target;
56+};
57+
58+#endif // UNITY_INPUTWATCHER_H
plugins/Utils/plugin.cpp+11
@@ -26,6 +26,7 @@
2626#include "plugin.h"
2727
2828// local
29+#include "inputwatcher.h"
2930#include "qlimitproxymodelqml.h"
3031#include "unitysortfilterproxymodelqml.h"
3132#include "relativetimeformatter.h"
@@ -34,6 +35,7 @@
3435#include "windowkeysfilter.h"
3536#include "easingcurve.h"
3637#include "windowstatestorage.h"
38+#include "constants.h"
3739
3840static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
3941{
@@ -42,6 +44,13 @@ static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEn
4244 return new WindowStateStorage();
4345}
4446
47+static QObject *createConstants(QQmlEngine *engine, QJSEngine *scriptEngine)
48+{
49+ Q_UNUSED(engine)
50+ Q_UNUSED(scriptEngine)
51+ return new Constants();
52+}
53+
4554void UtilsPlugin::registerTypes(const char *uri)
4655{
4756 Q_ASSERT(uri == QLatin1String("Utils"));
@@ -55,6 +64,8 @@ void UtilsPlugin::registerTypes(const char *uri)
5564 qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve");
5665 qmlRegisterType<RelativeTimeFormatter>(uri, 0, 1, "RelativeTimeFormatter");
5766 qmlRegisterSingletonType<WindowStateStorage>(uri, 0, 1, "WindowStateStorage", createWindowStateStorage);
67+ qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher");
68+ qmlRegisterSingletonType<Constants>(uri, 0, 1, "Constants", createConstants);
5869}
5970
6071void UtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
po/bg.po+38−39
@@ -15,35 +15,35 @@ msgstr ""
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: 2015-04-13 05:42+0000\n"
18+"X-Launchpad-Export-Date: 2015-04-14 05:33+0000\n"
1919"X-Generator: Launchpad (build 17423)\n"
2020
21−#: plugins/LightDM/Greeter.cpp:130
21+#: plugins/LightDM/Greeter.cpp:112
2222msgid "Password: "
2323msgstr ""
2424
2525#: plugins/Unity/Launcher/launcheritem.cpp:45
26−#: plugins/Unity/Launcher/launcheritem.cpp:91
26+#: plugins/Unity/Launcher/launcheritem.cpp:100
2727msgid "Pin shortcut"
2828msgstr ""
2929
30−#: plugins/Unity/Launcher/launcheritem.cpp:91
30+#: plugins/Unity/Launcher/launcheritem.cpp:100
3131msgid "Unpin shortcut"
3232msgstr ""
3333
34−#: qml/Components/DelayedLockscreen.qml:47
34+#: qml/Components/DelayedLockscreen.qml:49
3535msgid "Device Locked"
3636msgstr ""
3737
38−#: qml/Components/DelayedLockscreen.qml:62
38+#: qml/Components/DelayedLockscreen.qml:64
3939msgid "You have been locked out due to too many failed passphrase attempts."
4040msgstr ""
4141
42−#: qml/Components/DelayedLockscreen.qml:63
42+#: qml/Components/DelayedLockscreen.qml:65
4343msgid "You have been locked out due to too many failed passcode attempts."
4444msgstr ""
4545
46−#: qml/Components/DelayedLockscreen.qml:72
46+#: qml/Components/DelayedLockscreen.qml:74
4747#, qt-format
4848msgid "Please wait %1 minute and then try again…"
4949msgid_plural "Please wait %1 minutes and then try again…"
@@ -55,7 +55,7 @@ msgctxt "Title: Lock/Log out dialog"
5555msgid "Log out"
5656msgstr ""
5757
58−#: qml/Components/Dialogs.qml:75
58+#: qml/Components/Dialogs.qml:68
5959msgid "Are you sure you want to log out?"
6060msgstr ""
6161
@@ -69,6 +69,7 @@ msgctxt "Button: Log out from the system"
6969msgid "Log Out"
7070msgstr ""
7171
72+#: qml/Components/Dialogs.qml:84 qml/Components/Dialogs.qml:115
7273#: qml/Components/Dialogs.qml:171
7374msgid "Cancel"
7475msgstr ""
@@ -78,7 +79,7 @@ msgctxt "Title: Reboot/Shut down dialog"
7879msgid "Shut down"
7980msgstr ""
8081
81−#: qml/Components/Dialogs.qml:99
82+#: qml/Components/Dialogs.qml:97
8283msgid "Are you sure you want to shut down?"
8384msgstr ""
8485
@@ -97,17 +98,15 @@ msgctxt "Title: Reboot dialog"
9798msgid "Reboot"
9899msgstr ""
99100
100−#: qml/Components/Dialogs.qml:124
101+#: qml/Components/Dialogs.qml:128
101102msgid "Are you sure you want to reboot?"
102103msgstr ""
103104
104−#: qml/Components/Dialogs.qml:77 qml/Components/Dialogs.qml:101
105−#: qml/Components/Dialogs.qml:126
105+#: qml/Components/Dialogs.qml:130
106106msgid "No"
107107msgstr ""
108108
109−#: qml/Components/Dialogs.qml:84 qml/Components/Dialogs.qml:108
110−#: qml/Components/Dialogs.qml:133
109+#: qml/Components/Dialogs.qml:136
111110msgid "Yes"
112111msgstr ""
113112
@@ -116,7 +115,7 @@ msgctxt "Title: Power off/Restart dialog"
116115msgid "Power"
117116msgstr ""
118117
119−#: qml/Components/Dialogs.qml:149
118+#: qml/Components/Dialogs.qml:151
120119msgid ""
121120"Are you sure you would like\n"
122121"to power off?"
@@ -134,23 +133,23 @@ msgctxt "Button: Restart the system"
134133msgid "Restart"
135134msgstr ""
136135
137−#: qml/Components/Lockscreen.qml:223
136+#: qml/Components/Lockscreen.qml:238
138137msgid "Return to Call"
139138msgstr ""
140139
141−#: qml/Components/Lockscreen.qml:223
140+#: qml/Components/Lockscreen.qml:238
142141msgid "Emergency Call"
143142msgstr "Спешно повикване"
144143
145−#: qml/Components/Lockscreen.qml:255
144+#: qml/Components/Lockscreen.qml:270
146145msgid "OK"
147146msgstr ""
148147
149−#: qml/Dash/GenericScopeView.qml:434 qml/Dash/GenericScopeView.qml:591
148+#: qml/Dash/GenericScopeView.qml:533 qml/Dash/GenericScopeView.qml:691
150149msgid "See less"
151150msgstr ""
152151
153−#: qml/Dash/GenericScopeView.qml:434
152+#: qml/Dash/GenericScopeView.qml:533
154153msgid "See all"
155154msgstr ""
156155
@@ -174,11 +173,11 @@ msgctxt "Button: Show the current dash scope settings"
174173msgid "Settings"
175174msgstr ""
176175
177−#: qml/Dash/PageHeader.qml:285
176+#: qml/Dash/PageHeader.qml:293
178177msgid "Remove from Favorites"
179178msgstr ""
180179
181−#: qml/Dash/PageHeader.qml:285
180+#: qml/Dash/PageHeader.qml:293
182181msgid "Add to Favorites"
183182msgstr ""
184183
@@ -214,19 +213,19 @@ msgstr ""
214213msgid "Enable location data"
215214msgstr ""
216215
217−#: qml/Dash/ScopesList.qml:63
216+#: qml/Dash/ScopesList.qml:66
218217msgid "Manage"
219218msgstr ""
220219
221−#: qml/Dash/ScopesList.qml:107
220+#: qml/Dash/ScopesList.qml:112
222221msgid "Home"
223222msgstr ""
224223
225−#: qml/Dash/ScopesList.qml:108
224+#: qml/Dash/ScopesList.qml:113
226225msgid "Also installed"
227226msgstr ""
228227
229−#: qml/Greeter/Greeter.qml:174
228+#: qml/Greeter/CoverPage.qml:107
230229msgid "Unlock"
231230msgstr ""
232231
@@ -238,57 +237,57 @@ msgstr ""
238237msgid "Tap to unlock"
239238msgstr ""
240239
241−#: qml/Shell.qml:444
240+#: qml/Greeter/NarrowView.qml:53 qml/Wizard/Pages/passwd-confirm.qml:53
242241msgid "Sorry, incorrect passphrase."
243242msgstr ""
244243
245−#: qml/Shell.qml:445
244+#: qml/Greeter/NarrowView.qml:54 qml/Wizard/Pages/passwd-confirm.qml:54
246245msgid "Sorry, incorrect passcode."
247246msgstr ""
248247
249−#: qml/Shell.qml:446
248+#: qml/Greeter/NarrowView.qml:55
250249msgid "This will be your last attempt."
251250msgstr ""
252251
253−#: qml/Shell.qml:448
252+#: qml/Greeter/NarrowView.qml:57
254253msgid ""
255254"If passphrase is entered incorrectly, your phone will conduct a factory "
256255"reset and all personal data will be deleted."
257256msgstr ""
258257
259−#: qml/Shell.qml:449
258+#: qml/Greeter/NarrowView.qml:58
260259msgid ""
261260"If passcode is entered incorrectly, your phone will conduct a factory reset "
262261"and all personal data will be deleted."
263262msgstr ""
264263
265−#: qml/Shell.qml:402
264+#: qml/Greeter/NarrowView.qml:115
266265#, qt-format
267266msgid "Enter %1"
268267msgstr ""
269268
270−#: qml/Shell.qml:394
269+#: qml/Greeter/NarrowView.qml:116 qml/Wizard/Pages/passwd-set.qml:60
271270msgid "Enter passphrase"
272271msgstr ""
273272
274−#: qml/Shell.qml:398
273+#: qml/Greeter/NarrowView.qml:117
275274msgid "Enter passcode"
276275msgstr ""
277276
278−#: qml/Shell.qml:403
277+#: qml/Greeter/NarrowView.qml:118
279278#, qt-format
280279msgid "Sorry, incorrect %1"
281280msgstr ""
282281
283−#: qml/Shell.qml:395
282+#: qml/Greeter/NarrowView.qml:119
284283msgid "Sorry, incorrect passphrase"
285284msgstr ""
286285
287−#: qml/Shell.qml:396
286+#: qml/Greeter/NarrowView.qml:120
288287msgid "Please re-enter"
289288msgstr ""
290289
291−#: qml/Shell.qml:399
290+#: qml/Greeter/NarrowView.qml:121
292291msgid "Sorry, incorrect passcode"
293292msgstr ""
294293
po/en_AU.po+38−39
@@ -15,35 +15,35 @@ msgstr ""
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: 2015-04-12 06:01+0000\n"
18+"X-Launchpad-Export-Date: 2015-04-14 05:33+0000\n"
1919"X-Generator: Launchpad (build 17423)\n"
2020
21−#: plugins/LightDM/Greeter.cpp:130
21+#: plugins/LightDM/Greeter.cpp:112
2222msgid "Password: "
2323msgstr "Password: "
2424
2525#: plugins/Unity/Launcher/launcheritem.cpp:45
26−#: plugins/Unity/Launcher/launcheritem.cpp:91
26+#: plugins/Unity/Launcher/launcheritem.cpp:100
2727msgid "Pin shortcut"
2828msgstr "Pin shortcut"
2929
30−#: plugins/Unity/Launcher/launcheritem.cpp:91
30+#: plugins/Unity/Launcher/launcheritem.cpp:100
3131msgid "Unpin shortcut"
3232msgstr "Unpin shortcut"
3333
34−#: qml/Components/DelayedLockscreen.qml:47
34+#: qml/Components/DelayedLockscreen.qml:49
3535msgid "Device Locked"
3636msgstr "Device Locked"
3737
38−#: qml/Components/DelayedLockscreen.qml:62
38+#: qml/Components/DelayedLockscreen.qml:64
3939msgid "You have been locked out due to too many failed passphrase attempts."
4040msgstr "You have been locked out due to too many failed passphrase attempts."
4141
42−#: qml/Components/DelayedLockscreen.qml:63
42+#: qml/Components/DelayedLockscreen.qml:65
4343msgid "You have been locked out due to too many failed passcode attempts."
4444msgstr "You have been locked out due to too many failed passcode attempts."
4545
46−#: qml/Components/DelayedLockscreen.qml:72
46+#: qml/Components/DelayedLockscreen.qml:74
4747#, qt-format
4848msgid "Please wait %1 minute and then try again…"
4949msgid_plural "Please wait %1 minutes and then try again…"
@@ -55,7 +55,7 @@ msgctxt "Title: Lock/Log out dialog"
5555msgid "Log out"
5656msgstr "Log out"
5757
58−#: qml/Components/Dialogs.qml:75
58+#: qml/Components/Dialogs.qml:68
5959msgid "Are you sure you want to log out?"
6060msgstr "Are you sure you want to log out?"
6161
@@ -69,6 +69,7 @@ msgctxt "Button: Log out from the system"
6969msgid "Log Out"
7070msgstr "Log Out"
7171
72+#: qml/Components/Dialogs.qml:84 qml/Components/Dialogs.qml:115
7273#: qml/Components/Dialogs.qml:171
7374msgid "Cancel"
7475msgstr "Cancel"
@@ -78,7 +79,7 @@ msgctxt "Title: Reboot/Shut down dialog"
7879msgid "Shut down"
7980msgstr "Shut down"
8081
81−#: qml/Components/Dialogs.qml:99
82+#: qml/Components/Dialogs.qml:97
8283msgid "Are you sure you want to shut down?"
8384msgstr "Are you sure you want to shut down?"
8485
@@ -97,17 +98,15 @@ msgctxt "Title: Reboot dialog"
9798msgid "Reboot"
9899msgstr "Reboot"
99100
100−#: qml/Components/Dialogs.qml:124
101+#: qml/Components/Dialogs.qml:128
101102msgid "Are you sure you want to reboot?"
102103msgstr "Are you sure you want to reboot?"
103104
104−#: qml/Components/Dialogs.qml:77 qml/Components/Dialogs.qml:101
105−#: qml/Components/Dialogs.qml:126
105+#: qml/Components/Dialogs.qml:130
106106msgid "No"
107107msgstr "No"
108108
109−#: qml/Components/Dialogs.qml:84 qml/Components/Dialogs.qml:108
110−#: qml/Components/Dialogs.qml:133
109+#: qml/Components/Dialogs.qml:136
111110msgid "Yes"
112111msgstr "Yes"
113112
@@ -116,7 +115,7 @@ msgctxt "Title: Power off/Restart dialog"
116115msgid "Power"
117116msgstr "Power"
118117
119−#: qml/Components/Dialogs.qml:149
118+#: qml/Components/Dialogs.qml:151
120119msgid ""
121120"Are you sure you would like\n"
122121"to power off?"
@@ -134,23 +133,23 @@ msgctxt "Button: Restart the system"
134133msgid "Restart"
135134msgstr "Restart"
136135
137−#: qml/Components/Lockscreen.qml:223
136+#: qml/Components/Lockscreen.qml:238
138137msgid "Return to Call"
139138msgstr "Return to Call"
140139
141−#: qml/Components/Lockscreen.qml:223
140+#: qml/Components/Lockscreen.qml:238
142141msgid "Emergency Call"
143142msgstr "Emergency Call"
144143
145−#: qml/Components/Lockscreen.qml:255
144+#: qml/Components/Lockscreen.qml:270
146145msgid "OK"
147146msgstr "OK"
148147
149−#: qml/Dash/GenericScopeView.qml:434 qml/Dash/GenericScopeView.qml:591
148+#: qml/Dash/GenericScopeView.qml:533 qml/Dash/GenericScopeView.qml:691
150149msgid "See less"
151150msgstr "See less"
152151
153−#: qml/Dash/GenericScopeView.qml:434
152+#: qml/Dash/GenericScopeView.qml:533
154153msgid "See all"
155154msgstr "See all"
156155
@@ -174,11 +173,11 @@ msgctxt "Button: Show the current dash scope settings"
174173msgid "Settings"
175174msgstr "Settings"
176175
177−#: qml/Dash/PageHeader.qml:285
176+#: qml/Dash/PageHeader.qml:293
178177msgid "Remove from Favorites"
179178msgstr "Remove from Favourites"
180179
181−#: qml/Dash/PageHeader.qml:285
180+#: qml/Dash/PageHeader.qml:293
182181msgid "Add to Favorites"
183182msgstr "Add to Favourites"
184183
@@ -214,19 +213,19 @@ msgstr "Release to refresh…"
214213msgid "Enable location data"
215214msgstr "Enable location data"
216215
217−#: qml/Dash/ScopesList.qml:63
216+#: qml/Dash/ScopesList.qml:66
218217msgid "Manage"
219218msgstr "Manage"
220219
221−#: qml/Dash/ScopesList.qml:107
220+#: qml/Dash/ScopesList.qml:112
222221msgid "Home"
223222msgstr "Home"
224223
225−#: qml/Dash/ScopesList.qml:108
224+#: qml/Dash/ScopesList.qml:113
226225msgid "Also installed"
227226msgstr "Also installed"
228227
229−#: qml/Greeter/Greeter.qml:174
228+#: qml/Greeter/CoverPage.qml:107
230229msgid "Unlock"
231230msgstr "Unlock"
232231
@@ -238,19 +237,19 @@ msgstr "Retry"
238237msgid "Tap to unlock"
239238msgstr "Tap to unlock"
240239
241−#: qml/Shell.qml:444
240+#: qml/Greeter/NarrowView.qml:53 qml/Wizard/Pages/passwd-confirm.qml:53
242241msgid "Sorry, incorrect passphrase."
243242msgstr "Sorry, incorrect passphrase."
244243
245−#: qml/Shell.qml:445
244+#: qml/Greeter/NarrowView.qml:54 qml/Wizard/Pages/passwd-confirm.qml:54
246245msgid "Sorry, incorrect passcode."
247246msgstr "Sorry, incorrect passcode."
248247
249−#: qml/Shell.qml:446
248+#: qml/Greeter/NarrowView.qml:55
250249msgid "This will be your last attempt."
251250msgstr "This will be your last attempt."
252251
253−#: qml/Shell.qml:448
252+#: qml/Greeter/NarrowView.qml:57
254253msgid ""
255254"If passphrase is entered incorrectly, your phone will conduct a factory "
256255"reset and all personal data will be deleted."
@@ -258,7 +257,7 @@ msgstr ""
258257"If passphrase is entered incorrectly, your phone will conduct a factory "
259258"reset and all personal data will be deleted."
260259
261−#: qml/Shell.qml:449
260+#: qml/Greeter/NarrowView.qml:58
262261msgid ""
263262"If passcode is entered incorrectly, your phone will conduct a factory reset "
264263"and all personal data will be deleted."
@@ -266,33 +265,33 @@ msgstr ""
266265"If passcode is entered incorrectly, your phone will conduct a factory reset "
267266"and all personal data will be deleted."
268267
269−#: qml/Shell.qml:402
268+#: qml/Greeter/NarrowView.qml:115
270269#, qt-format
271270msgid "Enter %1"
272271msgstr "Enter %1"
273272
274−#: qml/Shell.qml:394
273+#: qml/Greeter/NarrowView.qml:116 qml/Wizard/Pages/passwd-set.qml:60
275274msgid "Enter passphrase"
276275msgstr "Enter passphrase"
277276
278−#: qml/Shell.qml:398
277+#: qml/Greeter/NarrowView.qml:117
279278msgid "Enter passcode"
280279msgstr "Enter passcode"
281280
282−#: qml/Shell.qml:403
281+#: qml/Greeter/NarrowView.qml:118
283282#, qt-format
284283msgid "Sorry, incorrect %1"
285284msgstr "Sorry, incorrect %1"
286285
287−#: qml/Shell.qml:395
286+#: qml/Greeter/NarrowView.qml:119
288287msgid "Sorry, incorrect passphrase"
289288msgstr "Sorry, incorrect passphrase"
290289
291−#: qml/Shell.qml:396
290+#: qml/Greeter/NarrowView.qml:120
292291msgid "Please re-enter"
293292msgstr "Please re-enter"
294293
295−#: qml/Shell.qml:399
294+#: qml/Greeter/NarrowView.qml:121
296295msgid "Sorry, incorrect passcode"
297296msgstr "Sorry, incorrect passcode"
298297
po/fa.po+38−39
@@ -15,36 +15,36 @@ msgstr ""
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: 2015-04-11 05:50+0000\n"
18+"X-Launchpad-Export-Date: 2015-04-14 05:33+0000\n"
1919"X-Generator: Launchpad (build 17423)\n"
2020
21−#: plugins/LightDM/Greeter.cpp:130
21+#: plugins/LightDM/Greeter.cpp:112
2222msgid "Password: "
2323msgstr "گذرواژه: "
2424
2525#: plugins/Unity/Launcher/launcheritem.cpp:45
26−#: plugins/Unity/Launcher/launcheritem.cpp:91
26+#: plugins/Unity/Launcher/launcheritem.cpp:100
2727msgid "Pin shortcut"
2828msgstr "سنجاق کردن میانبر"
2929
30−#: plugins/Unity/Launcher/launcheritem.cpp:91
30+#: plugins/Unity/Launcher/launcheritem.cpp:100
3131msgid "Unpin shortcut"
3232msgstr "برداشتن سنجاق میانبر"
3333
34−#: qml/Components/DelayedLockscreen.qml:47
34+#: qml/Components/DelayedLockscreen.qml:49
3535msgid "Device Locked"
3636msgstr "دستگاه قفل شد"
3737
38−#: qml/Components/DelayedLockscreen.qml:62
38+#: qml/Components/DelayedLockscreen.qml:64
3939msgid "You have been locked out due to too many failed passphrase attempts."
4040msgstr ""
4141"شما به دلیل تلاش‌های بسیار زیاد شکست خورده برای عبارت‌عبور قفل شده‌اید."
4242
43−#: qml/Components/DelayedLockscreen.qml:63
43+#: qml/Components/DelayedLockscreen.qml:65
4444msgid "You have been locked out due to too many failed passcode attempts."
4545msgstr "شما به دلیل تلاش‌های بسیار زیاد شکست خورده برای رمزعبور قفل شده‌اید."
4646
47−#: qml/Components/DelayedLockscreen.qml:72
47+#: qml/Components/DelayedLockscreen.qml:74
4848#, qt-format
4949msgid "Please wait %1 minute and then try again…"
5050msgid_plural "Please wait %1 minutes and then try again…"
@@ -55,7 +55,7 @@ msgctxt "Title: Lock/Log out dialog"
5555msgid "Log out"
5656msgstr "خروج از حساب"
5757
58−#: qml/Components/Dialogs.qml:75
58+#: qml/Components/Dialogs.qml:68
5959msgid "Are you sure you want to log out?"
6060msgstr "مطمئنید که می‌خواهید از حساب خارج شوید"
6161
@@ -69,6 +69,7 @@ msgctxt "Button: Log out from the system"
6969msgid "Log Out"
7070msgstr "خروج"
7171
72+#: qml/Components/Dialogs.qml:84 qml/Components/Dialogs.qml:115
7273#: qml/Components/Dialogs.qml:171
7374msgid "Cancel"
7475msgstr "لغو"
@@ -78,7 +79,7 @@ msgctxt "Title: Reboot/Shut down dialog"
7879msgid "Shut down"
7980msgstr "خاموش کردن"
8081
81−#: qml/Components/Dialogs.qml:99
82+#: qml/Components/Dialogs.qml:97
8283msgid "Are you sure you want to shut down?"
8384msgstr "مطمئنید که می‌خواهید خاموش کنید؟"
8485
@@ -97,17 +98,15 @@ msgctxt "Title: Reboot dialog"
9798msgid "Reboot"
9899msgstr "راه‌اندازی دوباره"
99100
100−#: qml/Components/Dialogs.qml:124
101+#: qml/Components/Dialogs.qml:128
101102msgid "Are you sure you want to reboot?"
102103msgstr "مطمئنید که می‌خواهید مجدّداً راه‌اندازی کنسد؟"
103104
104−#: qml/Components/Dialogs.qml:77 qml/Components/Dialogs.qml:101
105−#: qml/Components/Dialogs.qml:126
105+#: qml/Components/Dialogs.qml:130
106106msgid "No"
107107msgstr "خیر"
108108
109−#: qml/Components/Dialogs.qml:84 qml/Components/Dialogs.qml:108
110−#: qml/Components/Dialogs.qml:133
109+#: qml/Components/Dialogs.qml:136
111110msgid "Yes"
112111msgstr "بله"
113112
@@ -116,7 +115,7 @@ msgctxt "Title: Power off/Restart dialog"
116115msgid "Power"
117116msgstr "انرژی"
118117
119−#: qml/Components/Dialogs.qml:149
118+#: qml/Components/Dialogs.qml:151
120119msgid ""
121120"Are you sure you would like\n"
122121"to power off?"
@@ -134,23 +133,23 @@ msgctxt "Button: Restart the system"
134133msgid "Restart"
135134msgstr "راه‌اندازی دوباره"
136135
137−#: qml/Components/Lockscreen.qml:223
136+#: qml/Components/Lockscreen.qml:238
138137msgid "Return to Call"
139138msgstr "بازگشت به تماس"
140139
141−#: qml/Components/Lockscreen.qml:223
140+#: qml/Components/Lockscreen.qml:238
142141msgid "Emergency Call"
143142msgstr "تماس اضطراری"
144143
145−#: qml/Components/Lockscreen.qml:255
144+#: qml/Components/Lockscreen.qml:270
146145msgid "OK"
147146msgstr "قبول"
148147
149−#: qml/Dash/GenericScopeView.qml:434 qml/Dash/GenericScopeView.qml:591
148+#: qml/Dash/GenericScopeView.qml:533 qml/Dash/GenericScopeView.qml:691
150149msgid "See less"
151150msgstr "کم‌تر ببینید"
152151
153−#: qml/Dash/GenericScopeView.qml:434
152+#: qml/Dash/GenericScopeView.qml:533
154153msgid "See all"
155154msgstr "دیدن همه"
156155
@@ -174,11 +173,11 @@ msgctxt "Button: Show the current dash scope settings"
174173msgid "Settings"
175174msgstr "تنظیمات"
176175
177−#: qml/Dash/PageHeader.qml:285
176+#: qml/Dash/PageHeader.qml:293
178177msgid "Remove from Favorites"
179178msgstr "برداشتن از برگزیده‌ها"
180179
181−#: qml/Dash/PageHeader.qml:285
180+#: qml/Dash/PageHeader.qml:293
182181msgid "Add to Favorites"
183182msgstr "افزودن به برگزیده‌ها"
184183
@@ -214,19 +213,19 @@ msgstr "برای تازه‌سازی رها کنید…"
214213msgid "Enable location data"
215214msgstr "فعّال کردن داده‌های موقعیّت"
216215
217−#: qml/Dash/ScopesList.qml:63
216+#: qml/Dash/ScopesList.qml:66
218217msgid "Manage"
219218msgstr "مدیریت"
220219
221−#: qml/Dash/ScopesList.qml:107
220+#: qml/Dash/ScopesList.qml:112
222221msgid "Home"
223222msgstr "خانه"
224223
225−#: qml/Dash/ScopesList.qml:108
224+#: qml/Dash/ScopesList.qml:113
226225msgid "Also installed"
227226msgstr "هم‌چنین نصب شده"
228227
229−#: qml/Greeter/Greeter.qml:174
228+#: qml/Greeter/CoverPage.qml:107
230229msgid "Unlock"
231230msgstr "بازکردن قفل"
232231
@@ -238,19 +237,19 @@ msgstr "تلاش دوباره"
238237msgid "Tap to unlock"
239238msgstr "برای باز کردن قفل ضربه بزنید"
240239
241−#: qml/Shell.qml:444
240+#: qml/Greeter/NarrowView.qml:53 qml/Wizard/Pages/passwd-confirm.qml:53
242241msgid "Sorry, incorrect passphrase."
243242msgstr "متأسّفیم، عبارت‌عبور نادرست است."
244243
245−#: qml/Shell.qml:445
244+#: qml/Greeter/NarrowView.qml:54 qml/Wizard/Pages/passwd-confirm.qml:54
246245msgid "Sorry, incorrect passcode."
247246msgstr "متأسّفیم، رمزعبور نادرست است."
248247
249−#: qml/Shell.qml:446
248+#: qml/Greeter/NarrowView.qml:55
250249msgid "This will be your last attempt."
251250msgstr "این آخرین تلاش شما خواهد بود."
252251
253−#: qml/Shell.qml:448
252+#: qml/Greeter/NarrowView.qml:57
254253msgid ""
255254"If passphrase is entered incorrectly, your phone will conduct a factory "
256255"reset and all personal data will be deleted."
@@ -258,7 +257,7 @@ msgstr ""
258257"اگر عبارت‌عبور نادرست وارد شود، تلفن شما بازنشانی کارخانه خواهد شد و تمامی "
259258"اطّلاعات شخصی حذف خواهند شد."
260259
261−#: qml/Shell.qml:449
260+#: qml/Greeter/NarrowView.qml:58
262261msgid ""
263262"If passcode is entered incorrectly, your phone will conduct a factory reset "
264263"and all personal data will be deleted."
@@ -266,33 +265,33 @@ msgstr ""
266265"اگر رمزعبور نادرست وارد شود، تلفن شما بازنشانی کارخانه خواهد شد و تمامی "
267266"اطّلاعات شخصی حذف خواهند شد."
268267
269−#: qml/Shell.qml:402
268+#: qml/Greeter/NarrowView.qml:115
270269#, qt-format
271270msgid "Enter %1"
272271msgstr "%1 را وارد کنید"
273272
274−#: qml/Shell.qml:394
273+#: qml/Greeter/NarrowView.qml:116 qml/Wizard/Pages/passwd-set.qml:60
275274msgid "Enter passphrase"
276275msgstr "عبارت‌عبور را وارد کنید"
277276
278−#: qml/Shell.qml:398
277+#: qml/Greeter/NarrowView.qml:117
279278msgid "Enter passcode"
280279msgstr "رمزعبور را وارد کنید"
281280
282−#: qml/Shell.qml:403
281+#: qml/Greeter/NarrowView.qml:118
283282#, qt-format
284283msgid "Sorry, incorrect %1"
285284msgstr "متأسّفیم، %1 نادرست بود"
286285
287−#: qml/Shell.qml:395
286+#: qml/Greeter/NarrowView.qml:119
288287msgid "Sorry, incorrect passphrase"
289288msgstr "متأسّفیم، عبارت‌عبور نادرست بود"
290289
291−#: qml/Shell.qml:396
290+#: qml/Greeter/NarrowView.qml:120
292291msgid "Please re-enter"
293292msgstr "لطفاً دوباره وارد کنید"
294293
295−#: qml/Shell.qml:399
294+#: qml/Greeter/NarrowView.qml:121
296295msgid "Sorry, incorrect passcode"
297296msgstr "متأسّفیم، رمزعبور نادرست بود"
298297
po/sk.po+38−39
@@ -15,35 +15,35 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=(n==1) ? 1 : (n>=2 && n<=4) ? 2 : 0;\n"
18−"X-Launchpad-Export-Date: 2015-04-11 05:50+0000\n"
18+"X-Launchpad-Export-Date: 2015-04-14 05:33+0000\n"
1919"X-Generator: Launchpad (build 17423)\n"
2020
21−#: plugins/LightDM/Greeter.cpp:130
21+#: plugins/LightDM/Greeter.cpp:112
2222msgid "Password: "
2323msgstr ""
2424
2525#: plugins/Unity/Launcher/launcheritem.cpp:45
26−#: plugins/Unity/Launcher/launcheritem.cpp:91
26+#: plugins/Unity/Launcher/launcheritem.cpp:100
2727msgid "Pin shortcut"
2828msgstr ""
2929
30−#: plugins/Unity/Launcher/launcheritem.cpp:91
30+#: plugins/Unity/Launcher/launcheritem.cpp:100
3131msgid "Unpin shortcut"
3232msgstr ""
3333
34−#: qml/Components/DelayedLockscreen.qml:47
34+#: qml/Components/DelayedLockscreen.qml:49
3535msgid "Device Locked"
3636msgstr ""
3737
38−#: qml/Components/DelayedLockscreen.qml:62
38+#: qml/Components/DelayedLockscreen.qml:64
3939msgid "You have been locked out due to too many failed passphrase attempts."
4040msgstr ""
4141
42−#: qml/Components/DelayedLockscreen.qml:63
42+#: qml/Components/DelayedLockscreen.qml:65
4343msgid "You have been locked out due to too many failed passcode attempts."
4444msgstr ""
4545
46−#: qml/Components/DelayedLockscreen.qml:72
46+#: qml/Components/DelayedLockscreen.qml:74
4747#, qt-format
4848msgid "Please wait %1 minute and then try again…"
4949msgid_plural "Please wait %1 minutes and then try again…"
@@ -55,7 +55,7 @@ msgctxt "Title: Lock/Log out dialog"
5555msgid "Log out"
5656msgstr ""
5757
58−#: qml/Components/Dialogs.qml:75
58+#: qml/Components/Dialogs.qml:68
5959msgid "Are you sure you want to log out?"
6060msgstr ""
6161
@@ -69,6 +69,7 @@ msgctxt "Button: Log out from the system"
6969msgid "Log Out"
7070msgstr ""
7171
72+#: qml/Components/Dialogs.qml:84 qml/Components/Dialogs.qml:115
7273#: qml/Components/Dialogs.qml:171
7374msgid "Cancel"
7475msgstr ""
@@ -78,7 +79,7 @@ msgctxt "Title: Reboot/Shut down dialog"
7879msgid "Shut down"
7980msgstr ""
8081
81−#: qml/Components/Dialogs.qml:99
82+#: qml/Components/Dialogs.qml:97
8283msgid "Are you sure you want to shut down?"
8384msgstr ""
8485
@@ -97,17 +98,15 @@ msgctxt "Title: Reboot dialog"
9798msgid "Reboot"
9899msgstr ""
99100
100−#: qml/Components/Dialogs.qml:124
101+#: qml/Components/Dialogs.qml:128
101102msgid "Are you sure you want to reboot?"
102103msgstr ""
103104
104−#: qml/Components/Dialogs.qml:77 qml/Components/Dialogs.qml:101
105−#: qml/Components/Dialogs.qml:126
105+#: qml/Components/Dialogs.qml:130
106106msgid "No"
107107msgstr ""
108108
109−#: qml/Components/Dialogs.qml:84 qml/Components/Dialogs.qml:108
110−#: qml/Components/Dialogs.qml:133
109+#: qml/Components/Dialogs.qml:136
111110msgid "Yes"
112111msgstr ""
113112
@@ -116,7 +115,7 @@ msgctxt "Title: Power off/Restart dialog"
116115msgid "Power"
117116msgstr ""
118117
119−#: qml/Components/Dialogs.qml:149
118+#: qml/Components/Dialogs.qml:151
120119msgid ""
121120"Are you sure you would like\n"
122121"to power off?"
@@ -132,23 +131,23 @@ msgctxt "Button: Restart the system"
132131msgid "Restart"
133132msgstr ""
134133
135−#: qml/Components/Lockscreen.qml:223
134+#: qml/Components/Lockscreen.qml:238
136135msgid "Return to Call"
137136msgstr ""
138137
139−#: qml/Components/Lockscreen.qml:223
138+#: qml/Components/Lockscreen.qml:238
140139msgid "Emergency Call"
141140msgstr ""
142141
143−#: qml/Components/Lockscreen.qml:255
142+#: qml/Components/Lockscreen.qml:270
144143msgid "OK"
145144msgstr ""
146145
147−#: qml/Dash/GenericScopeView.qml:434 qml/Dash/GenericScopeView.qml:591
146+#: qml/Dash/GenericScopeView.qml:533 qml/Dash/GenericScopeView.qml:691
148147msgid "See less"
149148msgstr ""
150149
151−#: qml/Dash/GenericScopeView.qml:434
150+#: qml/Dash/GenericScopeView.qml:533
152151msgid "See all"
153152msgstr ""
154153
@@ -172,11 +171,11 @@ msgctxt "Button: Show the current dash scope settings"
172171msgid "Settings"
173172msgstr ""
174173
175−#: qml/Dash/PageHeader.qml:285
174+#: qml/Dash/PageHeader.qml:293
176175msgid "Remove from Favorites"
177176msgstr ""
178177
179−#: qml/Dash/PageHeader.qml:285
178+#: qml/Dash/PageHeader.qml:293
180179msgid "Add to Favorites"
181180msgstr ""
182181
@@ -212,19 +211,19 @@ msgstr ""
212211msgid "Enable location data"
213212msgstr ""
214213
215−#: qml/Dash/ScopesList.qml:63
214+#: qml/Dash/ScopesList.qml:66
216215msgid "Manage"
217216msgstr ""
218217
219−#: qml/Dash/ScopesList.qml:107
218+#: qml/Dash/ScopesList.qml:112
220219msgid "Home"
221220msgstr ""
222221
223−#: qml/Dash/ScopesList.qml:108
222+#: qml/Dash/ScopesList.qml:113
224223msgid "Also installed"
225224msgstr ""
226225
227−#: qml/Greeter/Greeter.qml:174
226+#: qml/Greeter/CoverPage.qml:107
228227msgid "Unlock"
229228msgstr ""
230229
@@ -236,57 +235,57 @@ msgstr ""
236235msgid "Tap to unlock"
237236msgstr ""
238237
239−#: qml/Shell.qml:444
238+#: qml/Greeter/NarrowView.qml:53 qml/Wizard/Pages/passwd-confirm.qml:53
240239msgid "Sorry, incorrect passphrase."
241240msgstr ""
242241
243−#: qml/Shell.qml:445
242+#: qml/Greeter/NarrowView.qml:54 qml/Wizard/Pages/passwd-confirm.qml:54
244243msgid "Sorry, incorrect passcode."
245244msgstr ""
246245
247−#: qml/Shell.qml:446
246+#: qml/Greeter/NarrowView.qml:55
248247msgid "This will be your last attempt."
249248msgstr ""
250249
251−#: qml/Shell.qml:448
250+#: qml/Greeter/NarrowView.qml:57
252251msgid ""
253252"If passphrase is entered incorrectly, your phone will conduct a factory "
254253"reset and all personal data will be deleted."
255254msgstr ""
256255
257−#: qml/Shell.qml:449
256+#: qml/Greeter/NarrowView.qml:58
258257msgid ""
259258"If passcode is entered incorrectly, your phone will conduct a factory reset "
260259"and all personal data will be deleted."
261260msgstr ""
262261
263−#: qml/Shell.qml:402
262+#: qml/Greeter/NarrowView.qml:115
264263#, qt-format
265264msgid "Enter %1"
266265msgstr ""
267266
268−#: qml/Shell.qml:394
267+#: qml/Greeter/NarrowView.qml:116 qml/Wizard/Pages/passwd-set.qml:60
269268msgid "Enter passphrase"
270269msgstr ""
271270
272−#: qml/Shell.qml:398
271+#: qml/Greeter/NarrowView.qml:117
273272msgid "Enter passcode"
274273msgstr ""
275274
276−#: qml/Shell.qml:403
275+#: qml/Greeter/NarrowView.qml:118
277276#, qt-format
278277msgid "Sorry, incorrect %1"
279278msgstr ""
280279
281−#: qml/Shell.qml:395
280+#: qml/Greeter/NarrowView.qml:119
282281msgid "Sorry, incorrect passphrase"
283282msgstr ""
284283
285−#: qml/Shell.qml:396
284+#: qml/Greeter/NarrowView.qml:120
286285msgid "Please re-enter"
287286msgstr ""
288287
289−#: qml/Shell.qml:399
288+#: qml/Greeter/NarrowView.qml:121
290289msgid "Sorry, incorrect passcode"
291290msgstr ""
292291
po/sr.po+33−32
@@ -9,16 +9,16 @@ msgstr ""
99"Project-Id-Version: unity\n"
1010"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1111"POT-Creation-Date: 2015-03-19 16:03+0100\n"
12−"PO-Revision-Date: 2015-03-04 22:25+0000\n"
13−"Last-Translator: Саша Петровић <salepetronije@gmail.com>\n"
12+"PO-Revision-Date: 2015-04-13 15:19+0000\n"
13+"Last-Translator: Данило Шеган <Unknown>\n"
1414"Language-Team: српски <xfce4@xfce4.org>\n"
1515"MIME-Version: 1.0\n"
1616"Content-Type: text/plain; charset=UTF-8\n"
1717"Content-Transfer-Encoding: 8bit\n"
1818"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
1919"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
20−"X-Launchpad-Export-Date: 2015-03-25 06:05+0000\n"
21−"X-Generator: Launchpad (build 17413)\n"
20+"X-Launchpad-Export-Date: 2015-04-14 05:33+0000\n"
21+"X-Generator: Launchpad (build 17423)\n"
2222"Language: sr\n"
2323
2424#: plugins/LightDM/Greeter.cpp:112
@@ -57,7 +57,7 @@ msgstr[2] "Молим, сачекајте %1 минута, па покушајт
5757#: qml/Components/Dialogs.qml:67
5858msgctxt "Title: Lock/Log out dialog"
5959msgid "Log out"
60−msgstr ""
60+msgstr "Одјави се"
6161
6262#: qml/Components/Dialogs.qml:68
6363msgid "Are you sure you want to log out?"
@@ -66,12 +66,12 @@ msgstr "Сигурно желите да се одјавите?"
6666#: qml/Components/Dialogs.qml:70
6767msgctxt "Button: Lock the system"
6868msgid "Lock"
69−msgstr ""
69+msgstr "Закључај"
7070
7171#: qml/Components/Dialogs.qml:77
7272msgctxt "Button: Log out from the system"
7373msgid "Log Out"
74−msgstr ""
74+msgstr "Одјави се"
7575
7676#: qml/Components/Dialogs.qml:84 qml/Components/Dialogs.qml:115
7777#: qml/Components/Dialogs.qml:171
@@ -81,7 +81,7 @@ msgstr "Откажи"
8181#: qml/Components/Dialogs.qml:96
8282msgctxt "Title: Reboot/Shut down dialog"
8383msgid "Shut down"
84−msgstr ""
84+msgstr "Угаси"
8585
8686#: qml/Components/Dialogs.qml:97
8787msgid "Are you sure you want to shut down?"
@@ -90,17 +90,17 @@ msgstr "Сигурно желите да угасите?"
9090#: qml/Components/Dialogs.qml:99
9191msgctxt "Button: Reboot the system"
9292msgid "Reboot"
93−msgstr ""
93+msgstr "Ресетуј"
9494
9595#: qml/Components/Dialogs.qml:107
9696msgctxt "Button: Shut down the system"
9797msgid "Shut down"
98−msgstr ""
98+msgstr "Угаси"
9999
100100#: qml/Components/Dialogs.qml:127
101101msgctxt "Title: Reboot dialog"
102102msgid "Reboot"
103−msgstr ""
103+msgstr "Ресетуј"
104104
105105#: qml/Components/Dialogs.qml:128
106106msgid "Are you sure you want to reboot?"
@@ -117,7 +117,7 @@ msgstr "Да"
117117#: qml/Components/Dialogs.qml:150
118118msgctxt "Title: Power off/Restart dialog"
119119msgid "Power"
120−msgstr ""
120+msgstr "Напајање"
121121
122122#: qml/Components/Dialogs.qml:151
123123msgid ""
@@ -130,12 +130,12 @@ msgstr ""
130130#: qml/Components/Dialogs.qml:153
131131msgctxt "Button: Power off the system"
132132msgid "Power off"
133−msgstr ""
133+msgstr "Искључи"
134134
135135#: qml/Components/Dialogs.qml:162
136136msgctxt "Button: Restart the system"
137137msgid "Restart"
138−msgstr ""
138+msgstr "Покрени поново"
139139
140140#: qml/Components/Lockscreen.qml:238
141141msgid "Return to Call"
@@ -160,22 +160,22 @@ msgstr "Опширније"
160160#: qml/Dash/GenericScopeView.qml:595
161161msgctxt "Label: Hint for dash search line edit"
162162msgid "Search"
163−msgstr ""
163+msgstr "Претрага"
164164
165165#: qml/Dash/PageHeader.qml:269
166166msgctxt "Button: Open the Ubuntu Store"
167167msgid "Store"
168−msgstr ""
168+msgstr "Продавница"
169169
170170#: qml/Dash/PageHeader.qml:276
171171msgctxt "Button: Start a search in the current dash scope"
172172msgid "Search"
173−msgstr ""
173+msgstr "Тражи"
174174
175175#: qml/Dash/PageHeader.qml:286
176176msgctxt "Button: Show the current dash scope settings"
177177msgid "Settings"
178−msgstr ""
178+msgstr "Подешавања"
179179
180180#: qml/Dash/PageHeader.qml:293
181181msgid "Remove from Favorites"
@@ -235,11 +235,11 @@ msgstr "Откључај"
235235
236236#: qml/Greeter/LoginList.qml:236
237237msgid "Retry"
238−msgstr ""
238+msgstr "Покушај поново"
239239
240240#: qml/Greeter/LoginList.qml:237
241241msgid "Tap to unlock"
242−msgstr ""
242+msgstr "Додирните да откључате"
243243
244244#: qml/Greeter/NarrowView.qml:53 qml/Wizard/Pages/passwd-confirm.qml:53
245245msgid "Sorry, incorrect passphrase."
@@ -342,7 +342,7 @@ msgstr "Неуспешно, тапните да покушате поново"
342342#: qml/Panel/Indicators/MessageMenuItemFactory.qml:149
343343msgctxt "Label: Hint in message indicator line edit"
344344msgid "Reply"
345−msgstr ""
345+msgstr "Одговор"
346346
347347#: qml/Panel/Indicators/ModemInfoItem.qml:105
348348msgid "Unlock SIM"
@@ -354,7 +354,7 @@ msgstr "Роминг"
354354
355355#: qml/Tutorial/TutorialBottomFinish.qml:24
356356msgid "This action does different things for different apps"
357−msgstr ""
357+msgstr "Ова радња ради различите ствари за различите програме"
358358
359359#: qml/Tutorial/TutorialBottomFinish.qml:25
360360msgid "Tap here to finish."
@@ -366,7 +366,7 @@ msgstr "Отвори нарочите изборнике"
366366
367367#: qml/Tutorial/TutorialBottom.qml:29
368368msgid "Swipe up from the bottom edge."
369−msgstr ""
369+msgstr "Превуците од доње ивице навише."
370370
371371#: qml/Tutorial/TutorialLeftFinish.qml:24
372372msgid "These are the shortcuts to favorite apps"
@@ -407,7 +407,7 @@ msgstr "Прегледајте покренуте задатке."
407407#: qml/Wizard/Page.qml:89
408408msgctxt "Button: Go back one page in the Wizard"
409409msgid "Back"
410−msgstr ""
410+msgstr "Назад"
411411
412412#: qml/Wizard/Pages/10-welcome.qml:27
413413msgid "Hi!"
@@ -415,7 +415,7 @@ msgstr "Здраво!"
415415
416416#: qml/Wizard/Pages/10-welcome.qml:44
417417msgid "Welcome to your Ubuntu phone."
418−msgstr ""
418+msgstr "Добродошли у свој Убунту телефон."
419419
420420#: qml/Wizard/Pages/10-welcome.qml:52
421421msgid "Let’s get started."
@@ -451,32 +451,32 @@ msgstr "Молим, изаберите како бисте желели да о
451451#: qml/Wizard/Pages/30-passwd-type.qml:97
452452msgctxt "Label: Type of security method"
453453msgid "Swipe"
454−msgstr ""
454+msgstr "Превлачење"
455455
456456#: qml/Wizard/Pages/30-passwd-type.qml:98
457457msgctxt "Label: Description of security method"
458458msgid "No security"
459−msgstr ""
459+msgstr "Без заштите"
460460
461461#: qml/Wizard/Pages/30-passwd-type.qml:100
462462msgctxt "Label: Type of security method"
463463msgid "Passcode"
464−msgstr ""
464+msgstr "Код"
465465
466466#: qml/Wizard/Pages/30-passwd-type.qml:101
467467msgctxt "Label: Description of security method"
468468msgid "4 digits only"
469−msgstr ""
469+msgstr "Само 4 цифре"
470470
471471#: qml/Wizard/Pages/30-passwd-type.qml:103
472472msgctxt "Label: Type of security method"
473473msgid "Passphrase"
474−msgstr ""
474+msgstr "Лозинка"
475475
476476#: qml/Wizard/Pages/30-passwd-type.qml:104
477477msgctxt "Label: Description of security method"
478478msgid "Numbers and letters"
479−msgstr ""
479+msgstr "Бројеви и слова"
480480
481481#: qml/Wizard/Pages/40-wifi.qml:29
482482msgid "Connect to Wi‑Fi"
@@ -505,6 +505,7 @@ msgstr "Користећи само ГПС (мања тачност)"
505505#: qml/Wizard/Pages/50-location.qml:86
506506msgid "Using GPS, anonymized Wi-Fi and cellular network info (recommended)"
507507msgstr ""
508+"Помоћу GPS-a, заштићених података о бежичним и мобилним мрежама (препоручено)"
508509
509510#. TRANSLATORS: HERE is a trademark for Nokia's location service, you probably shouldn't translate it
510511#: qml/Wizard/Pages/50-location.qml:103
@@ -582,7 +583,7 @@ msgstr "Изаберите своју шифру"
582583
583584#: qml/Wizard/Pages/passwd-set.qml:68
584585msgid "Passphrase must be 4 characters long"
585−msgstr ""
586+msgstr "Лозинка мора имати бар 4 знака"
586587
587588#: qml/Wizard/StackButton.qml:39
588589#, qt-format
qml/Components/Dialogs.qml+2
@@ -51,11 +51,13 @@ Item {
5151 if (!dialogLoader.active) {
5252 dialogLoader.sourceComponent = powerDialogComponent;
5353 dialogLoader.active = true;
54+ dialogLoader.item.forceActiveFocus();
5455 }
5556 }
5657 }
5758 Loader {
5859 id: dialogLoader
60+ objectName: "dialogLoader"
5961 anchors.fill: parent
6062 active: false
6163 }
qml/Dash/Dash.qml+27−14
@@ -28,29 +28,42 @@ Showable {
2828
2929 visible: shown
3030
31+ Connections {
32+ target: UriHandler
33+ onOpened: {
34+ backToDashContent()
35+ dashContent.currentScope.performQuery(uris[0])
36+ }
37+ }
38+
3139 DashCommunicatorService {
3240 objectName: "dashCommunicatorService"
3341 onSetCurrentScopeRequested: {
3442 if (!isSwipe || !window.active || bottomEdgeController.progress != 0 || scopeItem.scope || dashContent.subPageShown) {
3543 if (bottomEdgeController.progress != 0 && window.active) animate = false;
3644 dashContent.setCurrentScopeAtIndex(index, animate, isSwipe)
37− // Close dash overview and nested temp scopes in it
38− if (bottomEdgeController.progress != 0) {
39− bottomEdgeController.enableAnimation = window.active;
40− bottomEdgeController.progress = 0;
41− }
42− // Close normal temp scopes (e.g. App Store)
43− if (scopeItem.scope) {
44− scopeItem.backClicked();
45− }
46− // Close previews
47− if (dashContent.subPageShown) {
48− dashContent.closePreview();
49− }
45+ backToDashContent()
5046 }
5147 }
5248 }
5349
50+ function backToDashContent()
51+ {
52+ // Close dash overview and nested temp scopes in it
53+ if (bottomEdgeController.progress != 0) {
54+ bottomEdgeController.enableAnimation = window.active;
55+ bottomEdgeController.progress = 0;
56+ }
57+ // Close normal temp scopes (e.g. App Store)
58+ if (scopeItem.scope) {
59+ scopeItem.backClicked();
60+ }
61+ // Close previews
62+ if (dashContent.subPageShown) {
63+ dashContent.closePreview();
64+ }
65+ }
66+
5467 function setCurrentScope(scopeId, animate, reset) {
5568 var scopeIndex = -1;
5669 for (var i = 0; i < scopes.count; ++i) {
@@ -178,7 +191,7 @@ Showable {
178191 Binding {
179192 target: scopesList.scope
180193 property: "isActive"
181− value: bottomEdgeController.progress === 1
194+ value: bottomEdgeController.progress === 1 && (Qt.application.state == Qt.ApplicationActive)
182195 }
183196
184197 Connections {
qml/Dash/DashContent.qml−5
@@ -63,11 +63,6 @@ Item {
6363 }
6464 }
6565
66− Connections {
67− target: UriHandler
68− onOpened: dashContentList.currentItem.theScope.performQuery(uris[0])
69− }
70−
7166 function setCurrentScopeAtIndex(index, animate, reset) {
7267 // if the scopes haven't loaded yet, then wait until they are.
7368 if (!scopes.loaded) {
qml/Dash/GenericScopeView.qml+1−2
@@ -19,7 +19,6 @@ import Ubuntu.Components 1.1
1919import Utils 0.1
2020import Unity 0.2
2121import Dash 0.1
22−import Powerd 0.1
2322import "../Components"
2423import "../Components/ListItems" as ListItems
2524
@@ -105,7 +104,7 @@ FocusScope {
105104 Binding {
106105 target: scope
107106 property: "isActive"
108− value: isCurrent && !subPageLoader.open && (Powerd.status === Powerd.On)
107+ value: isCurrent && !subPageLoader.open && (Qt.application.state == Qt.ApplicationActive)
109108 }
110109
111110 UnitySortFilterProxyModel {
qml/Panel/Indicators/MenuItemFactory.qml+48−52
@@ -19,6 +19,7 @@
1919
2020import QtQuick 2.0
2121import Ubuntu.Settings.Menus 0.1 as Menus
22+import Ubuntu.Settings.Components 0.1
2223import QMenuModel 0.1
2324import Utils 0.1 as Utils
2425import Ubuntu.Components.ListItems 0.1 as ListItems
@@ -84,6 +85,7 @@ Item {
8485 id: sliderMenu;
8586
8687 Menus.SliderMenu {
88+ id: sliderItem
8789 objectName: "sliderMenu"
8890 property QtObject menuData: null
8991 property var menuModel: menuFactory.menuModel
@@ -113,15 +115,6 @@ Item {
113115 onMenuIndexChanged: {
114116 loadAttributes();
115117 }
116− onServerValueChanged: {
117− // value can be changed by slider, so a binding won't work.
118− if (serverValue !== undefined) {
119− value = serverValue;
120− }
121− }
122− onUpdated: {
123− menuModel.changeState(menuIndex, value);
124− }
125118
126119 function loadAttributes() {
127120 if (!menuModel || menuIndex == -1) return;
@@ -130,6 +123,20 @@ Item {
130123 'min-icon': 'icon',
131124 'max-icon': 'icon'});
132125 }
126+
127+ ServerPropertySynchroniser {
128+ objectName: "sync"
129+ syncTimeout: Utils.Constants.indicatorValueTimeout
130+ bufferedSyncTimeout: true
131+ maximumWaitBufferInterval: 16
132+
133+ serverTarget: sliderItem
134+ serverProperty: "serverValue"
135+ userTarget: sliderItem
136+ userProperty: "value"
137+
138+ onSyncTriggered: menuModel.changeState(menuIndex, value)
139+ }
133140 }
134141 }
135142
@@ -280,6 +287,7 @@ Item {
280287 id: checkableMenu;
281288
282289 Menus.CheckableMenu {
290+ id: checkItem
283291 objectName: "checkableMenu"
284292 property QtObject menuData: null
285293 property int menuIndex: -1
@@ -290,26 +298,16 @@ Item {
290298 checked: serverChecked
291299 highlightWhenPressed: false
292300
293− onServerCheckedChanged: updateFromServer()
294− onTriggered: {
295− menuModel.activate(menuIndex);
296− resyncTimer.restart();
297− }
301+ ServerPropertySynchroniser {
302+ objectName: "sync"
303+ syncTimeout: Utils.Constants.indicatorValueTimeout
298304
299− // value can be changed by menu, so a binding won't work.
300− function updateFromServer() {
301− resyncTimer.stop();
302− if (checked != serverChecked) {
303− checked = serverChecked;
304− }
305− }
305+ serverTarget: checkItem
306+ serverProperty: "serverChecked"
307+ userTarget: checkItem
308+ userProperty: "checked"
306309
307− // Server value is not guaranteed to change to what we expect from an activation.
308− // In this case, we need to re-assert that we are presenting the UI with the set backend value.
309− Timer {
310− id: resyncTimer
311− interval: 1500
312− onTriggered: updateFromServer()
310+ onSyncTriggered: menuModel.activate(checkItem.menuIndex)
313311 }
314312 }
315313 }
@@ -318,6 +316,7 @@ Item {
318316 id: switchMenu;
319317
320318 Menus.SwitchMenu {
319+ id: switchItem
321320 objectName: "switchMenu"
322321 property QtObject menuData: null
323322 property int menuIndex: -1
@@ -329,26 +328,16 @@ Item {
329328 checked: serverChecked
330329 highlightWhenPressed: false
331330
332− onServerCheckedChanged: updateFromServer()
333− onTriggered: {
334− menuModel.activate(menuIndex);
335− resyncTimer.restart();
336− }
331+ ServerPropertySynchroniser {
332+ objectName: "sync"
333+ syncTimeout: Utils.Constants.indicatorValueTimeout
337334
338− // value can be changed by menu, so a binding won't work.
339− function updateFromServer() {
340− resyncTimer.stop();
341− if (checked != serverChecked) {
342− checked = serverChecked;
343− }
344− }
335+ serverTarget: switchItem
336+ serverProperty: "serverChecked"
337+ userTarget: switchItem
338+ userProperty: "checked"
345339
346− // Server value is not guaranteed to change to what we expect from an activation.
347− // In this case, we need to re-assert that we are presenting the UI with the set backend value.
348− Timer {
349− id: resyncTimer
350− interval: 1500
351− onTriggered: updateFromServer()
340+ onSyncTriggered: menuModel.activate(switchItem.menuIndex);
352341 }
353342 }
354343 }
@@ -464,6 +453,7 @@ Item {
464453 id: accessPoint;
465454
466455 Menus.AccessPointMenu {
456+ id: apItem
467457 objectName: "accessPoint"
468458 property QtObject menuData: null
469459 property var menuModel: menuFactory.menuModel
@@ -485,19 +475,12 @@ Item {
485475 signalStrength: strengthAction.valid ? strengthAction.state : 0
486476 highlightWhenPressed: false
487477
488− onServerCheckedChanged: {
489− // value can be changed by menu, so a binding won't work.
490− active = serverChecked;
491− }
492478 onMenuModelChanged: {
493479 loadAttributes();
494480 }
495481 onMenuIndexChanged: {
496482 loadAttributes();
497483 }
498− onTriggered: {
499− menuModel.activate(menuIndex);
500− }
501484
502485 function loadAttributes() {
503486 if (!menuModel || menuIndex == -1) return;
@@ -505,6 +488,19 @@ Item {
505488 'x-canonical-wifi-ap-is-secure': 'bool',
506489 'x-canonical-wifi-ap-strength-action': 'string'});
507490 }
491+
492+ ServerPropertySynchroniser {
493+ objectName: "sync"
494+ syncTimeout: Utils.Constants.indicatorValueTimeout
495+
496+ serverTarget: apItem
497+ serverProperty: "serverChecked"
498+ userTarget: apItem
499+ userProperty: "active"
500+ userTrigger: "onTriggered"
501+
502+ onSyncTriggered: menuModel.activate(apItem.menuIndex)
503+ }
508504 }
509505 }
510506
qml/Panel/Indicators/client/IndicatorsList.qml+2−2
@@ -31,8 +31,8 @@ Page {
3131
3232 Indicators.IndicatorsModel {
3333 id: indicatorsModel
34−
35− Component.onCompleted: load(profile)
34+ profile: page.profile
35+ Component.onCompleted: load()
3636 }
3737
3838 ListView {
qml/Panel/IndicatorsMenu.qml+5−1
@@ -88,6 +88,7 @@ Showable {
8888
8989 Handle {
9090 id: handle
91+ objectName: "handle"
9192 anchors {
9293 left: parent.left
9394 right: parent.right
@@ -163,7 +164,10 @@ Showable {
163164 }
164165
165166 MouseArea {
166− anchors.fill: __showDragHandle
167+ anchors.bottom: parent.bottom
168+ anchors.left: parent.left
169+ anchors.right: parent.right
170+ height: minimizedPanelHeight
167171 enabled: __showDragHandle.enabled
168172 onClicked: {
169173 bar.selectItemAt(mouseX)
qml/Panel/Panel.qml+1
@@ -187,6 +187,7 @@ Item {
187187
188188 QtObject {
189189 id: d
190+ objectName: "panelPriv"
190191 readonly property real indicatorHeight: indicators.minimizedPanelHeight + indicatorOrangeLine.height
191192 }
192193
qml/Shell.qml+28−18
@@ -79,6 +79,9 @@ Item {
7979 }
8080 }
8181
82+ // This is _only_ used to expose the property to autopilot tests
83+ readonly property string testShellMode: shellMode
84+
8285 function activateApplication(appId) {
8386 if (ApplicationManager.findApplication(appId)) {
8487 ApplicationManager.requestFocusApplication(appId);
@@ -181,7 +184,6 @@ Item {
181184 objectName: "stages"
182185 width: parent.width
183186 height: parent.height
184− visible: !ApplicationManager.empty
185187
186188 Connections {
187189 target: ApplicationManager
@@ -282,6 +284,31 @@ Item {
282284 value: shell.background
283285 }
284286 }
287+
288+ Tutorial {
289+ id: tutorial
290+ objectName: "tutorial"
291+ anchors.fill: parent
292+ active: AccountsService.demoEdges
293+ paused: LightDM.Greeter.active
294+ launcher: launcher
295+ panel: panel
296+ edgeSize: shell.edgeSize
297+
298+ // EdgeDragAreas don't work with mice. So to avoid trapping the user,
299+ // we'll tell the tutorial to avoid using them on the Desktop. The
300+ // Desktop doesn't use the same spread design anyway. The tutorial is
301+ // all a bit of a placeholder on non-phone form factors right now.
302+ // When the design team gives us more guidance, we can do something
303+ // more clever here.
304+ // TODO: use DeviceConfiguration instead of checking source
305+ useEdgeDragArea: applicationsDisplayLoader.source != Qt.resolvedUrl("Stages/DesktopStage.qml")
306+
307+ onFinished: {
308+ AccountsService.demoEdges = false;
309+ active = false; // for immediate response / if AS is having problems
310+ }
311+ }
285312 }
286313
287314 InputMethod {
@@ -579,23 +606,6 @@ Item {
579606 }
580607 }
581608
582− Tutorial {
583− id: tutorial
584− objectName: "tutorial"
585− active: AccountsService.demoEdges
586− paused: LightDM.Greeter.active
587− launcher: launcher
588− panel: panel
589− stages: stages
590− overlay: overlay
591− edgeSize: shell.edgeSize
592−
593− onFinished: {
594− AccountsService.demoEdges = false;
595− active = false; // for immediate response / if AS is having problems
596− }
597− }
598−
599609 Connections {
600610 target: SessionBroadcast
601611 onShowHome: showHome()
qml/Stages/SurfaceContainer.qml+12−9
@@ -1,5 +1,5 @@
11/*
2− * Copyright 2014 Canonical Ltd.
2+ * Copyright 2014-2015 Canonical Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU Lesser General Public License as published by
@@ -17,6 +17,7 @@
1717import QtQuick 2.0
1818import Ubuntu.Components 1.1
1919import Ubuntu.Gestures 0.1 // For TouchGate
20+import Utils 0.1 // for InputWatcher
2021
2122FocusScope {
2223 id: root
@@ -26,8 +27,6 @@ FocusScope {
2627 property int orientation
2728 property bool interactive
2829
29− signal surfacePressed()
30−
3130 onSurfaceChanged: {
3231 if (surface) {
3332 // Set the surface focus *after* it is added to the scene to
@@ -45,17 +44,21 @@ FocusScope {
4544 Binding { target: surface; property: "enabled"; value: root.interactive; when: surface }
4645 Binding { target: surface; property: "antialiasing"; value: !root.interactive; when: surface }
4746
47+ InputWatcher {
48+ target: root.surface
49+ onTargetPressedChanged: {
50+ if (targetPressed && root.interactive) {
51+ root.focus = true;
52+ root.forceActiveFocus();
53+ }
54+ }
55+ }
56+
4857 TouchGate {
4958 targetItem: surface
5059 anchors.fill: root
5160 enabled: root.surface ? root.surface.enabled : false
5261 z: 2
53− onPressed: {
54− root.focus = true;
55− if (root.interactive) {
56− root.forceActiveFocus();
57− }
58− }
5962 }
6063
6164 states: [
qml/Tutorial/Tutorial.qml+7−14
@@ -23,11 +23,10 @@ Item {
2323 property alias active: loader.active
2424 property bool paused
2525 property real edgeSize
26+ property bool useEdgeDragArea
2627
2728 property Item launcher
2829 property Item panel
29− property Item stages
30− property Item overlay
3130
3231 readonly property bool launcherEnabled: loader.item ? loader.item.launcherEnabled : true
3332 readonly property bool spreadEnabled: loader.item ? loader.item.spreadEnabled : true
@@ -62,26 +61,20 @@ Item {
6261
6362 Binding {
6463 target: loader.item
65− property: "launcher"
66− value: root.launcher
67− }
68−
69− Binding {
70− target: loader.item
71− property: "panel"
72− value: root.panel
64+ property: "useEdgeDragArea"
65+ value: root.useEdgeDragArea
7366 }
7467
7568 Binding {
7669 target: loader.item
77− property: "stages"
78− value: root.stages
70+ property: "launcher"
71+ value: root.launcher
7972 }
8073
8174 Binding {
8275 target: loader.item
83− property: "overlay"
84− value: root.overlay
76+ property: "panel"
77+ value: root.panel
8578 }
8679
8780 Connections {
qml/Tutorial/TutorialContent.qml+9−8
@@ -22,8 +22,6 @@ Item {
2222
2323 property Item launcher
2424 property Item panel
25− property Item stages
26− property Item overlay
2725
2826 readonly property bool launcherEnabled: !running ||
2927 (!paused && tutorialLeft.shown)
@@ -34,6 +32,7 @@ Item {
3432
3533 property bool paused: false
3634 property real edgeSize
35+ property bool useEdgeDragArea
3736
3837 signal finished()
3938
@@ -66,7 +65,6 @@ Item {
6665 TutorialLeft {
6766 id: tutorialLeft
6867 objectName: "tutorialLeft"
69− parent: root.stages
7068 anchors.fill: parent
7169 launcher: root.launcher
7270 paused: !shown || root.paused
@@ -77,21 +75,26 @@ Item {
7775 TutorialLeftFinish {
7876 id: tutorialLeftFinish
7977 objectName: "tutorialLeftFinish"
80− parent: root.stages
8178 anchors.fill: parent
8279 textXOffset: root.launcher.panelWidth
8380 paused: !shown || root.paused
81+ text: root.useEdgeDragArea ? i18n.tr("Tap here to continue.") : i18n.tr("Click here to finish.")
8482
8583 onFinished: {
8684 root.launcher.hide();
87− tutorialRight.show();
85+ if (root.useEdgeDragArea) {
86+ tutorialRight.show();
87+ } else {
88+ // Last two screens use EdgeDragArea (right edge spread and
89+ // bottom edge). So just end tutorial here.
90+ root.finish();
91+ }
8892 }
8993 }
9094
9195 TutorialRight {
9296 id: tutorialRight
9397 objectName: "tutorialRight"
94− parent: root.stages
9598 anchors.fill: parent
9699 edgeSize: root.edgeSize
97100 panel: root.panel
@@ -103,7 +106,6 @@ Item {
103106 TutorialBottom {
104107 id: tutorialBottom
105108 objectName: "tutorialBottom"
106− parent: root.stages
107109 anchors.fill: parent
108110 edgeSize: root.edgeSize
109111 paused: !shown || root.paused
@@ -114,7 +116,6 @@ Item {
114116 TutorialBottomFinish {
115117 id: tutorialBottomFinish
116118 objectName: "tutorialBottomFinish"
117− parent: root.stages
118119 anchors.fill: parent
119120 backgroundFadesOut: true
120121 paused: !shown || root.paused
run.sh+1−1
@@ -65,6 +65,6 @@ else
6565 echo "Unity8 is already running, please stop it first"
6666 exit 1
6767 fi
68− /sbin/initctl start unity8 BINARY="`readlink -f $QML_PHONE_SHELL_PATH` $QML_PHONE_SHELL_ARGS $@" QML2_IMPORT_PATH=$QML2_IMPORT_PATH LD_LIBRARY_PATH=$LD_LIBRARY_PATH
68+ /sbin/initctl start unity8 BINARY="`readlink -f $QML_PHONE_SHELL_PATH` $QML_PHONE_SHELL_ARGS $@" XDG_DATA_DIRS=$XDG_DATA_DIRS QML2_IMPORT_PATH=$QML2_IMPORT_PATH LD_LIBRARY_PATH=$LD_LIBRARY_PATH
6969 tailf -n 0 ~/.cache/upstart/unity8.log
7070fi
src/Panel/Indicators/client/CMakeLists.txt−2
@@ -1,5 +1,4 @@
11project(indicators_client)
2−set(INDICATORS_CLIENT_APP indicators-client)
32
43set(INDICATORS_CLIENT_SRC
54 main.cpp
@@ -15,7 +14,6 @@ add_executable(${INDICATORS_CLIENT_APP}
1514)
1615
1716qt5_use_modules(${INDICATORS_CLIENT_APP} Core Widgets Quick)
18−set_target_properties(${INDICATORS_CLIENT_APP} PROPERTIES COMPILE_FLAGS -fPIC)
1917
2018install(TARGETS ${INDICATORS_CLIENT_APP}
2119 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
src/main.cpp+26
@@ -70,6 +70,11 @@ int main(int argc, const char *argv[])
7070Load the testability driver");
7171 parser.addOption(testabilityOption);
7272
73+ QCommandLineOption modeOption("mode",
74+ "Whether to run greeter and/or shell [full-greeter, full-shell, greeter, shell]",
75+ "mode", "full-greeter");
76+ parser.addOption(modeOption);
77+
7378 application = new QGuiApplication(argc, (char**)argv);
7479
7580 // Treat args with single dashes the same as arguments with two dashes
@@ -90,6 +95,26 @@ Load the testability driver");
9095 qmlArgs.setSize(geom.at(0).toInt(), geom.at(1).toInt());
9196 }
9297
98+ // If an invalid option was specified, set it to the default
99+ // If no default was provided in the QCommandLineOption constructor, abort.
100+ QString shellMode;
101+ if(!parser.isSet(modeOption) ||
102+ (parser.value(modeOption) != "full-greeter" &&
103+ parser.value(modeOption) != "full-shell" &&
104+ parser.value(modeOption) != "greeter" &&
105+ parser.value(modeOption) != "shell"))
106+ {
107+ if (modeOption.defaultValues().first() != nullptr) {
108+ shellMode = modeOption.defaultValues().first();
109+ qWarning() << "Mode argument was not provided or was set to an illegal value. Using default value of --mode=" << shellMode;
110+ } else {
111+ qFatal("Shell mode argument was not provided and there is no default mode,");
112+ }
113+
114+ } else {
115+ shellMode = parser.value(modeOption);
116+ }
117+
93118 // The testability driver is only loaded by QApplication but not by QGuiApplication.
94119 // However, QApplication depends on QWidget which would add some unneeded overhead => Let's load the testability driver on our own.
95120 if (parser.isSet(testabilityOption) || getenv("QT_LOAD_TESTABILITY")) {
@@ -117,6 +142,7 @@ Load the testability driver");
117142 view->engine()->setBaseUrl(QUrl::fromLocalFile(::qmlDirectory()));
118143 view->rootContext()->setContextProperty("applicationArguments", &qmlArgs);
119144 view->rootContext()->setContextProperty("indicatorProfile", indicatorProfile);
145+ view->rootContext()->setContextProperty("shellMode", shellMode);
120146 if (parser.isSet(framelessOption)) {
121147 view->setFlags(Qt::FramelessWindowHint);
122148 }
tests/autopilot/unity8/application_lifecycle/tests/test_application_lifecycle.py+2−4
@@ -91,10 +91,9 @@ class ApplicationLifecycleTests(tests.ApplicationLifeCycleTestCase):
9191 def test_greeter_hides_on_app_open(self):
9292 """Greeter should hide when an app is opened"""
9393 process_helpers.lock_unity()
94− greeter = self.main_window.get_greeter()
95− self.assertThat(greeter.created, Eventually(Equals(True)))
9694
9795 application_name = self.launch_fake_app()
96+ greeter = self.main_window.get_greeter()
9897 greeter.wait_swiped_away()
9998 process_helpers.unlock_unity()
10099 self.assert_current_focused_application(application_name)
@@ -108,10 +107,9 @@ class ApplicationLifecycleTests(tests.ApplicationLifeCycleTestCase):
108107 self.assert_current_focused_application('unity8-dash')
109108
110109 process_helpers.lock_unity()
111− greeter = self.main_window.get_greeter()
112− self.assertThat(greeter.created, Eventually(Equals(True)))
113110
114111 self.launch_upstart_application(application_name)
112+ greeter = self.main_window.get_greeter()
115113 greeter.wait_swiped_away()
116114 process_helpers.unlock_unity()
117115 self.assert_current_focused_application(application_name)
tests/autopilot/unity8/fixture_setup.py+46−1
@@ -19,12 +19,17 @@
1919
2020import fixtures
2121import subprocess
22+import logging
2223
2324from autopilot import introspection
2425
25−from unity8 import process_helpers
26+from unity8 import (
27+ get_binary_path,
28+ process_helpers
29+)
2630from unity8.shell import emulators
2731
32+logger = logging.getLogger(__name__)
2833
2934class LaunchDashApp(fixtures.Fixture):
3035
@@ -96,3 +101,43 @@ class DisplayRotationLock(fixtures.Fixture):
96101 'rotation-lock', value_string
97102 ]
98103 subprocess.check_output(command)
104+
105+class LaunchMockIndicatorService(fixtures.Fixture):
106+
107+ """Fixture to launch the indicator test service."""
108+
109+ def __init__(self, action_delay, ensure_not_running=True):
110+ """Initialize an instance.
111+
112+ :param action_delay: The delay to use when activating actions.
113+ Measured in milliseconds. Value of -1 will result in infinite delay.
114+ :type action_delay: An integer.
115+ :param boolean ensure_not_running: Make sure service is not running
116+
117+ """
118+ super(LaunchMockIndicatorService, self).__init__()
119+ self.action_delay = action_delay
120+ self.ensure_not_running = ensure_not_running
121+
122+ def setUp(self):
123+ super(LaunchMockIndicatorService, self).setUp()
124+ if self.ensure_not_running:
125+ self.ensure_service_not_running()
126+ self.addCleanup(self.stop_service)
127+ self.application_proxy = self.launch_service()
128+
129+ def launch_service(self):
130+ logger.info("Starting unity-mock-indicator-service")
131+ binary_path = get_binary_path('unity-mock-indicator-service')
132+ binary_arg = 'BINARY={}'.format(binary_path)
133+ env_args = 'ARGS=-t {}'.format(self.action_delay)
134+ all_args = [binary_arg, env_args]
135+ process_helpers.start_job('unity-mock-indicator-service', *all_args)
136+
137+ def stop_service(self):
138+ logger.info("Stopping unity-mock-indicator-service")
139+ process_helpers.stop_job('unity-mock-indicator-service')
140+
141+ def ensure_service_not_running(self):
142+ if process_helpers.is_job_running('unity-mock-indicator-service'):
143+ self.stop_service()
tests/autopilot/unity8/greeter/__init__.pynew file

No changes to the content.

tests/autopilot/unity8/greeter/tests/__init__.pynew file+26
@@ -0,0 +1,26 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2015 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 unity8.shell.emulators import main_window as main_window_emulator
21+from unity8.shell.tests import UnityTestCase
22+
23+class GreeterTestCase(UnityTestCase):
24+ def get_shell(self, unity_proxy):
25+ main_window = unity_proxy.select_single(main_window_emulator.QQuickView)
26+ return main_window.select_single('Shell')
tests/autopilot/unity8/greeter/tests/test_args.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) 2015 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 unity8.greeter.tests import GreeterTestCase
21+
22+class GreeterArgsTest(GreeterTestCase):
23+
24+ DEFAULT_SHELL_MODE = 'full-greeter'
25+ NONEXISTENT_MODE = 'non-existent-mode'
26+
27+ def test_full_greeter_mode(self):
28+ unity_proxy = self.launch_unity(mode='full-greeter')
29+ shell = self.get_shell(unity_proxy)
30+ self.assertTrue(shell.testShellMode == 'full-greeter')
31+
32+ def test_full_shell_mode(self):
33+ unity_proxy = self.launch_unity(mode='full-shell')
34+ shell = self.get_shell(unity_proxy)
35+ self.assertTrue(shell.testShellMode == 'full-shell')
36+
37+ def test_greeter_mode(self):
38+ unity_proxy = self.launch_unity(mode='greeter')
39+ shell = self.get_shell(unity_proxy)
40+ self.assertTrue(shell.testShellMode == 'greeter')
41+
42+ def test_nonexistent_mode(self):
43+ unity_proxy = self.launch_unity(mode=self.NONEXISTENT_MODE)
44+ shell = self.get_shell(unity_proxy)
45+ self.assertTrue(shell.testShellMode == self.DEFAULT_SHELL_MODE,
46+ "Shell mode was {} but should have been {}".format(
47+ shell.testShellMode, self.DEFAULT_SHELL_MODE))
48+
49+ def test_shell_mode(self):
50+ unity_proxy = self.launch_unity(mode='shell')
51+ shell = self.get_shell(unity_proxy)
52+ self.assertTrue(shell.testShellMode == 'shell')
tests/autopilot/unity8/indicators/__init__.py+89−10
@@ -19,6 +19,7 @@ import ubuntuuitoolkit
1919from autopilot import introspection
2020
2121from unity8.shell import emulators
22+from unity8 import fixture_setup
2223
2324
2425class IndicatorPage(emulators.UnityEmulatorBase):
@@ -33,26 +34,25 @@ class IndicatorPage(emulators.UnityEmulatorBase):
3334 def validate_dbus_object(cls, path, state):
3435 return False
3536
37+class Indicator():
3638
37−class DisplayIndicator():
38−
39− def __init__(self, main_window):
39+ def __init__(self, main_window, name):
4040 self._main_window = main_window
41+ self._name = name
4142
4243 def is_indicator_icon_visible(self):
4344 panel_item = self._main_window.wait_select_single(
44− objectName='indicator-rotation-lock-panelItem')
45+ objectName=self._name+'-panelItem')
4546 return panel_item.indicatorVisible
4647
4748 def open(self):
48− """Open the display indicator page.
49+ """Open the indicator page.
4950
50− :return: The custom proxy object for the display indicator page.
51+ :return: The custom proxy object for the indicator page.
5152
5253 """
5354 if self.is_indicator_icon_visible():
54− return self._main_window.open_indicator_page(
55− 'indicator-rotation-lock')
55+ return self._main_window.open_indicator_page(self._name)
5656 else:
5757 return self._open_indicator_with_icon_not_visible()
5858
@@ -61,10 +61,10 @@ class DisplayIndicator():
6161 self._main_window.open_indicator_page('indicator-datetime')
6262 self._make_indicator_icon_visible()
6363 indicator_rotation_icon = self._main_window.select_single(
64− objectName='indicator-rotation-lock-panelItem')
64+ objectName=self._name+'-panelItem')
6565 self._main_window.pointing_device.click_object(indicator_rotation_icon)
6666 return self._main_window.wait_select_single(
67− objectName='indicator-rotation-lock-page')
67+ objectName=self._name+'-page')
6868
6969 def _make_indicator_icon_visible(self):
7070 indicators_bar_flickable = self._main_window.select_single(
@@ -95,6 +95,13 @@ class DisplayIndicator():
9595 self._main_window.close_indicator_page()
9696
9797
98+class DisplayIndicator(Indicator):
99+
100+ def __init__(self, main_window):
101+ super(DisplayIndicator, self).__init__(main_window, 'indicator-rotation-lock')
102+ self._main_window = main_window
103+
104+
98105class DisplayIndicatorPage(IndicatorPage):
99106
100107 """Autopilot helper for the display indicator page."""
@@ -122,3 +129,75 @@ class DisplayIndicatorPage(IndicatorPage):
122129 switcher = self._get_switcher()
123130 switcher.uncheck()
124131 switcher.checked.wait_for(False)
132+
133+
134+class TestIndicator(Indicator):
135+
136+ def __init__(self, main_window):
137+ super(TestIndicator, self).__init__(main_window, 'indicator-mock')
138+ self._main_window = main_window
139+
140+
141+class TestIndicatorPage(IndicatorPage):
142+
143+ """Autopilot helper for the mock indicator page."""
144+
145+ @classmethod
146+ def validate_dbus_object(cls, path, state):
147+ name = introspection.get_classname_from_path(path)
148+ if name == b'IndicatorPage':
149+ if state['objectName'][1] == 'indicator-mock-page':
150+ return True
151+ return False
152+
153+ def get_switcher(self):
154+ return self.select_single(
155+ ubuntuuitoolkit.CheckBox, objectName='switcher')
156+
157+ def get_switch_menu(self):
158+ return self.select_single(
159+ 'SwitchMenu', objectName='indicator.action.switch')
160+
161+ def get_slider(self):
162+ return self.select_single(objectName='slider')
163+
164+ def get_slider_menu(self):
165+ return self.select_single(objectName='indicator.action.slider')
166+
167+
168+class Slider(emulators.UnityEmulatorBase):
169+
170+ """Autopilot helper for the Slider component."""
171+
172+ # XXX Because of https://bugs.launchpad.net/autopilot-qt/+bug/1341671
173+ # we need to make sure it does not match in any selection.
174+ # --elopio - 2015-01-20
175+
176+ @classmethod
177+ def validate_dbus_object(cls, path, state):
178+ name = introspection.get_classname_from_path(path)
179+ if name == b'Slider':
180+ return True
181+ return False
182+
183+ def slide_left(self, timeout=10):
184+ x, y, width, height = self.globalRect
185+
186+ rate = 5
187+ start_x = x + width/2
188+ start_y = stop_y = y + height/2
189+ stop_x = x
190+
191+ self.pointing_device.drag(start_x, start_y, stop_x, stop_y, rate)
192+ self.value.wait_for(self.minimumValue, timeout);
193+
194+ def slide_right(self, timeout=10):
195+ x, y, width, height = self.globalRect
196+
197+ rate = 5
198+ start_x = x + width/2
199+ start_y = stop_y = y + height/2
200+ stop_x = x + width
201+
202+ self.pointing_device.drag(start_x, start_y, stop_x, stop_y, rate)
203+ self.value.wait_for(self.maximumValue, timeout);
tests/autopilot/unity8/indicators/tests/__init__.py+7
@@ -26,6 +26,13 @@ class IndicatorTestCase(tests.UnityTestCase):
2626
2727 device_emulation_scenarios = tests._get_device_emulation_scenarios()
2828
29+ def setUp(self):
30+ super().setUp()
31+ self.unity_proxy = self.launch_unity()
32+ process_helpers.unlock_unity(self.unity_proxy)
33+
34+class DeviceIndicatorTestCase(IndicatorTestCase):
35+
2936 def setUp(self):
3037 if platform.model() == 'Desktop':
3138 self.skipTest('Test cannot be run on the desktop.')
tests/autopilot/unity8/indicators/tests/test_action_latency.pynew file+232
@@ -0,0 +1,232 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Indicators Autopilot Test Suite
4+# Copyright (C) 2015 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+from testscenarios import multiply_scenarios
20+
21+from unity8 import (
22+ fixture_setup,
23+ indicators,
24+ process_helpers
25+)
26+from unity8.shell import tests
27+from unity8.indicators import tests
28+
29+from autopilot.matchers import Eventually
30+from testtools.matchers import Equals, NotEquals
31+import time
32+
33+
34+class TestIndicatorBaseTestCase(tests.IndicatorTestCase):
35+
36+ scenarios = [ tests.IndicatorTestCase.device_emulation_scenarios[0] ]
37+
38+ def setUp(self):
39+ super(TestIndicatorBaseTestCase, self).setUp()
40+
41+ self.launch_indicator_service()
42+
43+ # wait for the indicator to appear in unity
44+ self.indicator = indicators.TestIndicator(self.main_window)
45+ self.assertThat(
46+ self.indicator.is_indicator_icon_visible(),
47+ Eventually(Equals(True), timeout=20)
48+ )
49+ self.indicator_page = self.indicator.open()
50+
51+ def launch_indicator_service(self):
52+ launch_service_fixture = fixture_setup.LaunchMockIndicatorService(self.action_delay)
53+ self.useFixture(launch_service_fixture)
54+
55+
56+class TestServerValueUpdate(TestIndicatorBaseTestCase):
57+
58+ """Test that an action causes the server to update"""
59+
60+ time_scenarios = [
61+ ('Low', {'action_delay': 0}),
62+ ('Medium', {'action_delay': 2500}),
63+ ('High', {'action_delay': 8000}),
64+ ]
65+ scenarios = multiply_scenarios(
66+ time_scenarios,
67+ TestIndicatorBaseTestCase.scenarios
68+ )
69+
70+ def test_switch_reaches_server_value(self):
71+ switch = self.indicator_page.get_switcher()
72+ switch_menu = self.indicator_page.get_switch_menu()
73+
74+ switch.change_state()
75+
76+ self.assertThat(
77+ switch_menu.serverChecked,
78+ Eventually(Equals(switch.checked), timeout=20)
79+ )
80+
81+ def test_slider_reaches_server_value(self):
82+ slider = self.indicator_page.get_slider()
83+ slider_menu = self.indicator_page.get_slider_menu()
84+
85+ old_value = slider.value
86+ slider.slide_left()
87+
88+ self.assertThat(
89+ slider_menu.serverValue,
90+ Eventually(NotEquals(old_value), timeout=20)
91+ )
92+
93+ self.assertThat(
94+ slider_menu.serverValue,
95+ Eventually(Equals(slider.value), timeout=20)
96+ )
97+
98+class TestBuffering(TestIndicatorBaseTestCase):
99+
100+ """Test that switching multiple times will buffer activations
101+
102+ See https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1390136 .
103+ """
104+ action_delay = 2500
105+
106+ def test_switch_buffers_actvations(self):
107+
108+ switch = self.indicator_page.get_switcher()
109+ switch.change_state()
110+ intermediate_value = switch.checked;
111+
112+ # will buffer change until it receives the change from server
113+ switch.change_state()
114+ final_value = switch.checked;
115+
116+ # backend will respond to first switch.
117+ switch_menu = self.indicator_page.get_switch_menu()
118+ self.assertThat(
119+ switch_menu.serverChecked,
120+ Eventually(Equals(intermediate_value), timeout=20)
121+ )
122+ # The buffered activation should have gone to server now.
123+
124+ # front-end should not change as a result of server update while it is buffered
125+ self.assertThat(
126+ switch.checked,
127+ Equals(final_value)
128+ )
129+
130+ # server will respond to the second activate
131+ self.assertThat(
132+ switch_menu.serverChecked,
133+ Eventually(Equals(final_value), timeout=20)
134+ )
135+
136+ # make sure we've got the server value set.
137+ self.assertThat(
138+ switch.checked,
139+ Equals(switch_menu.serverChecked)
140+ )
141+
142+ def test_slider_buffers_activations(self):
143+
144+ slider = self.indicator_page.get_slider()
145+ original_value = slider.value;
146+ slider.slide_left()
147+
148+ # will buffer change until it receives the change from server
149+ slider.slide_right()
150+ final_value = slider.value;
151+
152+ # backend will respond to first slider. Since it's a live slider it'll probably
153+ # be a random value along the slide.
154+ slider_menu = self.indicator_page.get_slider_menu()
155+ self.assertThat(
156+ slider_menu.serverValue,
157+ Eventually(NotEquals(original_value), timeout=20)
158+ )
159+ # It wont yet have reached the final value due to the buffering
160+ # Second activate should have gone out by now
161+ self.assertThat(
162+ slider_menu.serverValue,
163+ NotEquals(final_value)
164+ )
165+
166+ # front-end should not change as a result of server update while it is buffered
167+ self.assertThat(
168+ slider.value,
169+ Equals(final_value)
170+ )
171+
172+ # server will respond to the second activate
173+ self.assertThat(
174+ slider_menu.serverValue,
175+ Eventually(Equals(final_value), timeout=20)
176+ )
177+
178+ # make sure we've got the server value set.
179+ self.assertThat(
180+ slider.value,
181+ Equals(slider_menu.serverValue)
182+ )
183+
184+
185+class TestClientRevertsToServerValue(TestIndicatorBaseTestCase):
186+
187+ """Test that an action which does not respond in time will revert
188+ to original value if not actioned in time.
189+
190+ See https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1390136 .
191+ """
192+ action_delay = -1 # never action.
193+
194+ def test_switch_reverts_on_late_response(self):
195+
196+ switch = self.indicator_page.get_switcher()
197+ switch_menu = self.indicator_page.get_switch_menu()
198+
199+ original_value = switch.checked;
200+ switch.change_state()
201+
202+ # switch should revert to original value after 5 seconds (30 seconds in real usage)
203+ self.assertThat(
204+ switch.checked,
205+ Eventually(Equals(original_value), timeout=20)
206+ )
207+
208+ # make sure we've got the server value set.
209+ self.assertThat(
210+ switch.checked,
211+ Equals(switch_menu.serverChecked)
212+ )
213+
214+ def test_slider_reverts_on_late_response(self):
215+
216+ slider = self.indicator_page.get_slider()
217+ slider_menu = self.indicator_page.get_slider_menu()
218+
219+ original_value = slider.value;
220+ slider.slide_left()
221+
222+ # slider should revert to original value after 5 seconds (30 seconds in real usage)
223+ self.assertThat(
224+ slider.value,
225+ Eventually(Equals(original_value), timeout=20)
226+ )
227+
228+ # make sure we've got the server value set.
229+ self.assertThat(
230+ slider.value,
231+ Equals(slider_menu.serverValue)
232+ )
tests/autopilot/unity8/indicators/tests/test_display_indicator.py+3−1
@@ -23,7 +23,9 @@ from unity8 import (
2323from unity8.indicators import tests
2424
2525
26−class DisplayIndicatorTestCase(tests.IndicatorTestCase):
26+class DisplayIndicatorTestCase(tests.DeviceIndicatorTestCase):
27+
28+ scenarios = tests.IndicatorTestCase.device_emulation_scenarios
2729
2830 def test_indicator_icon_must_be_visible_after_rotation_locked(self):
2931 rotation_unlocked = fixture_setup.DisplayRotationLock(False)
tests/autopilot/unity8/indicators/tests/test_indicators.py+2−2
@@ -23,7 +23,7 @@ from autopilot import platform
2323from unity8.indicators import tests
2424
2525
26−class IndicatorExistsTestCase(tests.IndicatorTestCase):
26+class IndicatorExistsTestCase(tests.DeviceIndicatorTestCase):
2727
2828 indicator_scenarios = [
2929 ('Bluetooth', dict(indicator_name='indicator-bluetooth')),
@@ -51,7 +51,7 @@ class IndicatorExistsTestCase(tests.IndicatorTestCase):
5151 )
5252
5353
54−class IndicatorPageTitleMatchesWidgetTestCase(tests.IndicatorTestCase):
54+class IndicatorPageTitleMatchesWidgetTestCase(tests.DeviceIndicatorTestCase):
5555
5656 indicator_scenarios = [
5757 ('Bluetooth', dict(indicator_name='indicator-bluetooth',
tests/autopilot/unity8/process_helpers.py+47−14
@@ -89,20 +89,53 @@ def unlock_unity(unity_proxy_obj=None):
8989
9090
9191def lock_unity(unity_proxy_obj=None):
92− """Helper function that attempts to lock the unity greeter."""
93− import evdev
94− import time
95− uinput = evdev.UInput(name='unity8-autopilot-power-button',
96− devnode='/dev/autopilot-uinput')
97− # One press and release to turn screen off (locking unity)
98− uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_POWER, 1)
99− uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_POWER, 0)
100− uinput.syn()
101− time.sleep(1)
102− # And another press and release to turn screen back on
103− uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_POWER, 1)
104− uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_POWER, 0)
105− uinput.syn()
92+ """Helper function that attempts to lock unity greeter.
93+
94+ If unity_proxy_object is None create a proxy object by querying for the
95+ running unity process.
96+ Otherwise re-use the passed proxy object.
97+
98+ :raises RuntimeError: if the greeter attempts and fails to be locked.
99+
100+ :raises RuntimeWarning: when the greeter is found because it is
101+ already locked.
102+ :raises CannotAccessUnity: if unity is not introspectable or cannot be
103+ found on dbus.
104+ :raises CannotAccessUnity: if unity's upstart status is not "start" or the
105+ upstart job cannot be found at all.
106+
107+ """
108+ if unity_proxy_obj is None:
109+ try:
110+ pid = _get_unity_pid()
111+ unity = _get_unity_proxy_object(pid)
112+ main_window = unity.select_single(main_window_emulator.QQuickView)
113+ except ProcessSearchError as e:
114+ raise CannotAccessUnity(
115+ "Cannot introspect unity, make sure that it has been started "
116+ "with testability. Perhaps use the function "
117+ "'restart_unity_with_testability' this module provides."
118+ "(%s)"
119+ % str(e)
120+ )
121+ else:
122+ main_window = unity_proxy_obj.select_single(
123+ main_window_emulator.QQuickView)
124+
125+ greeter = main_window.get_greeter()
126+ if greeter.created is True:
127+ raise RuntimeWarning("Greeter appears to be already locked.")
128+
129+ bus = dbus.SessionBus()
130+ dbus_proxy = bus.get_object("com.canonical.UnityGreeter", "/")
131+ try:
132+ dbus_proxy.ShowGreeter()
133+ except dbus.DBusException:
134+ logger.info("Failed to lock greeter")
135+ raise
136+ else:
137+ greeter.created.wait_for(True)
138+ logger.info("Greeter locked, continuing.")
106139
107140
108141def restart_unity_with_testability(*args):
tests/autopilot/unity8/shell/tests/__init__.py+13−4
@@ -65,7 +65,6 @@ UNITYSHELL_GSETTINGS_PATH = "/org/compiz/profiles/unity/plugins/unityshell/"
6565UNITYSHELL_LAUNCHER_KEY = "launcher-hide-mode"
6666UNITYSHELL_LAUNCHER_MODE = 1 # launcher hidden
6767
68−
6968def _get_device_emulation_scenarios(devices='All'):
7069 nexus4 = ('Desktop Nexus 4',
7170 dict(app_width=768, app_height=1280, grid_unit_px=18))
@@ -253,8 +252,14 @@ class UnityTestCase(AutopilotTestCase):
253252 "%s=%s" % (key, value)
254253 ], stderr=subprocess.STDOUT)
255254
256− def launch_unity(self, **kwargs):
257− """Launch the unity shell, return a proxy object for it."""
255+ def launch_unity(self, mode="full-greeter", *args):
256+ """
257+ Launch the unity shell, return a proxy object for it.
258+
259+ :param str mode: The type of greeter/shell mode to use
260+ :param args: A list of aguments to pass to unity8
261+
262+ """
258263 binary_path = get_binary_path()
259264 lib_path = get_lib_path()
260265
@@ -289,9 +294,13 @@ class UnityTestCase(AutopilotTestCase):
289294 except OSError:
290295 pass
291296
297+ unity8_cli_args_list = ["--mode={}".format(mode)]
298+ if len(args) != 0:
299+ unity8_cli_args_list += args
300+
292301 app_proxy = self._launch_unity_with_upstart(
293302 binary_path,
294− self.unity_geometry_args,
303+ self.unity_geometry_args + unity8_cli_args_list
295304 )
296305
297306 self._set_proxy(app_proxy)
tests/autopilot/unity8/shell/tests/test_lock_screen.py+1−1
@@ -135,7 +135,7 @@ class TestLockscreen(UnityTestCase):
135135 :raises: TypeError if passphrase is not a string.
136136
137137 """
138− if not isinstance(passphrase, basestring):
138+ if not isinstance(passphrase, str):
139139 raise TypeError(
140140 "'passphrase' parameter must be a string, not %r."
141141 % type(passphrase)
tests/mocks/CMakeLists.txt+1
@@ -30,6 +30,7 @@ endmacro()
3030
3131add_subdirectory(AccountsService)
3232add_subdirectory(GSettings.1.0)
33+add_subdirectory(indicator-service)
3334add_subdirectory(libusermetrics)
3435add_subdirectory(LightDM)
3536add_subdirectory(Lights)
tests/mocks/GSettings.1.0/fake_gsettings.cpp+47−50
@@ -17,11 +17,12 @@
1717#include "fake_gsettings.h"
1818
1919#include <QList>
20−#include <QDebug>
2120
2221GSettingsControllerQml* GSettingsControllerQml::s_controllerInstance = 0;
2322
24−GSettingsControllerQml::GSettingsControllerQml() {
23+GSettingsControllerQml::GSettingsControllerQml()
24+ : m_usageMode("Staged")
25+{
2526}
2627
2728GSettingsControllerQml::~GSettingsControllerQml() {
@@ -35,50 +36,32 @@ GSettingsControllerQml* GSettingsControllerQml::instance() {
3536 return s_controllerInstance;
3637}
3738
38−void GSettingsControllerQml::registerSettingsObject(GSettingsQml *obj) {
39− m_registeredGSettings.append(obj);
40−}
41−
42−void GSettingsControllerQml::unRegisterSettingsObject(GSettingsQml *obj) {
43− m_registeredGSettings.removeOne(obj);
39+QString GSettingsControllerQml::pictureUri() const
40+{
41+ return m_pictureUri;
4442}
4543
46−void GSettingsControllerQml::setPictureUri(const QByteArray &schemaId, const QString &str)
44+void GSettingsControllerQml::setPictureUri(const QString &str)
4745{
48− if (m_pictureUri[schemaId] != str) {
49− m_pictureUri[schemaId] = str;
50−
51− Q_FOREACH (GSettingsQml *obj, m_registeredGSettings) {
52− if (obj->schema()->id() == schemaId) {
53− Q_EMIT obj->pictureUriChanged(str);
54− }
55− }
46+ if (str != m_pictureUri) {
47+ m_pictureUri = str;
48+ Q_EMIT pictureUriChanged(m_pictureUri);
5649 }
5750}
5851
59−QString GSettingsControllerQml::pictureUri(const QByteArray &schemaId) const
52+QString GSettingsControllerQml::usageMode() const
6053{
61− return m_pictureUri.value(schemaId, "");
54+ return m_usageMode;
6255}
6356
64−void GSettingsControllerQml::setUsageMode(const QByteArray &schemaId, const QString &str)
57+void GSettingsControllerQml::setUsageMode(const QString &usageMode)
6558{
66− if (m_usageMode[schemaId] != str) {
67− m_usageMode[schemaId] = str;
68−
69− Q_FOREACH (GSettingsQml *obj, m_registeredGSettings) {
70− if (obj->schema()->id() == schemaId) {
71− Q_EMIT obj->usageModeChanged(str);
72− }
73− }
59+ if (usageMode != m_usageMode) {
60+ m_usageMode = usageMode;
61+ Q_EMIT usageModeChanged(m_usageMode);
7462 }
7563}
7664
77−QString GSettingsControllerQml::usageMode(const QByteArray &schemaId) const
78−{
79− return m_usageMode.value(schemaId, "Staged");
80−}
81−
8265GSettingsSchemaQml::GSettingsSchemaQml(QObject *parent): QObject(parent) {
8366}
8467
@@ -93,7 +76,6 @@ void GSettingsSchemaQml::setId(const QByteArray &id) {
9376 }
9477
9578 m_id = id;
96− Q_EMIT idChanged(id);
9779}
9880
9981QByteArray GSettingsSchemaQml::path() const {
@@ -109,33 +91,48 @@ void GSettingsSchemaQml::setPath(const QByteArray &path) {
10991 m_path = path;
11092}
11193
112−GSettingsQml::GSettingsQml(QObject *parent): QObject(parent) {
94+GSettingsQml::GSettingsQml(QObject *parent)
95+ : QObject(parent)
96+{
11397 m_schema = new GSettingsSchemaQml(this);
114− GSettingsControllerQml::instance()->registerSettingsObject(this);
115−}
116−
117−GSettingsQml::~GSettingsQml() {
118− GSettingsControllerQml::instance()->unRegisterSettingsObject(this);
98+ connect(GSettingsControllerQml::instance(), SIGNAL(pictureUriChanged(const QString &)),
99+ this, SIGNAL(pictureUriChanged(const QString &)));
100+ connect(GSettingsControllerQml::instance(), SIGNAL(usageModeChanged(const QString &)),
101+ this, SIGNAL(usageModeChanged(const QString &)));
119102}
120103
121104GSettingsSchemaQml * GSettingsQml::schema() const {
122105 return m_schema;
123106}
124107
125−void GSettingsQml::setPictureUri(const QString &str) {
126− GSettingsControllerQml::instance()->setPictureUri(m_schema->id(), str);
108+QString GSettingsQml::pictureUri() const
109+{
110+ if (m_schema->id() == "org.gnome.desktop.background") {
111+ return GSettingsControllerQml::instance()->pictureUri();
112+ } else {
113+ return "";
114+ }
127115}
128116
129−QString GSettingsQml::pictureUri() const {
130− return GSettingsControllerQml::instance()->pictureUri(m_schema->id());
117+void GSettingsQml::setPictureUri(const QString &str)
118+{
119+ if (m_schema->id() == "org.gnome.desktop.background") {
120+ GSettingsControllerQml::instance()->setPictureUri(str);
121+ }
131122}
132123
133−void GSettingsQml::setUsageMode(const QString &str) {
134− GSettingsControllerQml::instance()->setUsageMode(m_schema->id(), str);
124+QString GSettingsQml::usageMode() const
125+{
126+ if (m_schema->id() == "com.canonical.Unity8") {
127+ return GSettingsControllerQml::instance()->usageMode();
128+ } else {
129+ return "";
130+ }
135131}
136132
137−QString GSettingsQml::usageMode() const {
138− return GSettingsControllerQml::instance()->usageMode(m_schema->id());
139−
133+void GSettingsQml::setUsageMode(const QString &usageMode)
134+{
135+ if (m_schema->id() == "com.canonical.Unity8") {
136+ GSettingsControllerQml::instance()->setUsageMode(usageMode);
137+ }
140138}
141−
tests/mocks/GSettings.1.0/fake_gsettings.h+14−20
@@ -18,14 +18,13 @@
1818#define FAKE_GSETTINGS_H
1919
2020#include <QList>
21−#include <QHash>
2221#include <QObject>
2322
2423class GSettingsSchemaQml: public QObject
2524{
2625 Q_OBJECT
2726
28− Q_PROPERTY(QByteArray id READ id WRITE setId NOTIFY idChanged)
27+ Q_PROPERTY(QByteArray id READ id WRITE setId)
2928
3029public:
3130 GSettingsSchemaQml(QObject *parent = nullptr);
@@ -36,9 +35,6 @@ public:
3635 QByteArray path() const;
3736 void setPath(const QByteArray &path);
3837
39−Q_SIGNALS:
40− void idChanged(const QByteArray &id);
41−
4238private:
4339 QByteArray m_id;
4440 QByteArray m_path;
@@ -54,16 +50,14 @@ class GSettingsQml: public QObject
5450
5551public:
5652 GSettingsQml(QObject *parent = nullptr);
57− ~GSettingsQml();
5853
5954 GSettingsSchemaQml * schema() const;
60−
61− void setPictureUri(const QString &str);
6255 QString pictureUri() const;
63−
64− void setUsageMode(const QString &str);
6556 QString usageMode() const;
6657
58+ void setPictureUri(const QString &str);
59+ void setUsageMode(const QString &usageMode);
60+
6761Q_SIGNALS:
6862 void schemaChanged();
6963 void pictureUriChanged(const QString&);
@@ -71,7 +65,6 @@ Q_SIGNALS:
7165
7266private:
7367 GSettingsSchemaQml* m_schema;
74− QString m_pictureUri;
7568
7669 friend class GSettingsSchemaQml;
7770};
@@ -84,23 +77,24 @@ public:
8477 static GSettingsControllerQml* instance();
8578 ~GSettingsControllerQml();
8679
87− void registerSettingsObject(GSettingsQml *obj);
88− void unRegisterSettingsObject(GSettingsQml *obj);
80+ QString pictureUri() const;
81+ Q_INVOKABLE void setPictureUri(const QString &str);
8982
90− Q_INVOKABLE void setPictureUri(const QByteArray &id, const QString &str);
91− QString pictureUri(const QByteArray &id) const;
83+ QString usageMode() const;
84+ Q_INVOKABLE void setUsageMode(const QString &usageMode);
9285
93− Q_INVOKABLE void setUsageMode(const QByteArray &id, const QString &str);
94− QString usageMode(const QByteArray &id) const;
86+Q_SIGNALS:
87+ void pictureUriChanged(const QString&);
88+ void usageModeChanged(const QString&);
9589
9690private:
9791 GSettingsControllerQml();
9892
93+ QString m_pictureUri;
94+ QString m_usageMode;
95+
9996 static GSettingsControllerQml* s_controllerInstance;
10097 QList<GSettingsQml *> m_registeredGSettings;
101−
102− QHash<QString, QString> m_pictureUri;
103− QHash<QString, QString> m_usageMode;
10498};
10599
106100#endif // FAKE_GSETTINGS_H
tests/mocks/Unity/Application/MirSurfaceItem.cpp+6
@@ -47,6 +47,12 @@ MirSurfaceItem::MirSurfaceItem(const QString& name,
4747{
4848 qDebug() << "MirSurfaceItem::MirSurfaceItem() " << this->name();
4949
50+ setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton | Qt::RightButton |
51+ Qt::ExtraButton1 | Qt::ExtraButton2 | Qt::ExtraButton3 | Qt::ExtraButton4 |
52+ Qt::ExtraButton5 | Qt::ExtraButton6 | Qt::ExtraButton7 | Qt::ExtraButton8 |
53+ Qt::ExtraButton9 | Qt::ExtraButton10 | Qt::ExtraButton11 |
54+ Qt::ExtraButton12 | Qt::ExtraButton13);
55+
5056 QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
5157
5258 connect(this, &QQuickItem::focusChanged,
tests/mocks/Unity/Application/MirSurfaceItem.h+5
@@ -104,6 +104,11 @@ Q_SIGNALS:
104104protected:
105105 void touchEvent(QTouchEvent * event) override;
106106
107+ // becaue the default implementation ignores the events
108+ void mousePressEvent(QMouseEvent *) override {}
109+ void mouseMoveEvent(QMouseEvent *) override {}
110+ void mouseReleaseEvent(QMouseEvent *) override {}
111+
107112private Q_SLOTS:
108113 void onFocusChanged();
109114 void onComponentStatusChanged(QQmlComponent::Status status);
tests/mocks/Unity/fake_scope.cpp+13−2
@@ -24,6 +24,8 @@
2424#include "fake_scopes.h"
2525#include "fake_settingsmodel.h"
2626
27+#include <paths.h> // from unity8/include
28+
2729Scope::Scope(Scopes* parent) : Scope("MockScope5", "Mock Scope", false, parent)
2830{
2931}
@@ -249,11 +251,11 @@ QVariantMap Scope::customizations() const
249251 m["foreground-color"] = "blue";
250252 m["page-header"] = h;
251253 } else if (m_id == "MockScope4") {
252− h["navigation-background"] = QUrl("../../../tests/qmltests/Dash/artwork/background.png");
254+ h["navigation-background"] = QUrl(sourceDirectory() + "tests/qmltests/Dash/artwork/background.png");
253255 m["page-header"] = h;
254256 } else if (m_id == "MockScope5") {
255257 h["background"] = "gradient:///lightgrey/grey";
256− h["logo"] = QUrl("../../../tests/qmltests/Dash/tst_PageHeader/logo-ubuntu-orange.svg");
258+ h["logo"] = QUrl(sourceDirectory() + "tests/qmltests/Dash/tst_PageHeader/logo-ubuntu-orange.svg");
257259 h["divider-color"] = "red";
258260 h["navigation-background"] = "color:///black";
259261 m["page-header"] = h;
@@ -310,3 +312,12 @@ void Scope::setNavigationState(const QString &navigationId, bool isAltNavigation
310312 Q_EMIT currentNavigationIdChanged();
311313 }
312314}
315+
316+void Scope::performQuery(const QString& query)
317+{
318+ Q_EMIT queryPerformed(query);
319+ if (query.startsWith("scopes://")) {
320+ QString scopeId = query.mid(9);
321+ Q_EMIT gotoScope(scopeId);
322+ }
323+}
tests/mocks/Unity/fake_scope.h+4−2
@@ -72,7 +72,7 @@ public:
7272 Q_INVOKABLE unity::shell::scopes::NavigationInterface* getNavigation(QString const& navigationId) override;
7373 Q_INVOKABLE unity::shell::scopes::NavigationInterface* getAltNavigation(QString const& altNavigationId) override;
7474 Q_INVOKABLE void setNavigationState(const QString &navigationId, bool isAltNavigation) override;
75− Q_SIGNAL void performQuery(const QString& query) override;
75+ void performQuery(const QString& query) override;
7676
7777 Status status() const override;
7878 QVariantMap customizations() const override;
@@ -80,7 +80,9 @@ public:
8080 Q_INVOKABLE void refresh() override;
8181
8282Q_SIGNALS:
83− void refreshed(); // This is not in the Interface, here for testing benefits
83+ // These are not in the Interface, here for testing benefits
84+ void refreshed();
85+ void queryPerformed(const QString& query);
8486
8587protected:
8688
tests/mocks/data/unity/indicators/com.canonical.indicator.mocknew file+10
@@ -0,0 +1,10 @@
1+[Indicator Service]
2+Name=indicator-mock
3+ObjectPath=/com/canonical/indicator/mock
4+Position=0
5+
6+[phone]
7+ObjectPath=/com/canonical/indicator/mock/desktop
8+
9+[desktop]
10+ObjectPath=/com/canonical/indicator/mock/desktop
tests/mocks/indicator-service/CMakeLists.txtnew file+20
@@ -0,0 +1,20 @@
1+project(mock-indicator-service)
2+pkg_search_module(GIO REQUIRED gio-2.0)
3+
4+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")
5+
6+include_directories(
7+ ${CMAKE_CURRENT_SOURCE_DIR}
8+ ${GIO_INCLUDE_DIRS}
9+)
10+
11+add_executable(${MOCK_INDICATOR_SERVICE_APP}
12+ mock-indicator-service.c
13+)
14+
15+target_link_libraries(${MOCK_INDICATOR_SERVICE_APP} ${GIO_LDFLAGS})
16+
17+set_target_properties(${MOCK_INDICATOR_SERVICE_APP} PROPERTIES COMPILE_FLAGS -fPIC)
18+
19+install(TARGETS ${MOCK_INDICATOR_SERVICE_APP}
20+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
tests/mocks/indicator-service/mock-indicator-service.cnew file+261
@@ -0,0 +1,261 @@
1+/*
2+ * Copyright (C) 2015 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License along
14+ * with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+#include <gio/gio.h>
17+#include <stdio.h>
18+#include <stdlib.h>
19+
20+G_DEFINE_QUARK (SLIDER_VALUE, slider_value)
21+
22+typedef struct
23+{
24+ GSimpleActionGroup *actions;
25+ GMenu *menu;
26+
27+ guint actions_export_id;
28+ guint menu_export_id;
29+ int action_delay;
30+} IndicatorTestService;
31+
32+static void
33+bus_acquired (GDBusConnection *connection,
34+ const gchar *name,
35+ gpointer user_data)
36+{
37+ (void) name;
38+ IndicatorTestService *indicator = user_data;
39+ GError *error = NULL;
40+
41+ indicator->actions_export_id = g_dbus_connection_export_action_group (connection,
42+ "/com/canonical/indicator/mock",
43+ G_ACTION_GROUP (indicator->actions),
44+ &error);
45+ if (indicator->actions_export_id == 0)
46+ {
47+ g_warning ("cannot export action group: %s", error->message);
48+ g_error_free (error);
49+ return;
50+ }
51+
52+ indicator->menu_export_id = g_dbus_connection_export_menu_model (connection,
53+ "/com/canonical/indicator/mock/desktop",
54+ G_MENU_MODEL (indicator->menu),
55+ &error);
56+ if (indicator->menu_export_id == 0)
57+ {
58+ g_warning ("cannot export menu: %s", error->message);
59+ g_error_free (error);
60+ return;
61+ }
62+}
63+
64+static void
65+name_lost (GDBusConnection *connection,
66+ const gchar *name,
67+ gpointer user_data)
68+{
69+ (void) name;
70+ IndicatorTestService *indicator = user_data;
71+
72+ if (indicator->actions_export_id)
73+ g_dbus_connection_unexport_action_group (connection, indicator->actions_export_id);
74+
75+ if (indicator->menu_export_id)
76+ g_dbus_connection_unexport_menu_model (connection, indicator->menu_export_id);
77+}
78+
79+static void
80+activate_show (GSimpleAction *action,
81+ GVariant *parameter,
82+ gpointer user_data)
83+{
84+ (void) action;
85+ (void) parameter;
86+ (void) user_data;
87+ g_message ("showing");
88+}
89+
90+static gboolean
91+actual_switch (gpointer user_data)
92+{
93+ GSimpleAction *action = user_data;
94+
95+ GVariant* v = g_action_get_state(G_ACTION(action));
96+ gboolean state = g_variant_get_boolean (v);
97+ GVariant *new_state = g_variant_new_boolean (state == TRUE ? FALSE : TRUE);
98+
99+ g_simple_action_set_state(G_SIMPLE_ACTION(action), new_state);
100+
101+ g_variant_unref (v);
102+ g_message ("switching");
103+ return FALSE;
104+}
105+
106+static void
107+activate_switch (GSimpleAction *action,
108+ GVariant *parameter,
109+ gpointer user_data)
110+{
111+ (void) action;
112+ (void) parameter;
113+
114+ IndicatorTestService *indicator = user_data;
115+
116+ g_timeout_add(indicator->action_delay, actual_switch, action);
117+ g_message ("switch delay");
118+}
119+
120+static gboolean
121+actual_slide (gpointer user_data)
122+{
123+ GSimpleAction *action = user_data;
124+
125+ GVariant* new_state = g_object_get_qdata (G_OBJECT (action), slider_value_quark ());
126+
127+ g_simple_action_set_state(G_SIMPLE_ACTION(action), new_state);
128+
129+ g_message ("switching");
130+ return FALSE;
131+}
132+
133+void change_slider (GSimpleAction *action,
134+ GVariant *value,
135+ gpointer user_data)
136+{
137+ IndicatorTestService *indicator = user_data;
138+
139+ g_object_set_qdata (G_OBJECT (action), slider_value_quark (), g_variant_ref(value));
140+
141+ g_timeout_add(indicator->action_delay, actual_slide, action);
142+ g_message ("slide delay %.03f", g_variant_get_double(value));
143+}
144+
145+int
146+main (int argc, char **argv)
147+{
148+ IndicatorTestService indicator = { 0 };
149+ indicator.action_delay = -1;
150+ GMenuItem *item;
151+ GMenu *submenu;
152+ GActionEntry entries[] = {
153+ { "_header", NULL, NULL, "{'title': <'Test'>,"
154+ " 'label': <'Test'>,"
155+ " 'visible': <true>,"
156+ " 'accessible-desc': <'Test indicator'> }", NULL },
157+ { "action.show", activate_show, NULL, NULL, NULL },
158+ { "action.switch", activate_switch, NULL, "true", NULL },
159+ { "action.checkbox", activate_switch, NULL, "true", NULL },
160+ { "action.accessPoint", activate_switch, NULL, "false", NULL },
161+ { "action.slider", NULL, NULL, "0.5", change_slider }
162+ };
163+ GMainLoop *loop;
164+
165+ int help = 0;
166+ if (argc > 1)
167+ {
168+ int i;
169+ for (i = 1; i < argc; i++) {
170+ const char *arg = argv[i];
171+
172+ if (arg[0] == '-') {
173+ switch (arg[1])
174+ {
175+ case 't':
176+ {
177+ arg += 2;
178+ if (!arg[0] && i < argc-1) {
179+ i++;
180+ int delay = -1;
181+
182+ if (sscanf(argv[i], "%d", &delay) == 1) {
183+ indicator.action_delay = delay;
184+ } else {
185+ printf("Invalid action delay value: %s\n", argv[i]);
186+ help = 1;
187+ }
188+ } else {
189+ printf("Invalid action delay value: %s\n", argv[i]);
190+ help = 1;
191+ }
192+ break;
193+ }
194+ case 'h':
195+ help = 1;
196+ break;
197+ }
198+ }
199+ }
200+ }
201+
202+ if (help) {
203+ printf("Usage: %s [<options>]\n"
204+ " -t DELAY Action activation delay\n"
205+ " -h Show this help text\n"
206+ , argv[0]);
207+ return 0;
208+ }
209+
210+ indicator.actions = g_simple_action_group_new ();
211+ g_action_map_add_action_entries (G_ACTION_MAP (indicator.actions), entries, G_N_ELEMENTS (entries), &indicator);
212+
213+ submenu = g_menu_new ();
214+ g_menu_append (submenu, "Show", "indicator.action.show");
215+
216+ // Switch
217+ item = g_menu_item_new("Switch", "indicator.action.switch");
218+ g_menu_item_set_attribute (item, "x-canonical-type", "s", "com.canonical.indicator.switch");
219+ g_menu_append_item(submenu, item);
220+
221+ // Checkbox
222+ item = g_menu_item_new("Checkbox", "indicator.action.checkbox");
223+ g_menu_append_item(submenu, item);
224+
225+ // Slider
226+ item = g_menu_item_new("Slider", "indicator.action.slider");
227+ g_menu_item_set_attribute (item, "x-canonical-type", "s", "com.canonical.indicator.slider");
228+ g_menu_append_item(submenu, item);
229+
230+ // Access Point
231+ item = g_menu_item_new("Access Point", "indicator.action.accessPoint");
232+ g_menu_item_set_attribute (item, "x-canonical-type", "s", "unity.widgets.systemsettings.tablet.accesspoint");
233+ g_menu_append_item(submenu, item);
234+
235+
236+ item = g_menu_item_new (NULL, "indicator._header");
237+ g_menu_item_set_attribute (item, "x-canonical-type", "s", "com.canonical.indicator.root");
238+ g_menu_item_set_submenu (item, G_MENU_MODEL (submenu));
239+ indicator.menu = g_menu_new ();
240+ g_menu_append_item (indicator.menu, item);
241+
242+ g_bus_own_name (G_BUS_TYPE_SESSION,
243+ "com.canonical.indicator.mock",
244+ G_BUS_NAME_OWNER_FLAGS_NONE,
245+ bus_acquired,
246+ NULL,
247+ name_lost,
248+ &indicator,
249+ NULL);
250+
251+ loop = g_main_loop_new (NULL, FALSE);
252+ g_main_loop_run (loop);
253+
254+ g_object_unref (submenu);
255+ g_object_unref (item);
256+ g_object_unref (indicator.actions);
257+ g_object_unref (indicator.menu);
258+ g_object_unref (loop);
259+
260+ return 1;
261+}
tests/plugins/Unity/Indicators/indicatorsmanagertest.cpp−2
@@ -31,13 +31,11 @@ private Q_SLOTS:
3131
3232 void initTestCase()
3333 {
34− setenv("UNITY_TEST_ENV", "1", 1);
3534 setenv("XDG_DATA_DIRS", (sourceDirectory() + "/tests/data").toLatin1().data(), 1);
3635 }
3736
3837 void cleanupTestCase()
3938 {
40− unsetenv("UNITY_TEST_ENV");
4139 }
4240
4341 /*
tests/plugins/Unity/Indicators/indicatorsmodeltest.cpp−2
@@ -32,13 +32,11 @@ private Q_SLOTS:
3232
3333 void initTestCase()
3434 {
35− setenv("UNITY_TEST_ENV", "1", 1);
3635 setenv("XDG_DATA_DIRS", (sourceDirectory() + "/tests/data").toLatin1().data(), 1);
3736 }
3837
3938 void cleanupTestCase()
4039 {
41− unsetenv("UNITY_TEST_ENV");
4240 }
4341
4442 /*
tests/plugins/Unity/Launcher/launchermodeltest.cpp+57
@@ -400,6 +400,63 @@ private Q_SLOTS:
400400 QCOMPARE(launcherModel->get(index)->count(), 55);
401401 }
402402
403+ void testCountEmblemAddsRemovesItem_data() {
404+ QTest::addColumn<bool>("isPinned");
405+ QTest::addColumn<bool>("isRunning");
406+ QTest::addColumn<bool>("startWhenVisible");
407+ QTest::newRow("not pinned, not running") << false << false << false;
408+ QTest::newRow("pinned, not running") << true << false << false;
409+ QTest::newRow("not pinned, not running, starting from notification") << false << false << true;
410+ QTest::newRow("pinned, not running, starting from notification") << true << false << true;
411+ QTest::newRow("not pinned, running") << false << true << false;
412+ QTest::newRow("pinned, running") << true << true << false;
413+ }
414+
415+ void testCountEmblemAddsRemovesItem() {
416+ QFETCH(bool, isPinned);
417+ QFETCH(bool, isRunning);
418+ QFETCH(bool, startWhenVisible);
419+
420+ // Make sure item is here as expected after init() and that count is not visible
421+ int index = launcherModel->findApplication("abs-icon");
422+ QCOMPARE(index == -1, false);
423+ QCOMPARE(launcherModel->get(index)->countVisible(), false);
424+
425+ // Pin if we need to
426+ if (isPinned) {
427+ launcherModel->pin("abs-icon");
428+ }
429+ QCOMPARE(launcherModel->get(0)->pinned(), isPinned);
430+
431+ // Stop it if we need to
432+ if (!isRunning) {
433+ appManager->stopApplication("abs-icon");
434+ }
435+ QCOMPARE(launcherModel->findApplication("abs-icon") >= 0, isRunning || isPinned);
436+
437+
438+ // set the count emblem to visible
439+ QDBusInterface interface("com.canonical.Unity.Launcher", "/com/canonical/Unity/Launcher/abs_2Dicon", "org.freedesktop.DBus.Properties");
440+ interface.call("Set", "com.canonical.Unity.Launcher.Item", "count", QVariant::fromValue(QDBusVariant(55)));
441+ interface.call("Set", "com.canonical.Unity.Launcher.Item", "countVisible", QVariant::fromValue(QDBusVariant(true)));
442+
443+ // Make sure item is here and that count is visible
444+ index = launcherModel->findApplication("abs-icon");
445+ QCOMPARE(index == -1, false);
446+ QCOMPARE(launcherModel->get(index)->countVisible(), true);
447+
448+ if (!isRunning && startWhenVisible) {
449+ appManager->addApplication(new MockApp("abs-icon"));
450+ }
451+
452+ // Hide count emblem again
453+ interface.call("Set", "com.canonical.Unity.Launcher.Item", "countVisible", QVariant::fromValue(QDBusVariant(false)));
454+
455+ // Make sure item is shown/hidden as expected
456+ index = launcherModel->findApplication("abs-icon");
457+ QCOMPARE(index == -1, !isRunning && !isPinned && !startWhenVisible);
458+ }
459+
403460 void testRefreshAfterDeletedDesktopFiles_data() {
404461 QTest::addColumn<bool>("deleted");
405462 QTest::newRow("have .desktop files") << false;
tests/qmltests/Components/tst_Dialogs.qml+4−2
@@ -79,7 +79,7 @@ Rectangle {
7979 Column {
8080 anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
8181 spacing: units.gu(1)
82− Button { text: "Power dialog"; onClicked: { testCase.showPowerDialog(); } }
82+ Button { text: "Power dialog"; onClicked: { testCase.test_showPowerDialog(); } }
8383 Button { text: "Logout Requested"; onClicked: { fakeUnitySession.logoutRequested(); } }
8484 Button { text: "Shutdown Requested"; onClicked: { fakeUnitySession.shutdownRequested(); } }
8585 Button { text: "Reboot Requested"; onClicked: { fakeUnitySession.rebootRequested(); } }
@@ -96,9 +96,11 @@ Rectangle {
9696 name: "Dialogs"
9797 when: windowShown
9898
99− function showPowerDialog() {
99+ function test_showPowerDialog() {
100100 var dialogsPrivate = findInvisibleChild(dialogs, "dialogsPrivate");
101101 dialogsPrivate.showPowerDialog();
102+ var dialogLoader = findInvisibleChild(dialogs, "dialogLoader");
103+ tryCompare(dialogLoader.item, "focus", true);
102104 }
103105 }
104106}
tests/qmltests/Dash/tst_Dash.qml+49−1
@@ -315,7 +315,7 @@ Item {
315315
316316 var scopesList = findChild(dash, "scopesList");
317317 spy.target = scopesList.scope;
318− spy.signalName = "performQuery";
318+ spy.signalName = "queryPerformed";
319319
320320 // Click on the store
321321 var scopesListPageHeader = findChild(scopesList, "pageHeader");
@@ -517,5 +517,53 @@ Item {
517517 tryCompare(dashTempScopeItem, "x", dash.width);
518518 tryCompare(dashTempScopeItem, "visible", false);
519519 }
520+
521+ function test_UriDispatcher()
522+ {
523+ var dashContentList = findChild(dash, "dashContentList");
524+
525+ UriHandler.opened("scopes://clickscope");
526+ tryCompare(dashContentList, "currentIndex", 1);
527+
528+ // Show the manage dash
529+ touchFlick(dash, dash.width / 2, dash.height - 1, dash.width / 2, units.gu(2));
530+ var bottomEdgeController = findInvisibleChild(dash, "bottomEdgeController");
531+ tryCompare(bottomEdgeController, "progress", 1);
532+
533+ // UriHandler changes to a scope and closes the manage scopes
534+ UriHandler.opened("scopes://MockScope1");
535+ tryCompare(dashContentList, "currentIndex", 0);
536+ tryCompare(bottomEdgeController, "progress", 0);
537+
538+ // Show a preview
539+ var scopeLoader0 = findChild(dashContent, "scopeLoader0");
540+ var dashCategory0 = findChild(scopeLoader0, "dashCategory0");
541+ var delegate0 = findChild(dashCategory0, "delegate0");
542+ mouseClick(delegate0);
543+ tryCompare(dashContent, "subPageShown", true)
544+
545+ // UriHandler changes to a scope and closes the manage scopes
546+ UriHandler.opened("scopes://clickscope");
547+ tryCompare(dashContentList, "currentIndex", 1);
548+ tryCompare(dashContent, "subPageShown", false);
549+
550+ // Go to a temp scope
551+ touchFlick(dash, dash.width / 2, dash.height - 1, dash.width / 2, units.gu(2));
552+ var bottomEdgeController = findInvisibleChild(dash, "bottomEdgeController");
553+ tryCompare(bottomEdgeController, "progress", 1);
554+ var nonfavScopesListCategory = findChild(dash, "scopesListCategoryother");
555+ var nonfavScopesListCategoryList = findChild(nonfavScopesListCategory, "scopesListCategoryInnerList");
556+ tryCompare(nonfavScopesListCategoryList, "currentIndex", 0);
557+ mouseClick(nonfavScopesListCategoryList.currentItem);
558+ var dashTempScopeItem = findChild(dash, "dashTempScopeItem");
559+ tryCompare(dashTempScopeItem, "x", 0);
560+ tryCompare(dashTempScopeItem, "visible", true);
561+
562+ // UriHandler changes to a scope and closes the temp scope
563+ UriHandler.opened("scopes://MockScope1");
564+ tryCompare(dashContentList, "currentIndex", 0);
565+ tryCompare(dashTempScopeItem, "x", dashTempScopeItem.width);
566+ tryCompare(dashTempScopeItem, "visible", false);
567+ }
520568 }
521569}
tests/qmltests/Dash/tst_GenericScopeView.qml+1−1
@@ -206,7 +206,7 @@ Item {
206206 var header = findChild(genericScopeView, "dashSectionHeader1");
207207
208208 spy.target = genericScopeView.scope;
209− spy.signalName = "performQuery";
209+ spy.signalName = "queryPerformed";
210210
211211 mouseClick(header);
212212
tests/qmltests/Dash/tst_PreviewListView.qml+1−1
@@ -109,7 +109,7 @@ Rectangle {
109109
110110 var image = findChild(header, "titleImage");
111111 verify(image, "Could not find the title image.");
112− compare(image.source, Qt.resolvedUrl("../Dash/tst_PageHeader/logo-ubuntu-orange.svg"), "Title image has the wrong source");
112+ compare(image.source, Qt.resolvedUrl("tst_PageHeader/logo-ubuntu-orange.svg"), "Title image has the wrong source");
113113 }
114114 }
115115}
tests/qmltests/Panel/Indicators/tst_MenuItemFactory.qml+5−1
@@ -230,7 +230,7 @@ Item {
230230 compare(loader.item.value, data.manualValue, "Slider value does not match manual set value");
231231
232232 menuData.actionState = data.value2;
233− compare(loader.item.value, data.value2, "Value does not match new data");
233+ tryCompare(loader.item, "value", data.value2, 10000, "Value does not match new data");
234234
235235 menuData.actionState = undefined;
236236 compare(loader.item.value, data.value2, "Undefined state should not update slider value");
@@ -819,6 +819,10 @@ Item {
819819 loader.data = menuData;
820820 loader.sourceComponent = factory.load(menuData);
821821
822+ var sync = findInvisibleChild(loader.item, "sync");
823+ verify(sync);
824+ sync.syncTimeout = 500;
825+
822826 compare(loader.item.checked, false, "Loader did not load check state");
823827 mouseClick(loader.item,
824828 loader.item.width / 2, loader.item.height / 2);
tests/qmltests/Panel/tst_Panel.qml+52
@@ -390,5 +390,57 @@ IndicatorTest {
390390 tap(panel, touchPosX, touchPosY);
391391 compare(backgroundPressedSpy.count, 2);
392392 }
393+
394+ /*
395+ Regression test for https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1439318
396+ When the panel is in fullscreen mode and the user taps near the top edge,
397+ the panel should take no action and the tap should reach the item behind the
398+ panel.
399+ */
400+ function test_tapNearTopEdgeWithPanelInFullscreenMode() {
401+ var indicatorArea = findChild(panel, "indicatorArea");
402+ verify(indicatorArea);
403+ var panelPriv = findInvisibleChild(panel, "panelPriv");
404+ verify(panelPriv);
405+
406+ panel.fullscreenMode = true;
407+ // wait until if finishes hiding itself
408+ tryCompare(indicatorArea, "y", -panelPriv.indicatorHeight);
409+
410+ compare(panel.indicators.shown, false);
411+ verify(panel.indicators.fullyClosed);
412+
413+ // tap near the very top of the screen
414+ tap(itemArea, itemArea.width / 2, 2);
415+
416+ // the tap should have reached the item behind the panel
417+ compare(backgroundPressedSpy.count, 2);
418+
419+ // give it a couple of event loop iterations for any animations etc to kick in
420+ wait(50);
421+
422+ compare(panel.indicators.shown, false);
423+ verify(panel.indicators.fullyClosed);
424+ }
425+
426+ function test_openAndClosePanelWithMouseClicks() {
427+ compare(panel.indicators.shown, false);
428+ verify(panel.indicators.fullyClosed);
429+
430+ mouseClick(panel.indicators,
431+ panel.indicators.width / 2,
432+ panel.indicators.minimizedPanelHeight / 2);
433+
434+ compare(panel.indicators.shown, true);
435+ tryCompare(panel.indicators, "fullyOpened", true);
436+
437+ var handle = findChild(panel.indicators, "handle");
438+ verify(handle);
439+
440+ mouseClick(handle);
441+
442+ compare(panel.indicators.shown, false);
443+ tryCompare(panel.indicators, "fullyClosed", true);
444+ }
393445 }
394446}
tests/qmltests/Stages/tst_SurfaceContainer.qml+32−5
@@ -1,5 +1,5 @@
11/*
2− * Copyright 2014 Canonical Ltd.
2+ * Copyright 2014-2015 Canonical Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
1616
1717import QtQuick 2.0
1818import QtTest 1.0
19−import Unity.Test 0.1 as UT
19+import Unity.Test 0.1
2020import ".."
2121import "../../../qml/Stages"
2222import Ubuntu.Components 0.1
@@ -32,6 +32,8 @@ Rectangle {
3232 id: surfaceContainerComponent
3333 SurfaceContainer {
3434 anchors.fill: parent
35+ orientation: Qt.PortraitOrientation
36+ interactive: interactiveCheckbox.checked
3537 }
3638 }
3739 Loader {
@@ -85,6 +87,12 @@ Rectangle {
8587 CheckBox {id: fullscreenCheckbox; checked: true; }
8688 Label { text: "fullscreen" }
8789 }
90+ Row {
91+ anchors { left: parent.left; right: parent.right }
92+ CheckBox {id: interactiveCheckbox; checked: true; }
93+ Label { text: "interactive" }
94+ }
95+ MouseTouchEmulationCheckbox {}
8896 }
8997 }
9098
@@ -94,7 +102,7 @@ Rectangle {
94102 signalName: "surfaceDestroyed"
95103 }
96104
97− UT.UnityTestCase {
105+ UnityTestCase {
98106 id: testCase
99107 name: "SurfaceContainer"
100108 when: windowShown
@@ -110,6 +118,8 @@ Rectangle {
110118
111119 tryCompare(surfaceContainerLoader.item, "surface", null);
112120 surfaceSpy.clear();
121+
122+ interactiveCheckbox.checked = true;
113123 }
114124
115125 /*
@@ -145,14 +155,13 @@ Rectangle {
145155 surfaceContainer.surface.touchPressCount = 0;
146156 surfaceContainer.surface.touchReleaseCount = 0;
147157
148− surfaceContainer.interactive = true;
149158 tap(surfaceContainer, surfaceContainer.width / 2, surfaceContainer.height / 2);
150159
151160 // surface got touches as the surfaceContainer is interactive
152161 compare(surfaceContainer.surface.touchPressCount, 1)
153162 compare(surfaceContainer.surface.touchReleaseCount, 1);
154163
155− surfaceContainer.interactive = false;
164+ interactiveCheckbox.checked = false;
156165 tap(surfaceContainer, surfaceContainer.width / 2, surfaceContainer.height / 2);
157166
158167 // surface shouldn't get the touches from the second tap as the surfaceContainer
@@ -160,5 +169,23 @@ Rectangle {
160169 compare(surfaceContainer.surface.touchPressCount, 1)
161170 compare(surfaceContainer.surface.touchReleaseCount, 1);
162171 }
172+
173+ function test_surfaceGetsActiveFocusOnMousePress() {
174+ surfaceCheckbox.checked = true;
175+ verify(surfaceContainer.surface !== null);
176+
177+ compare(surfaceContainer.surface.activeFocus, false);
178+ mouseClick(surfaceContainer);
179+ compare(surfaceContainer.surface.activeFocus, true);
180+ }
181+
182+ function test_surfaceGetsActiveFocusOnTap() {
183+ surfaceCheckbox.checked = true;
184+ verify(surfaceContainer.surface !== null);
185+
186+ compare(surfaceContainer.surface.activeFocus, false);
187+ tap(surfaceContainer);
188+ compare(surfaceContainer.surface.activeFocus, true);
189+ }
163190 }
164191}
tests/qmltests/Tutorial/tst_Tutorial.qml+22−5
@@ -17,6 +17,7 @@
1717import QtQuick 2.0
1818import QtTest 1.0
1919import AccountsService 0.1
20+import GSettings 1.0
2021import LightDM 0.1 as LightDM
2122import Ubuntu.Components 1.1
2223import Unity.Application 0.1
@@ -45,6 +46,11 @@ Item {
4546 }
4647 }
4748
49+ GSettings {
50+ id: unity8Settings
51+ schema.id: "com.canonical.Unity8"
52+ }
53+
4854 Component.onCompleted: {
4955 // must set the mock mode before loading the Shell
5056 LightDM.Greeter.mockMode = "single-pin";
@@ -112,6 +118,7 @@ Item {
112118
113119 function init() {
114120 tryCompare(shell, "enabled", true); // enabled by greeter when ready
121+ unity8Settings.usageMode = "Staged";
115122 AccountsService.demoEdges = false;
116123 AccountsService.demoEdges = true;
117124 swipeAwayGreeter();
@@ -185,17 +192,19 @@ Item {
185192 }
186193
187194 function checkRightEdge() {
188− touchFlick(shell, shell.width, halfHeight, halfWidth, halfHeight);
195+ if (unity8Settings.usageMode === "Staged") {
196+ touchFlick(shell, shell.width, halfHeight, halfWidth, halfHeight);
189197
190− var stage = findChild(shell, "stage");
191− var spreadView = findChild(stage, "spreadView");
192− tryCompare(spreadView, "phase", 0);
198+ var stage = findChild(shell, "stage");
199+ var spreadView = findChild(stage, "spreadView");
200+ tryCompare(spreadView, "phase", 0);
201+ }
193202 }
194203
195204 function checkBottomEdge() {
196205 // Can't actually check effect of swipe, since dash isn't really loaded
197206 var applicationsDisplayLoader = findChild(shell, "applicationsDisplayLoader");
198− tryCompare(applicationsDisplayLoader.item, "interactive", false);
207+ tryCompare(applicationsDisplayLoader, "interactive", false);
199208 }
200209
201210 function checkFinished() {
@@ -256,6 +265,14 @@ Item {
256265 goToPage(null);
257266 }
258267
268+ function test_walkthroughOnDesktop() {
269+ unity8Settings.usageMode = "Windowed";
270+ var page = goToPage("tutorialLeftFinish");
271+ var tick = findChild(page, "tick");
272+ tap(tick);
273+ checkFinished();
274+ }
275+
259276 function test_launcherShortDrag() {
260277 // goToPage does a normal launcher pull. But here we want to test
261278 // just barely pulling the launcher out and letting go (i.e. not
tests/qmltests/tst_Shell.qml+11−6
@@ -87,7 +87,7 @@ Rectangle {
8787 }
8888 StateChangeScript {
8989 script: {
90− GSettingsController.setUsageMode("com.canonical.Unity8", "Staged")
90+ GSettingsController.setUsageMode("Staged")
9191 }
9292 }
9393 },
@@ -100,7 +100,7 @@ Rectangle {
100100 }
101101 StateChangeScript {
102102 script: {
103− GSettingsController.setUsageMode("com.canonical.Unity8", "Staged")
103+ GSettingsController.setUsageMode("Staged")
104104 }
105105 }
106106 },
@@ -117,7 +117,7 @@ Rectangle {
117117 }
118118 StateChangeScript {
119119 script: {
120− GSettingsController.setUsageMode("com.canonical.Unity8", "Windowed")
120+ GSettingsController.setUsageMode("Windowed")
121121 }
122122 }
123123 }
@@ -1034,6 +1034,11 @@ Rectangle {
10341034 tryCompare(ApplicationManager, "focusedApplicationId", "gallery-app");
10351035 compare(wizard.shown, false);
10361036 compare(tutorial.running, false);
1037+ tryCompare(AccountsService, "demoEdges", false);
1038+ tryCompare(Wizard.System, "wizardEnabled", false);
1039+
1040+ var tutorialLeft = findChild(tutorial, "tutorialLeft");
1041+ compare(tutorialLeft, null); // should be destroyed with tutorial
10371042 }
10381043
10391044 function test_tapOnRightEdgeReachesApplicationSurface() {
@@ -1131,10 +1136,10 @@ Rectangle {
11311136 var buttonShowDashHome = findChild(launcher, "buttonShowDashHome");
11321137 var startPos = buttonShowDashHome.mapToItem(shell,
11331138 buttonShowDashHome.width * 0.2,
1134− buttonShowDashHome.height * 0.2);
1139+ buttonShowDashHome.height * 0.8);
11351140 var endPos = buttonShowDashHome.mapToItem(shell,
11361141 buttonShowDashHome.width * 0.8,
1137− buttonShowDashHome.height * 0.8);
1142+ buttonShowDashHome.height * 0.2);
11381143 touchFlick(shell, startPos.x, startPos.y, endPos.x, endPos.y);
11391144 }
11401145
@@ -1167,7 +1172,7 @@ Rectangle {
11671172 loadShell("phone");
11681173 swipeAwayGreeter();
11691174 AccountsService.backgroundFile = data.accounts;
1170− GSettingsController.setPictureUri("org.gnome.desktop.background", data.gsettings);
1175+ GSettingsController.setPictureUri(data.gsettings);
11711176
11721177 if (data.output === "defaultBackground") {
11731178 tryCompare(shell, "background", shell.defaultBackground);