on xenial help sign in
merge trunk
6e1c315Michael Zanetti
debian/changelog+54
@@ -1,3 +1,57 @@
1+unity8 (8.00+14.10.20140908.1-0ubuntu1) utopic; urgency=low
2+
3+ [ Michał Sawicz ]
4+ * Use a single white pixel instead of the heavier checkers image.
5+ * Add support to unlock-device for the new adbd coming down the
6+ pipeline. Also fix autopilot tests and run scripts for that.
7+ * Make LVWPH non interactive while on header animation
8+ * Improve references to scope/scopeStyle in PreviewListView and
9+ PageHeader, add tests.
10+
11+ [ Nick Dedekind ]
12+ * Support for nested prompt session. (LP: #1358388)
13+
14+ [ Albert Astals ]
15+ * Remove unused hasAttributes variable
16+ * Disable dash overview if in temp scope preview
17+ * Block mouse events under scope overview bottombar (LP: #1362206)
18+ * Fix regression in focus handling due to SDK change
19+ * Fix warning 'Background.qml:81:21: Unable to assign bool to QUrl'
20+ * Fix launcher internationalization
21+ * Make swipe and home button press in the launcher dismiss the
22+ overview
23+ * GSV: Use proper variable since altnav renames
24+ * Fix some "Cannot read property 'luminance' of null" warnings
25+ * Make LVWPH non interactive while on header animation
26+
27+ [ Mirco Müller ]
28+ * Implemented the needed visual updates on notifications requested by
29+ Design for RTM. (LP: #1348092)
30+
31+ [ Michael Terry ]
32+ * Don't show greeter when screen turns off during a call, even if
33+ proximity sensor isn't active. (LP: #1347001)
34+ * Add support to unlock-device for the new adbd coming down the
35+ pipeline. Also fix autopilot tests and run scripts for that.
36+
37+ [ Michael Zanetti ]
38+ * open the application when clicking on the title entry in the
39+ quicklist (LP: #1336380)
40+ * Don't animate x while dragging apps from the left edge (LP:
41+ #1360105)
42+
43+ [ Diego Sarmentero ]
44+ * Reset button state on cancel (LP: #1362622)
45+
46+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 08 Sep 2014 14:16:42 +0000
47+
48+unity8 (8.00+14.10.20140903.1-0ubuntu1) utopic; urgency=low
49+
50+ [ Nick Dedekind ]
51+ * Support for nested prompt session. (LP: #1358388)
52+
53+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 03 Sep 2014 07:58:49 +0000
54+
1unity8 (8.00+14.10.20140828.1-0ubuntu1) utopic; urgency=low
55unity8 (8.00+14.10.20140828.1-0ubuntu1) utopic; urgency=low
2
56
3 [ Michael Terry ]
57 [ Michael Terry ]
debian/control+1−1
@@ -85,7 +85,7 @@ Depends: gsettings-desktop-schemas,
85 qmenumodel-qml (>= 0.2.8),
85 qmenumodel-qml (>= 0.2.8),
86 qml-module-qtquick-xmllistmodel,
86 qml-module-qtquick-xmllistmodel,
87 qtdeclarative5-gsettings1.0,
87 qtdeclarative5-gsettings1.0,
88− qtdeclarative5-qtmir-plugin (>= 0.4.1),
88+ qtdeclarative5-qtmir-plugin (>= 0.4.3),
89 qtdeclarative5-ubuntu-telephony0.1,
89 qtdeclarative5-ubuntu-telephony0.1,
90 unity-launcher-impl-3,
90 unity-launcher-impl-3,
91 unity8-common (= ${source:Version}),
91 unity8-common (= ${source:Version}),
plugins/AccountsService/AccountsService.qmltypes+1
@@ -26,5 +26,6 @@ Module {
26 Property { name: "backgroundFile"; type: "string"; isReadonly: true }
26 Property { name: "backgroundFile"; type: "string"; isReadonly: true }
27 Property { name: "statsWelcomeScreen"; type: "bool"; isReadonly: true }
27 Property { name: "statsWelcomeScreen"; type: "bool"; isReadonly: true }
28 Property { name: "passwordDisplayHint"; type: "PasswordDisplayHint"; isReadonly: true }
28 Property { name: "passwordDisplayHint"; type: "PasswordDisplayHint"; isReadonly: true }
29+ Property { name: "failedLogins"; type: "uint" }
29 }
30 }
30}
31}
plugins/Dash/CardCreator.js+2−2
@@ -440,14 +440,14 @@ function cardString(template, components) {
440 mascotCode = kMascotImageCode.arg(mascotAnchors).arg(mascotImageVisible);
440 mascotCode = kMascotImageCode.arg(mascotAnchors).arg(mascotImageVisible);
441 }
441 }
442
442
443− var summaryColorWithBackground = 'backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white")';
443+ var summaryColorWithBackground = 'backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white")';
444
444
445 var hasTitleContainer = hasTitle && (hasEmblem || (hasMascot && (hasSubtitle || hasAttributes)));
445 var hasTitleContainer = hasTitle && (hasEmblem || (hasMascot && (hasSubtitle || hasAttributes)));
446 var titleSubtitleCode = '';
446 var titleSubtitleCode = '';
447 if (hasTitle) {
447 if (hasTitle) {
448 var titleColor;
448 var titleColor;
449 if (headerAsOverlay) {
449 if (headerAsOverlay) {
450− titleColor = 'root.scopeStyle ? root.scopeStyle.getTextColor(overlayLoader.item.luminance) : (overlayLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white")';
450+ titleColor = 'root.scopeStyle && overlayLoader.item ? root.scopeStyle.getTextColor(overlayLoader.item.luminance) : (overlayLoader.item && overlayLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white")';
451 } else if (hasSummary) {
451 } else if (hasSummary) {
452 titleColor = 'summary.color';
452 titleColor = 'summary.color';
453 } else if (hasBackground) {
453 } else if (hasBackground) {
plugins/Dash/listviewwithpageheader.cpp+7−4
@@ -172,7 +172,7 @@ ListViewWithPageHeader::ListViewWithPageHeader()
172 connect(this, SIGNAL(contentWidthChanged()), this, SLOT(onContentWidthChanged()));
172 connect(this, SIGNAL(contentWidthChanged()), this, SLOT(onContentWidthChanged()));
173 connect(this, SIGNAL(contentHeightChanged()), this, SLOT(onContentHeightChanged()));
173 connect(this, SIGNAL(contentHeightChanged()), this, SLOT(onContentHeightChanged()));
174 connect(this, SIGNAL(heightChanged()), this, SLOT(onHeightChanged()));
174 connect(this, SIGNAL(heightChanged()), this, SLOT(onHeightChanged()));
175− connect(m_contentYAnimation, SIGNAL(stopped()), this, SLOT(onShowHeaderAnimationFinished()));
175+ connect(m_contentYAnimation, SIGNAL(runningChanged(bool)), this, SLOT(contentYAnimationRunningChanged(bool)));
176
176
177 setFlickableDirection(VerticalFlick);
177 setFlickableDirection(VerticalFlick);
178}
178}
@@ -1056,10 +1056,13 @@ void ListViewWithPageHeader::onModelUpdated(const QQmlChangeSet &changeSet, bool
1056 m_contentHeightDirty = true;
1056 m_contentHeightDirty = true;
1057}
1057}
1058
1058
1059−void ListViewWithPageHeader::onShowHeaderAnimationFinished()
1059+void ListViewWithPageHeader::contentYAnimationRunningChanged(bool running)
1060{
1060{
1061+ setInteractive(!running);
1062+ if (!running) {
1061− m_contentHeightDirty = true;
1063+ m_contentHeightDirty = true;
1062− polish();
1064+ polish();
1065+ }
1063}
1066}
1064
1067
1065void ListViewWithPageHeader::itemGeometryChanged(QQuickItem * /*item*/, const QRectF &newGeometry, const QRectF &oldGeometry)
1068void ListViewWithPageHeader::itemGeometryChanged(QQuickItem * /*item*/, const QRectF &newGeometry, const QRectF &oldGeometry)
plugins/Dash/listviewwithpageheader.h+1−1
@@ -118,7 +118,7 @@ private Q_SLOTS:
118 void onContentWidthChanged();
118 void onContentWidthChanged();
119 void onHeightChanged();
119 void onHeightChanged();
120 void onModelUpdated(const QQmlChangeSet &changeSet, bool reset);
120 void onModelUpdated(const QQmlChangeSet &changeSet, bool reset);
121− void onShowHeaderAnimationFinished();
121+ void contentYAnimationRunningChanged(bool running);
122
122
123private:
123private:
124 class ListItem
124 class ListItem
plugins/LightDM/LightDM.qmltypes+2
@@ -27,6 +27,7 @@ Module {
27 name: "showPrompt"
27 name: "showPrompt"
28 Parameter { name: "text"; type: "string" }
28 Parameter { name: "text"; type: "string" }
29 Parameter { name: "isSecret"; type: "bool" }
29 Parameter { name: "isSecret"; type: "bool" }
30+ Parameter { name: "isDefaultPrompt"; type: "bool" }
30 }
31 }
31 Signal { name: "authenticationComplete" }
32 Signal { name: "authenticationComplete" }
32 Signal {
33 Signal {
@@ -34,6 +35,7 @@ Module {
34 Parameter { name: "user"; type: "string" }
35 Parameter { name: "user"; type: "string" }
35 }
36 }
36 Signal { name: "isActiveChanged" }
37 Signal { name: "isActiveChanged" }
38+ Signal { name: "isAuthenticatedChanged" }
37 Signal { name: "showGreeter" }
39 Signal { name: "showGreeter" }
38 Signal {
40 Signal {
39 name: "requestAuthenticationUser"
41 name: "requestAuthenticationUser"
plugins/Powerd/Powerd.cpp+16−2
@@ -39,7 +39,8 @@ void dimTimeoutChanged(GSettings *settings, const gchar *key, QDBusInterface *un
39
39
40Powerd::Powerd(QObject* parent)
40Powerd::Powerd(QObject* parent)
41 : QObject(parent),
41 : QObject(parent),
42− unityScreen(nullptr)
42+ unityScreen(nullptr),
43+ cachedStatus(Status::On)
43{
44{
44 unityScreen = new QDBusInterface("com.canonical.Unity.Screen",
45 unityScreen = new QDBusInterface("com.canonical.Unity.Screen",
45 "/com/canonical/Unity/Screen",
46 "/com/canonical/Unity/Screen",
@@ -51,7 +52,7 @@ Powerd::Powerd(QObject* parent)
51 "com.canonical.Unity.Screen",
52 "com.canonical.Unity.Screen",
52 "DisplayPowerStateChange",
53 "DisplayPowerStateChange",
53 this,
54 this,
54− SIGNAL(displayPowerStateChange(int, int)));
55+ SLOT(handleDisplayPowerStateChange(int, int)));
55
56
56 systemSettings = g_settings_new("com.ubuntu.touch.system");
57 systemSettings = g_settings_new("com.ubuntu.touch.system");
57 g_signal_connect(systemSettings, "changed::auto-brightness", G_CALLBACK(autoBrightnessChanged), unityScreen);
58 g_signal_connect(systemSettings, "changed::auto-brightness", G_CALLBACK(autoBrightnessChanged), unityScreen);
@@ -67,3 +68,16 @@ Powerd::~Powerd()
67 g_signal_handlers_disconnect_by_data(systemSettings, unityScreen);
68 g_signal_handlers_disconnect_by_data(systemSettings, unityScreen);
68 g_object_unref(systemSettings);
69 g_object_unref(systemSettings);
69}
70}
71+
72+Powerd::Status Powerd::status() const
73+{
74+ return cachedStatus;
75+}
76+
77+void Powerd::handleDisplayPowerStateChange(int status, int reason)
78+{
79+ if (cachedStatus != (Status)status) {
80+ cachedStatus = (Status)status;
81+ Q_EMIT statusChanged((DisplayStateChangeReason)reason);
82+ }
83+}
plugins/Powerd/Powerd.h+8−1
@@ -29,6 +29,7 @@ class Powerd: public QObject
29 Q_OBJECT
29 Q_OBJECT
30 Q_ENUMS(Status)
30 Q_ENUMS(Status)
31 Q_ENUMS(DisplayStateChangeReason)
31 Q_ENUMS(DisplayStateChangeReason)
32+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
32
33
33public:
34public:
34 enum DisplayStateChangeReason {
35 enum DisplayStateChangeReason {
@@ -46,12 +47,18 @@ public:
46 explicit Powerd(QObject *parent = 0);
47 explicit Powerd(QObject *parent = 0);
47 ~Powerd();
48 ~Powerd();
48
49
50+ Status status() const;
51+
49Q_SIGNALS:
52Q_SIGNALS:
50− void displayPowerStateChange(int status, int reason);
53+ void statusChanged(DisplayStateChangeReason reason);
54+
55+private Q_SLOTS:
56+ void handleDisplayPowerStateChange(int status, int reason);
51
57
52private:
58private:
53 QDBusInterface *unityScreen;
59 QDBusInterface *unityScreen;
54 GSettings *systemSettings;
60 GSettings *systemSettings;
61+ Status cachedStatus;
55};
62};
56
63
57#endif
64#endif
plugins/Powerd/Powerd.qmltypes+3−3
@@ -30,10 +30,10 @@ Module {
30 "On": 1
30 "On": 1
31 }
31 }
32 }
32 }
33+ Property { name: "status"; type: "Status"; isReadonly: true }
33 Signal {
34 Signal {
34− name: "displayPowerStateChange"
35+ name: "statusChanged"
35− Parameter { name: "status"; type: "int" }
36− Parameter { name: "reason"; type: "int" }
36+ Parameter { name: "reason"; type: "DisplayStateChangeReason" }
37 }
37 }
38 }
38 }
39}
39}
plugins/Ubuntu/SystemImage/SystemImage.qmltypes+2
@@ -11,6 +11,8 @@ Module {
11 name: "SystemImage"
11 name: "SystemImage"
12 prototype: "QObject"
12 prototype: "QObject"
13 exports: ["Ubuntu.SystemImage/SystemImage 0.1"]
13 exports: ["Ubuntu.SystemImage/SystemImage 0.1"]
14+ isCreatable: false
15+ isSingleton: true
14 exportMetaObjectRevisions: [0]
16 exportMetaObjectRevisions: [0]
15 Method { name: "factoryReset" }
17 Method { name: "factoryReset" }
16 }
18 }
plugins/Unity/DashCommunicator/dashcommunicator.cpp+2−2
@@ -31,7 +31,7 @@ DashCommunicator::~DashCommunicator()
31}
31}
32
32
33
33
34−void DashCommunicator::setCurrentScope(const QString &scopeId, bool animate, bool reset)
34+void DashCommunicator::setCurrentScope(const QString &scopeId, bool animate, bool isSwipe)
35{
35{
36 QDBusConnection connection = QDBusConnection::sessionBus();
36 QDBusConnection connection = QDBusConnection::sessionBus();
37 QDBusInterface dashIface ("com.canonical.UnityDash",
37 QDBusInterface dashIface ("com.canonical.UnityDash",
@@ -39,5 +39,5 @@ void DashCommunicator::setCurrentScope(const QString &scopeId, bool animate, boo
39 "",
39 "",
40 connection);
40 connection);
41
41
42− dashIface.call("SetCurrentScope", scopeId, animate, reset);
42+ dashIface.call("SetCurrentScope", scopeId, animate, isSwipe);
43}
43}
plugins/Unity/DashCommunicator/dashcommunicator.h+1−1
@@ -29,7 +29,7 @@ public:
29 ~DashCommunicator();
29 ~DashCommunicator();
30
30
31public Q_SLOTS:
31public Q_SLOTS:
32− void setCurrentScope(const QString &scopeId, bool animate, bool reset);
32+ void setCurrentScope(const QString &scopeId, bool animate, bool isSwipe);
33};
33};
34
34
35#endif
35#endif
plugins/Unity/DashCommunicator/dashcommunicatorservice.h+1−1
@@ -29,7 +29,7 @@ public:
29 ~DashCommunicatorService();
29 ~DashCommunicatorService();
30
30
31Q_SIGNALS:
31Q_SIGNALS:
32− void setCurrentScopeRequested(const QString &scopeId, bool animate, bool reset);
32+ void setCurrentScopeRequested(const QString &scopeId, bool animate, bool isSwipe);
33
33
34private:
34private:
35 DBusDashCommunicatorService *m_dbusService;
35 DBusDashCommunicatorService *m_dbusService;
plugins/Unity/DashCommunicator/dbusdashcommunicatorservice.cpp+2−2
@@ -33,7 +33,7 @@ DBusDashCommunicatorService::~DBusDashCommunicatorService()
33{
33{
34}
34}
35
35
36−void DBusDashCommunicatorService::SetCurrentScope(const QString &scopeId, bool animate, bool reset)
36+void DBusDashCommunicatorService::SetCurrentScope(const QString &scopeId, bool animate, bool isSwipe)
37{
37{
38− Q_EMIT setCurrentScopeRequested(scopeId, animate, reset);
38+ Q_EMIT setCurrentScopeRequested(scopeId, animate, isSwipe);
39}
39}
plugins/Unity/DashCommunicator/dbusdashcommunicatorservice.h+2−2
@@ -29,10 +29,10 @@ public:
29 ~DBusDashCommunicatorService();
29 ~DBusDashCommunicatorService();
30
30
31Q_SIGNALS:
31Q_SIGNALS:
32− void setCurrentScopeRequested(const QString &scopeId, bool animate, bool reset);
32+ void setCurrentScopeRequested(const QString &scopeId, bool animate, bool isSwipe);
33
33
34public Q_SLOTS:
34public Q_SLOTS:
35− Q_SCRIPTABLE void SetCurrentScope(const QString &scopeId, bool animate, bool reset);
35+ Q_SCRIPTABLE void SetCurrentScope(const QString &scopeId, bool animate, bool isSwipe);
36
36
37};
37};
38
38
plugins/Unity/Indicators/Indicators.qmltypes+6−4
@@ -219,12 +219,14 @@ Module {
219 Method {
219 Method {
220 name: "model"
220 name: "model"
221 type: "UnityMenuModel*"
221 type: "UnityMenuModel*"
222− Parameter { name: "path"; type: "string" }
222+ Parameter { name: "bus"; type: "QByteArray" }
223+ Parameter { name: "path"; type: "QByteArray" }
224+ Parameter { name: "actions"; type: "QVariantMap" }
223 }
225 }
224 Method {
226 Method {
225− name: "registerModel"
227+ name: "contains"
228+ type: "bool"
226− Parameter { name: "path"; type: "string" }
229+ Parameter { name: "path"; type: "QByteArray" }
227− Parameter { name: "menuModel"; type: "UnityMenuModel"; isPointer: true }
228 }
230 }
229 }
231 }
230 Component {
232 Component {
plugins/Unity/Launcher/CMakeLists.txt+1−1
@@ -30,6 +30,6 @@ add_library(UnityLauncher-qml MODULE
30
30
31target_link_libraries(UnityLauncher-qml ${GSETTINGS_QT_LDFLAGS})
31target_link_libraries(UnityLauncher-qml ${GSETTINGS_QT_LDFLAGS})
32
32
33−qt5_use_modules(UnityLauncher-qml DBus Qml)
33+qt5_use_modules(UnityLauncher-qml DBus Qml Gui)
34
34
35add_unity8_plugin(Unity.Launcher 0.1 Unity/Launcher TARGETS UnityLauncher-qml)
35add_unity8_plugin(Unity.Launcher 0.1 Unity/Launcher TARGETS UnityLauncher-qml)
plugins/Unity/Launcher/backend/launcherbackend.cpp+7
@@ -28,6 +28,8 @@
28#include <QDebug>
28#include <QDebug>
29#include <QStandardPaths>
29#include <QStandardPaths>
30
30
31+#include <libintl.h>
32+
31class LauncherBackendItem
33class LauncherBackendItem
32{
34{
33public:
35public:
@@ -350,7 +352,12 @@ LauncherBackendItem* LauncherBackend::parseDesktopFile(const QString &desktopFil
350 QSettings settings(desktopFile, QSettings::IniFormat);
352 QSettings settings(desktopFile, QSettings::IniFormat);
351
353
352 LauncherBackendItem* item = new LauncherBackendItem();
354 LauncherBackendItem* item = new LauncherBackendItem();
355+
353 item->displayName = settings.value("Desktop Entry/Name").toString();
356 item->displayName = settings.value("Desktop Entry/Name").toString();
357+ const QString domain = settings.value("Desktop Entry/X-Ubuntu-Gettext-Domain").toString();
358+ if (!domain.isEmpty()) {
359+ item->displayName = dgettext(domain.toUtf8().constData(), item->displayName.toUtf8().constData());
360+ }
354
361
355 QString iconString = settings.value("Desktop Entry/Icon").toString();
362 QString iconString = settings.value("Desktop Entry/Icon").toString();
356 QString pathString = settings.value("Desktop Entry/Path").toString();
363 QString pathString = settings.value("Desktop Entry/Path").toString();
plugins/Unity/Launcher/launcheritem.cpp+1
@@ -36,6 +36,7 @@ LauncherItem::LauncherItem(const QString &appId, const QString &name, const QStr
36 m_quickList(new QuickListModel(this))
36 m_quickList(new QuickListModel(this))
37{
37{
38 QuickListEntry nameAction;
38 QuickListEntry nameAction;
39+ nameAction.setActionId("launch_item");
39 nameAction.setText(m_name);
40 nameAction.setText(m_name);
40 m_quickList->appendAction(nameAction);
41 m_quickList->appendAction(nameAction);
41 QuickListEntry pinningAction;
42 QuickListEntry pinningAction;
plugins/Unity/Launcher/launchermodel.cpp+3
@@ -23,6 +23,7 @@
23
23
24#include <unity/shell/application/ApplicationInfoInterface.h>
24#include <unity/shell/application/ApplicationInfoInterface.h>
25
25
26+#include <QDesktopServices>
26#include <QDebug>
27#include <QDebug>
27
28
28using namespace unity::shell::application;
29using namespace unity::shell::application;
@@ -191,6 +192,8 @@ void LauncherModel::quickListActionInvoked(const QString &appId, int actionIndex
191 } else {
192 } else {
192 pin(appId);
193 pin(appId);
193 }
194 }
195+ } else if (actionId == "launch_item") {
196+ QDesktopServices::openUrl(getUrlForAppId(appId));
194
197
195 // Nope, we don't know this action, let the backend forward it to the application
198 // Nope, we don't know this action, let the backend forward it to the application
196 } else {
199 } else {
po/am.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-09-02 07:20+0000\n"
17+"X-Launchpad-Export-Date: 2014-09-03 07:05+0000\n"
18−"X-Generator: Launchpad (build 17192)\n"
18+"X-Generator: Launchpad (build 17196)\n"
19
19
20#: plugins/LightDM/Greeter.cpp:130
20#: plugins/LightDM/Greeter.cpp:130
21msgid "Password: "
21msgid "Password: "
po/az.po+56−64
@@ -8,18 +8,18 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2014-08-26 18:24+0200\n"
10"POT-Creation-Date: 2014-08-26 18:24+0200\n"
11−"PO-Revision-Date: 2014-08-26 22:12+0000\n"
11+"PO-Revision-Date: 2014-09-03 16:39+0000\n"
12−"Last-Translator: Turan Mahmudov <turan.mahmudov@gmail.com>\n"
12+"Last-Translator: Nicat Məmmədov <n1c4t97@gmail.com>\n"
13"Language-Team: Azerbaijani <az@li.org>\n"
13"Language-Team: Azerbaijani <az@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-08-28 06:29+0000\n"
17+"X-Launchpad-Export-Date: 2014-09-04 08:35+0000\n"
18−"X-Generator: Launchpad (build 17174)\n"
18+"X-Generator: Launchpad (build 17196)\n"
19
19
20−#: plugins/LightDM/Greeter.cpp:129
20+#: plugins/LightDM/Greeter.cpp:130
21msgid "Password: "
21msgid "Password: "
22−msgstr "Parol: "
22+msgstr "Şifrә: "
23
23
24#: plugins/Unity/Launcher/launcheritem.cpp:43
24#: plugins/Unity/Launcher/launcheritem.cpp:43
25#: plugins/Unity/Launcher/launcheritem.cpp:73
25#: plugins/Unity/Launcher/launcheritem.cpp:73
@@ -32,37 +32,37 @@ msgstr "Açma qısayolu"
32
32
33#: qml/Components/Dialogs.qml:70
33#: qml/Components/Dialogs.qml:70
34msgid "Log out"
34msgid "Log out"
35−msgstr ""
35+msgstr "Çıxış"
36
36
37#: qml/Components/Dialogs.qml:71
37#: qml/Components/Dialogs.qml:71
38msgid "Are you sure you want to log out?"
38msgid "Are you sure you want to log out?"
39−msgstr ""
39+msgstr "Çıxmaq istәdiyinizdәn әminsiniz?"
40
40
41#: qml/Components/Dialogs.qml:73 qml/Components/Dialogs.qml:97
41#: qml/Components/Dialogs.qml:73 qml/Components/Dialogs.qml:97
42#: qml/Components/Dialogs.qml:122
42#: qml/Components/Dialogs.qml:122
43msgid "No"
43msgid "No"
44−msgstr ""
44+msgstr "Yox"
45
45
46#: qml/Components/Dialogs.qml:80 qml/Components/Dialogs.qml:104
46#: qml/Components/Dialogs.qml:80 qml/Components/Dialogs.qml:104
47#: qml/Components/Dialogs.qml:129
47#: qml/Components/Dialogs.qml:129
48msgid "Yes"
48msgid "Yes"
49−msgstr ""
49+msgstr "Hə"
50
50
51#: qml/Components/Dialogs.qml:94
51#: qml/Components/Dialogs.qml:94
52msgid "Shut down"
52msgid "Shut down"
53−msgstr ""
53+msgstr "Sistemi Söndür"
54
54
55#: qml/Components/Dialogs.qml:95
55#: qml/Components/Dialogs.qml:95
56msgid "Are you sure you want to shut down?"
56msgid "Are you sure you want to shut down?"
57−msgstr ""
57+msgstr "Sistemi söndürmәk istәdiyinizә әminsiniz?"
58
58
59#: qml/Components/Dialogs.qml:119
59#: qml/Components/Dialogs.qml:119
60msgid "Reboot"
60msgid "Reboot"
61−msgstr ""
61+msgstr "Yenidən yüklə"
62
62
63#: qml/Components/Dialogs.qml:120
63#: qml/Components/Dialogs.qml:120
64msgid "Are you sure you want to reboot?"
64msgid "Are you sure you want to reboot?"
65−msgstr ""
65+msgstr "Yenidәn başlatmaq istәdiyinizә әminsiniz?"
66
66
67#: qml/Components/Dialogs.qml:144
67#: qml/Components/Dialogs.qml:144
68msgid "Power"
68msgid "Power"
@@ -74,17 +74,17 @@ msgid ""
74"to power off?"
74"to power off?"
75msgstr ""
75msgstr ""
76
76
77−#: qml/Components/Dialogs.qml:144
77+#: qml/Components/Dialogs.qml:147
78msgid "Power off"
78msgid "Power off"
79msgstr "Söndür"
79msgstr "Söndür"
80
80
81−#: qml/Components/Dialogs.qml:162
81+#: qml/Components/Dialogs.qml:157
82msgid "Cancel"
82msgid "Cancel"
83msgstr "İmtina"
83msgstr "İmtina"
84
84
85#: qml/Components/EdgeDemoOverlay.qml:151
85#: qml/Components/EdgeDemoOverlay.qml:151
86msgid "Skip intro"
86msgid "Skip intro"
87−msgstr "Intro -nu keç"
87+msgstr "Tәqdimatı keç"
88
88
89#: qml/Components/EdgeDemo.qml:112
89#: qml/Components/EdgeDemo.qml:112
90msgid "Right edge"
90msgid "Right edge"
@@ -92,7 +92,7 @@ msgstr "Sağ Künc"
92
92
93#: qml/Components/EdgeDemo.qml:113
93#: qml/Components/EdgeDemo.qml:113
94msgid "Try swiping from the right edge to unlock the phone"
94msgid "Try swiping from the right edge to unlock the phone"
95−msgstr "Kilidi açmaq üçün sağ küncdən çəkin"
95+msgstr "Kilidi açmaq üçün sağ küncdən sürüşdürün"
96
96
97#: qml/Components/EdgeDemo.qml:144
97#: qml/Components/EdgeDemo.qml:144
98msgid "Top edge"
98msgid "Top edge"
@@ -100,7 +100,7 @@ msgstr "Yuxarı künc"
100
100
101#: qml/Components/EdgeDemo.qml:145
101#: qml/Components/EdgeDemo.qml:145
102msgid "Try swiping from the top edge to access the indicators"
102msgid "Try swiping from the top edge to access the indicators"
103−msgstr "Göstəricilərə keçid üçün yuxarı küncdən çəkin"
103+msgstr "Göstəriciləri görmәk üçün yuxarı küncdən sürüşdürün"
104
104
105#: qml/Components/EdgeDemo.qml:170
105#: qml/Components/EdgeDemo.qml:170
106msgid "Close"
106msgid "Close"
@@ -108,7 +108,7 @@ msgstr "Bağla"
108
108
109#: qml/Components/EdgeDemo.qml:171
109#: qml/Components/EdgeDemo.qml:171
110msgid "Swipe up again to close the settings screen"
110msgid "Swipe up again to close the settings screen"
111−msgstr "Nizamlamalar ekranını bağlamaq üçün yenidən yuxarı çəkin"
111+msgstr "Nizamlamalar ekranını bağlamaq üçün yenidən yuxarı sürüşdürün"
112
112
113#: qml/Components/EdgeDemo.qml:198
113#: qml/Components/EdgeDemo.qml:198
114msgid "Left edge"
114msgid "Left edge"
@@ -128,16 +128,16 @@ msgid ""
128"You have now mastered the edge gestures and can start using the "
128"You have now mastered the edge gestures and can start using the "
129"phone<br><br>Tap on the screen to start"
129"phone<br><br>Tap on the screen to start"
130msgstr ""
130msgstr ""
131−"Siz künc jestlərini mənimsəmisiniz və telefonu istifadə etməyə başlaya "
131+"Siz künc hәrәkәtlәrini öyrәndiniz və telefonu istifadə etməyə başlaya "
132"bilərsiniz.<br><br>Başlamaq üçün ekrana toxunun"
132"bilərsiniz.<br><br>Başlamaq üçün ekrana toxunun"
133
133
134#: qml/Components/Lockscreen.qml:167
134#: qml/Components/Lockscreen.qml:167
135msgid "Please wait"
135msgid "Please wait"
136−msgstr "Lütfən gözləyin"
136+msgstr "Xahiş edirik gözləyin"
137
137
138#: qml/Components/Lockscreen.qml:172
138#: qml/Components/Lockscreen.qml:172
139msgid "Too many incorrect attempts"
139msgid "Too many incorrect attempts"
140−msgstr "Çoxlu yanlış cəhd"
140+msgstr "Çoxlu yanlış cəhdlәr"
141
141
142#: qml/Components/Lockscreen.qml:206
142#: qml/Components/Lockscreen.qml:206
143msgid "Emergency Call"
143msgid "Emergency Call"
@@ -145,44 +145,45 @@ msgstr "Zərurət zəngi"
145
145
146#: qml/Components/Lockscreen.qml:226
146#: qml/Components/Lockscreen.qml:226
147msgid "OK"
147msgid "OK"
148−msgstr "ОК"
148+msgstr "Oldu"
149
149
150#: qml/Components/PassphraseLockscreen.qml:61
150#: qml/Components/PassphraseLockscreen.qml:61
151#, qt-format
151#, qt-format
152msgid "Hello %1"
152msgid "Hello %1"
153−msgstr "Xoş gördük %1"
153+msgstr "Salam %1"
154
154
155#: qml/Components/PassphraseLockscreen.qml:61
155#: qml/Components/PassphraseLockscreen.qml:61
156msgid "Hello"
156msgid "Hello"
157−msgstr "Xoş gördük"
157+msgstr "Salam"
158
158
159#: qml/Dash/GenericScopeView.qml:361
159#: qml/Dash/GenericScopeView.qml:361
160msgid "See less"
160msgid "See less"
161−msgstr "Daha az gör"
161+msgstr "Daha azını gör"
162
162
163#: qml/Dash/GenericScopeView.qml:361
163#: qml/Dash/GenericScopeView.qml:361
164msgid "See all"
164msgid "See all"
165msgstr "Hamısını gör"
165msgstr "Hamısını gör"
166
166
167−#: qml/Dash/GenericScopeView.qml:424 qml/Panel/SearchIndicator.qml:27
167+#: qml/Dash/GenericScopeView.qml:424 qml/Dash/PageHeader.qml:260
168+#: qml/Panel/SearchIndicator.qml:27
168msgid "Search"
169msgid "Search"
169msgstr "Axtar"
170msgstr "Axtar"
170
171
171#: qml/Dash/PageHeader.qml:270
172#: qml/Dash/PageHeader.qml:270
172msgid "Settings"
173msgid "Settings"
173−msgstr ""
174+msgstr "Tənzimləmələr"
174
175
175#: qml/Dash/PageHeader.qml:279
176#: qml/Dash/PageHeader.qml:279
176msgid "Remove from Favorites"
177msgid "Remove from Favorites"
177−msgstr ""
178+msgstr "Seçilmişlәrdәn çıxart"
178
179
179#: qml/Dash/PageHeader.qml:279
180#: qml/Dash/PageHeader.qml:279
180msgid "Add to Favorites"
181msgid "Add to Favorites"
181−msgstr ""
182+msgstr "Seçilmişlәrә әlavә et"
182
183
183#: qml/Dash/Previews/PreviewActionCombo.qml:34
184#: qml/Dash/Previews/PreviewActionCombo.qml:34
184msgid "More..."
185msgid "More..."
185−msgstr "Ətraflı..."
186+msgstr "Daha çox..."
186
187
187#: qml/Dash/Previews/PreviewActionCombo.qml:34
188#: qml/Dash/Previews/PreviewActionCombo.qml:34
188msgid "Less..."
189msgid "Less..."
@@ -190,7 +191,7 @@ msgstr "Az..."
190
191
191#: qml/Dash/Previews/PreviewRatingInput.qml:81
192#: qml/Dash/Previews/PreviewRatingInput.qml:81
192msgid "Rate this"
193msgid "Rate this"
193−msgstr "Qiymət ver"
194+msgstr "Qiymәtlәndir"
194
195
195#: qml/Dash/Previews/PreviewRatingInput.qml:126
196#: qml/Dash/Previews/PreviewRatingInput.qml:126
196msgid "Add a review"
197msgid "Add a review"
@@ -204,13 +205,13 @@ msgstr "Göndər"
204msgid "Manage Dash"
205msgid "Manage Dash"
205msgstr ""
206msgstr ""
206
207
207−#: qml/Dash/ScopesOverview.qml:408
208+#: qml/Dash/ScopesOverview.qml:417
208msgid "Done"
209msgid "Done"
209msgstr "Başa çatdı"
210msgstr "Başa çatdı"
210
211
211−#: qml/Dash/ScopesOverview.qml:434
212+#: qml/Dash/ScopesOverview.qml:443
212msgid "Store"
213msgid "Store"
213−msgstr "Saxla"
214+msgstr ""
214
215
215#: qml/Dash/ScopesOverviewTab.qml:36
216#: qml/Dash/ScopesOverviewTab.qml:36
216msgid "Favorites"
217msgid "Favorites"
@@ -224,13 +225,13 @@ msgstr "Hamısı"
224msgid "Swipe to unlock"
225msgid "Swipe to unlock"
225msgstr "Kilidi açmaq üçün sürüşdürün"
226msgstr "Kilidi açmaq üçün sürüşdürün"
226
227
227−#: qml/Hud/HudParametrizedActionsPage.qml:132
228+#: qml/Hud/HudParametrizedActionsPage.qml:139
228msgid "Confirm"
229msgid "Confirm"
229msgstr "Təsdiqlə"
230msgstr "Təsdiqlə"
230
231
231#: qml/Hud/Hud.qml:61 qml/Hud/Hud.qml:99 qml/Hud/Hud.qml:372
232#: qml/Hud/Hud.qml:61 qml/Hud/Hud.qml:99 qml/Hud/Hud.qml:372
232msgid "Type or say a command"
233msgid "Type or say a command"
233−msgstr "Əmri söyləyin və ya yazın"
234+msgstr "Bir әmr söyləyin və ya yazın"
234
235
235#: qml/Hud/Hud.qml:84
236#: qml/Hud/Hud.qml:84
236msgid "Loading. Please Wait..."
237msgid "Loading. Please Wait..."
@@ -246,15 +247,15 @@ msgstr "Danışır..."
246
247
247#: qml/Notifications/NotificationMenuItemFactory.qml:105
248#: qml/Notifications/NotificationMenuItemFactory.qml:105
248msgid "Show password"
249msgid "Show password"
249−msgstr "Parolu göstər"
250+msgstr "Şifrәni göstәr"
250
251
251#: qml/Notifications/NotificationMenuItemFactory.qml:120
252#: qml/Notifications/NotificationMenuItemFactory.qml:120
252msgid "Enter SIM PIN"
253msgid "Enter SIM PIN"
253msgstr "SIM PIN kodunuzu daxil edin"
254msgstr "SIM PIN kodunuzu daxil edin"
254
255
255−#: qml/Notifications/NotificationMenuItemFactory.qml:121 qml/Shell.qml:270
256+#: qml/Notifications/NotificationMenuItemFactory.qml:121
256msgid "Sorry, incorrect PIN"
257msgid "Sorry, incorrect PIN"
257−msgstr "Təəssüf ki, PIN yanlışdır"
258+msgstr "Bağışlayın, PIN yanlışdır"
258
259
259#: qml/Panel/ActiveCallHint.qml:77
260#: qml/Panel/ActiveCallHint.qml:77
260msgid "Tap to return to call..."
261msgid "Tap to return to call..."
@@ -274,7 +275,7 @@ msgstr "Endirilir"
274
275
275#: qml/Panel/Indicators/MenuItemFactory.qml:657
276#: qml/Panel/Indicators/MenuItemFactory.qml:657
276msgid "Paused, tap to resume"
277msgid "Paused, tap to resume"
277−msgstr "Saxlanıldı, davam etmək üçün toxunun"
278+msgstr "Dayandırıldı. Davam etmək üçün toxunun"
278
279
279#: qml/Panel/Indicators/MenuItemFactory.qml:659
280#: qml/Panel/Indicators/MenuItemFactory.qml:659
280msgid "Canceled"
281msgid "Canceled"
@@ -286,7 +287,7 @@ msgstr "Bitdi"
286
287
287#: qml/Panel/Indicators/MenuItemFactory.qml:663
288#: qml/Panel/Indicators/MenuItemFactory.qml:663
288msgid "Failed, tap to retry"
289msgid "Failed, tap to retry"
289−msgstr "Alınmadı, davam etmək üçün toxunun"
290+msgstr "Alınmadı. Yenidәn cәhd etmək üçün toxunun"
290
291
291#: qml/Panel/Indicators/ModemInfoItem.qml:105
292#: qml/Panel/Indicators/ModemInfoItem.qml:105
292msgid "Unlock SIM"
293msgid "Unlock SIM"
@@ -296,13 +297,13 @@ msgstr "SIM kilidini aç"
296msgid "Roaming"
297msgid "Roaming"
297msgstr "Rominq"
298msgstr "Rominq"
298
299
299−#: qml/Shell.qml:266
300+#: qml/Shell.qml:279
300msgid "Enter your passphrase"
301msgid "Enter your passphrase"
301msgstr "Açar sözünüzü daxil edin"
302msgstr "Açar sözünüzü daxil edin"
302
303
303−#: qml/Shell.qml:267
304+#: qml/Shell.qml:280
304msgid "Sorry, incorrect passphrase"
305msgid "Sorry, incorrect passphrase"
305−msgstr "Təəssüf ki, açar söz yanlışdır"
306+msgstr "Bağışlayın, açar söz yanlışdır"
306
307
307#: qml/Shell.qml:282
308#: qml/Shell.qml:282
308msgid "Enter your passcode"
309msgid "Enter your passcode"
@@ -312,29 +313,29 @@ msgstr ""
312msgid "Sorry, incorrect passcode"
313msgid "Sorry, incorrect passcode"
313msgstr ""
314msgstr ""
314
315
315−#: qml/Shell.qml:273
316+#: qml/Shell.qml:286
316#, qt-format
317#, qt-format
317msgid "Enter your %1"
318msgid "Enter your %1"
318msgstr "%1 daxil edin"
319msgstr "%1 daxil edin"
319
320
320−#: qml/Shell.qml:274
321+#: qml/Shell.qml:287
321#, qt-format
322#, qt-format
322msgid "Sorry, incorrect %1"
323msgid "Sorry, incorrect %1"
323−msgstr "Təəssüf ki, %1 yanlışdır"
324+msgstr "Bağışlayın, %1 yanlışdır"
324
325
325−#: qml/Shell.qml:310
326+#: qml/Shell.qml:323
326msgid "Sorry, incorrect passphrase."
327msgid "Sorry, incorrect passphrase."
327−msgstr "Təəssüf ki, açar söz yanlışdır."
328+msgstr "Bağışlayın, açar söz yanlışdır."
328
329
329−#: qml/Shell.qml:311
330+#: qml/Shell.qml:324
330msgid "Sorry, incorrect passcode."
331msgid "Sorry, incorrect passcode."
331msgstr "Təəssüf ki, açar kod yanlışdır."
332msgstr "Təəssüf ki, açar kod yanlışdır."
332
333
333−#: qml/Shell.qml:312
334+#: qml/Shell.qml:325
334msgid "This will be your last attempt."
335msgid "This will be your last attempt."
335msgstr "Bu sizin son cəhdiniz olacaq."
336msgstr "Bu sizin son cəhdiniz olacaq."
336
337
337−#: qml/Shell.qml:314
338+#: qml/Shell.qml:327
338msgid ""
339msgid ""
339"If passphrase is entered incorrectly, your phone will conduct a factory "
340"If passphrase is entered incorrectly, your phone will conduct a factory "
340"reset and all personal data will be deleted."
341"reset and all personal data will be deleted."
@@ -342,19 +343,10 @@ msgstr ""
342"Əgər açar söz yanlış daxil edilibsə, onda telefonunuz fabrika parametrlərinə "
343"Əgər açar söz yanlış daxil edilibsə, onda telefonunuz fabrika parametrlərinə "
343"geri qayıdacaq və bütün şəxsi məlumatlarınız silinəcək."
344"geri qayıdacaq və bütün şəxsi məlumatlarınız silinəcək."
344
345
345−#: qml/Shell.qml:315
346+#: qml/Shell.qml:328
346msgid ""
347msgid ""
347"If passcode is entered incorrectly, your phone will conduct a factory reset "
348"If passcode is entered incorrectly, your phone will conduct a factory reset "
348"and all personal data will be deleted."
349"and all personal data will be deleted."
349msgstr ""
350msgstr ""
350"Əgər açar kod yanlış daxil edilibsə, onda telefonunuz fabrika parametrlərinə "
351"Əgər açar kod yanlış daxil edilibsə, onda telefonunuz fabrika parametrlərinə "
351"geri qayıdacaq və bütün şəxsi məlumatlarınız silinəcək."
352"geri qayıdacaq və bütün şəxsi məlumatlarınız silinəcək."
352−
353−#~ msgid "Are you sure you would like to turn power off?"
354−#~ msgstr "Söndürmək istədiyinizə əminsiniz?"
355−
356−#~ msgid "Restart"
357−#~ msgstr "Yenidən Başlat"
358−
359−#~ msgid "Enter your PIN"
360−#~ msgstr "PIN kodunuzu daxil edin"
po/ca.po+8−6
@@ -8,14 +8,14 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2014-08-26 18:24+0200\n"
10"POT-Creation-Date: 2014-08-26 18:24+0200\n"
11−"PO-Revision-Date: 2014-09-01 01:01+0000\n"
11+"PO-Revision-Date: 2014-09-07 04:05+0000\n"
12"Last-Translator: David Planella <david.planella@ubuntu.com>\n"
12"Last-Translator: David Planella <david.planella@ubuntu.com>\n"
13"Language-Team: Catalan <ca@li.org>\n"
13"Language-Team: Catalan <ca@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-09-01 07:33+0000\n"
17+"X-Launchpad-Export-Date: 2014-09-08 06:58+0000\n"
18−"X-Generator: Launchpad (build 17176)\n"
18+"X-Generator: Launchpad (build 17196)\n"
19
19
20#: plugins/LightDM/Greeter.cpp:130
20#: plugins/LightDM/Greeter.cpp:130
21msgid "Password: "
21msgid "Password: "
@@ -50,11 +50,11 @@ msgstr "Sí"
50
50
51#: qml/Components/Dialogs.qml:94
51#: qml/Components/Dialogs.qml:94
52msgid "Shut down"
52msgid "Shut down"
53−msgstr ""
53+msgstr "Apaga"
54
54
55#: qml/Components/Dialogs.qml:95
55#: qml/Components/Dialogs.qml:95
56msgid "Are you sure you want to shut down?"
56msgid "Are you sure you want to shut down?"
57−msgstr ""
57+msgstr "Segur que voleu apagar?"
58
58
59#: qml/Components/Dialogs.qml:119
59#: qml/Components/Dialogs.qml:119
60msgid "Reboot"
60msgid "Reboot"
@@ -73,10 +73,12 @@ msgid ""
73"Are you sure you would like\n"
73"Are you sure you would like\n"
74"to power off?"
74"to power off?"
75msgstr ""
75msgstr ""
76+"Segur que voleu\n"
77+"apagar?"
76
78
77#: qml/Components/Dialogs.qml:147
79#: qml/Components/Dialogs.qml:147
78msgid "Power off"
80msgid "Power off"
79−msgstr "Apaga'l"
81+msgstr "Apaga"
80
82
81#: qml/Components/Dialogs.qml:157
83#: qml/Components/Dialogs.qml:157
82msgid "Cancel"
84msgid "Cancel"
po/de.po+7−7
@@ -8,14 +8,14 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2014-08-26 18:24+0200\n"
10"POT-Creation-Date: 2014-08-26 18:24+0200\n"
11−"PO-Revision-Date: 2014-08-29 13:00+0000\n"
11+"PO-Revision-Date: 2014-09-04 15:02+0000\n"
12−"Last-Translator: Martin Pitt <martin.pitt@ubuntu.com>\n"
12+"Last-Translator: Niklas Wenzel <nikwen.developer@gmail.com>\n"
13"Language-Team: German <de@li.org>\n"
13"Language-Team: German <de@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-08-30 07:46+0000\n"
17+"X-Launchpad-Export-Date: 2014-09-05 07:50+0000\n"
18−"X-Generator: Launchpad (build 17176)\n"
18+"X-Generator: Launchpad (build 17196)\n"
19
19
20#: plugins/LightDM/Greeter.cpp:130
20#: plugins/LightDM/Greeter.cpp:130
21msgid "Password: "
21msgid "Password: "
@@ -36,7 +36,7 @@ msgstr "Abmelden"
36
36
37#: qml/Components/Dialogs.qml:71
37#: qml/Components/Dialogs.qml:71
38msgid "Are you sure you want to log out?"
38msgid "Are you sure you want to log out?"
39−msgstr "Sind Sie sicher dass Sie sich abmelden wollen?"
39+msgstr "Sind Sie sicher, dass Sie sich abmelden wollen?"
40
40
41#: qml/Components/Dialogs.qml:73 qml/Components/Dialogs.qml:97
41#: qml/Components/Dialogs.qml:73 qml/Components/Dialogs.qml:97
42#: qml/Components/Dialogs.qml:122
42#: qml/Components/Dialogs.qml:122
@@ -54,7 +54,7 @@ msgstr "Herunterfahren"
54
54
55#: qml/Components/Dialogs.qml:95
55#: qml/Components/Dialogs.qml:95
56msgid "Are you sure you want to shut down?"
56msgid "Are you sure you want to shut down?"
57−msgstr "Sind Sie sicher dass Sie ausschalten wollen?"
57+msgstr "Sind Sie sicher, dass Sie herunterfahren wollen?"
58
58
59#: qml/Components/Dialogs.qml:119
59#: qml/Components/Dialogs.qml:119
60msgid "Reboot"
60msgid "Reboot"
@@ -62,7 +62,7 @@ msgstr "Neustart"
62
62
63#: qml/Components/Dialogs.qml:120
63#: qml/Components/Dialogs.qml:120
64msgid "Are you sure you want to reboot?"
64msgid "Are you sure you want to reboot?"
65−msgstr "Sind Sie sicher dass Sie neu starten wollen?"
65+msgstr "Sind Sie sicher, dass Sie neu starten wollen?"
66
66
67#: qml/Components/Dialogs.qml:144
67#: qml/Components/Dialogs.qml:144
68msgid "Power"
68msgid "Power"
po/es.po+39−45
@@ -8,16 +8,16 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2014-08-26 18:24+0200\n"
10"POT-Creation-Date: 2014-08-26 18:24+0200\n"
11−"PO-Revision-Date: 2014-08-27 15:20+0000\n"
11+"PO-Revision-Date: 2014-09-02 08:16+0000\n"
12−"Last-Translator: Leo Arias <leo.arias@canonical.com>\n"
12+"Last-Translator: Víctor R. Ruiz <Unknown>\n"
13"Language-Team: Spanish <es@li.org>\n"
13"Language-Team: Spanish <es@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-08-28 06:30+0000\n"
17+"X-Launchpad-Export-Date: 2014-09-03 07:05+0000\n"
18−"X-Generator: Launchpad (build 17174)\n"
18+"X-Generator: Launchpad (build 17196)\n"
19
19
20−#: plugins/LightDM/Greeter.cpp:129
20+#: plugins/LightDM/Greeter.cpp:130
21msgid "Password: "
21msgid "Password: "
22msgstr "Contraseña: "
22msgstr "Contraseña: "
23
23
@@ -32,53 +32,55 @@ msgstr "Desanclar"
32
32
33#: qml/Components/Dialogs.qml:70
33#: qml/Components/Dialogs.qml:70
34msgid "Log out"
34msgid "Log out"
35−msgstr ""
35+msgstr "Cerrar la sesión"
36
36
37#: qml/Components/Dialogs.qml:71
37#: qml/Components/Dialogs.qml:71
38msgid "Are you sure you want to log out?"
38msgid "Are you sure you want to log out?"
39−msgstr ""
39+msgstr "̉¿Está seguro de que quiere cerrar la sesión?"
40
40
41#: qml/Components/Dialogs.qml:73 qml/Components/Dialogs.qml:97
41#: qml/Components/Dialogs.qml:73 qml/Components/Dialogs.qml:97
42#: qml/Components/Dialogs.qml:122
42#: qml/Components/Dialogs.qml:122
43msgid "No"
43msgid "No"
44−msgstr ""
44+msgstr "No"
45
45
46#: qml/Components/Dialogs.qml:80 qml/Components/Dialogs.qml:104
46#: qml/Components/Dialogs.qml:80 qml/Components/Dialogs.qml:104
47#: qml/Components/Dialogs.qml:129
47#: qml/Components/Dialogs.qml:129
48msgid "Yes"
48msgid "Yes"
49−msgstr ""
49+msgstr "Sí"
50
50
51#: qml/Components/Dialogs.qml:94
51#: qml/Components/Dialogs.qml:94
52msgid "Shut down"
52msgid "Shut down"
53−msgstr ""
53+msgstr "Apagar"
54
54
55#: qml/Components/Dialogs.qml:95
55#: qml/Components/Dialogs.qml:95
56msgid "Are you sure you want to shut down?"
56msgid "Are you sure you want to shut down?"
57−msgstr ""
57+msgstr "¿Está seguro de que quiere apagar?"
58
58
59#: qml/Components/Dialogs.qml:119
59#: qml/Components/Dialogs.qml:119
60msgid "Reboot"
60msgid "Reboot"
61−msgstr ""
61+msgstr "Reiniciar"
62
62
63#: qml/Components/Dialogs.qml:120
63#: qml/Components/Dialogs.qml:120
64msgid "Are you sure you want to reboot?"
64msgid "Are you sure you want to reboot?"
65−msgstr ""
65+msgstr "¿Esta seguro de que quiere reiniciar?"
66
66
67#: qml/Components/Dialogs.qml:144
67#: qml/Components/Dialogs.qml:144
68msgid "Power"
68msgid "Power"
69−msgstr ""
69+msgstr "Encendido"
70
70
71#: qml/Components/Dialogs.qml:145
71#: qml/Components/Dialogs.qml:145
72msgid ""
72msgid ""
73"Are you sure you would like\n"
73"Are you sure you would like\n"
74"to power off?"
74"to power off?"
75msgstr ""
75msgstr ""
76+"¿Está seguro de que quiere\n"
77+"apagar?"
76
78
77−#: qml/Components/Dialogs.qml:144
79+#: qml/Components/Dialogs.qml:147
78msgid "Power off"
80msgid "Power off"
79msgstr "Apagar"
81msgstr "Apagar"
80
82
81−#: qml/Components/Dialogs.qml:162
83+#: qml/Components/Dialogs.qml:157
82msgid "Cancel"
84msgid "Cancel"
83msgstr "Cancelar"
85msgstr "Cancelar"
84
86
@@ -166,21 +168,22 @@ msgstr "Ver menos"
166msgid "See all"
168msgid "See all"
167msgstr "Ver todo"
169msgstr "Ver todo"
168
170
169−#: qml/Dash/GenericScopeView.qml:424 qml/Panel/SearchIndicator.qml:27
171+#: qml/Dash/GenericScopeView.qml:424 qml/Dash/PageHeader.qml:260
172+#: qml/Panel/SearchIndicator.qml:27
170msgid "Search"
173msgid "Search"
171msgstr "Buscar"
174msgstr "Buscar"
172
175
173#: qml/Dash/PageHeader.qml:270
176#: qml/Dash/PageHeader.qml:270
174msgid "Settings"
177msgid "Settings"
175−msgstr ""
178+msgstr "Configuración"
176
179
177#: qml/Dash/PageHeader.qml:279
180#: qml/Dash/PageHeader.qml:279
178msgid "Remove from Favorites"
181msgid "Remove from Favorites"
179−msgstr ""
182+msgstr "Quitar de favoritos"
180
183
181#: qml/Dash/PageHeader.qml:279
184#: qml/Dash/PageHeader.qml:279
182msgid "Add to Favorites"
185msgid "Add to Favorites"
183−msgstr ""
186+msgstr "Añadir a favoritos"
184
187
185#: qml/Dash/Previews/PreviewActionCombo.qml:34
188#: qml/Dash/Previews/PreviewActionCombo.qml:34
186msgid "More..."
189msgid "More..."
@@ -206,11 +209,11 @@ msgstr "Enviar"
206msgid "Manage Dash"
209msgid "Manage Dash"
207msgstr "Gestionar tablero"
210msgstr "Gestionar tablero"
208
211
209−#: qml/Dash/ScopesOverview.qml:408
212+#: qml/Dash/ScopesOverview.qml:417
210msgid "Done"
213msgid "Done"
211msgstr "Hecho"
214msgstr "Hecho"
212
215
213−#: qml/Dash/ScopesOverview.qml:434
216+#: qml/Dash/ScopesOverview.qml:443
214msgid "Store"
217msgid "Store"
215msgstr "Tienda"
218msgstr "Tienda"
216
219
@@ -226,7 +229,7 @@ msgstr "Todo"
226msgid "Swipe to unlock"
229msgid "Swipe to unlock"
227msgstr "Deslice para desbloquear"
230msgstr "Deslice para desbloquear"
228
231
229−#: qml/Hud/HudParametrizedActionsPage.qml:132
232+#: qml/Hud/HudParametrizedActionsPage.qml:139
230msgid "Confirm"
233msgid "Confirm"
231msgstr "Confirmar"
234msgstr "Confirmar"
232
235
@@ -254,7 +257,7 @@ msgstr "Mostrar contraseña"
254msgid "Enter SIM PIN"
257msgid "Enter SIM PIN"
255msgstr "Escriba el PIN de la SIM"
258msgstr "Escriba el PIN de la SIM"
256
259
257−#: qml/Notifications/NotificationMenuItemFactory.qml:121 qml/Shell.qml:270
260+#: qml/Notifications/NotificationMenuItemFactory.qml:121
258msgid "Sorry, incorrect PIN"
261msgid "Sorry, incorrect PIN"
259msgstr "El PIN es incorrecto"
262msgstr "El PIN es incorrecto"
260
263
@@ -298,45 +301,45 @@ msgstr "Desbloquear SIM"
298msgid "Roaming"
301msgid "Roaming"
299msgstr "Itinerancia"
302msgstr "Itinerancia"
300
303
301−#: qml/Shell.qml:266
304+#: qml/Shell.qml:279
302msgid "Enter your passphrase"
305msgid "Enter your passphrase"
303msgstr "Introudzca su contraseña"
306msgstr "Introudzca su contraseña"
304
307
305−#: qml/Shell.qml:267
308+#: qml/Shell.qml:280
306msgid "Sorry, incorrect passphrase"
309msgid "Sorry, incorrect passphrase"
307msgstr "Lo sentimos, contraseña incorrecta"
310msgstr "Lo sentimos, contraseña incorrecta"
308
311
309#: qml/Shell.qml:282
312#: qml/Shell.qml:282
310msgid "Enter your passcode"
313msgid "Enter your passcode"
311−msgstr ""
314+msgstr "Escriba su código de acceso"
312
315
313#: qml/Shell.qml:283
316#: qml/Shell.qml:283
314msgid "Sorry, incorrect passcode"
317msgid "Sorry, incorrect passcode"
315−msgstr ""
318+msgstr "El código de acceso es incorrecto"
316
319
317−#: qml/Shell.qml:273
320+#: qml/Shell.qml:286
318#, qt-format
321#, qt-format
319msgid "Enter your %1"
322msgid "Enter your %1"
320msgstr "Introduzca su %1"
323msgstr "Introduzca su %1"
321
324
322−#: qml/Shell.qml:274
325+#: qml/Shell.qml:287
323#, qt-format
326#, qt-format
324msgid "Sorry, incorrect %1"
327msgid "Sorry, incorrect %1"
325msgstr "Lo sentimos, %1 incorrecto"
328msgstr "Lo sentimos, %1 incorrecto"
326
329
327−#: qml/Shell.qml:310
330+#: qml/Shell.qml:323
328msgid "Sorry, incorrect passphrase."
331msgid "Sorry, incorrect passphrase."
329msgstr "Frase de paso incorrecta"
332msgstr "Frase de paso incorrecta"
330
333
331−#: qml/Shell.qml:311
334+#: qml/Shell.qml:324
332msgid "Sorry, incorrect passcode."
335msgid "Sorry, incorrect passcode."
333−msgstr "Código de paso incorrecto"
336+msgstr "Código de acceso incorrecto."
334
337
335−#: qml/Shell.qml:312
338+#: qml/Shell.qml:325
336msgid "This will be your last attempt."
339msgid "This will be your last attempt."
337msgstr "Este será su último intento."
340msgstr "Este será su último intento."
338
341
339−#: qml/Shell.qml:314
342+#: qml/Shell.qml:327
340msgid ""
343msgid ""
341"If passphrase is entered incorrectly, your phone will conduct a factory "
344"If passphrase is entered incorrectly, your phone will conduct a factory "
342"reset and all personal data will be deleted."
345"reset and all personal data will be deleted."
@@ -344,19 +347,10 @@ msgstr ""
344"Si se introduce la frase incorrectamente, el teléfono volverá a la "
347"Si se introduce la frase incorrectamente, el teléfono volverá a la "
345"configuración de fábrica y se perderán todos los datos personales."
348"configuración de fábrica y se perderán todos los datos personales."
346
349
347−#: qml/Shell.qml:315
350+#: qml/Shell.qml:328
348msgid ""
351msgid ""
349"If passcode is entered incorrectly, your phone will conduct a factory reset "
352"If passcode is entered incorrectly, your phone will conduct a factory reset "
350"and all personal data will be deleted."
353"and all personal data will be deleted."
351msgstr ""
354msgstr ""
352"Si se introduce el código incorrectamente, el teléfono volverá a la "
355"Si se introduce el código incorrectamente, el teléfono volverá a la "
353"configuración de fábrica y se perderán todos los datos personales."
356"configuración de fábrica y se perderán todos los datos personales."
354−
355−#~ msgid "Restart"
356−#~ msgstr "Reiniciar"
357−
358−#~ msgid "Are you sure you would like to turn power off?"
359−#~ msgstr "¿Está seguro de que quiere apagarlo?"
360−
361−#~ msgid "Enter your PIN"
362−#~ msgstr "Escriba el PIN"
po/eu.po+61−56
@@ -8,18 +8,18 @@ msgstr ""
8"Project-Id-Version: unity8\n"
8"Project-Id-Version: unity8\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2014-08-26 18:24+0200\n"
10"POT-Creation-Date: 2014-08-26 18:24+0200\n"
11−"PO-Revision-Date: 2014-08-06 22:51+0000\n"
11+"PO-Revision-Date: 2014-09-02 20:34+0000\n"
12"Last-Translator: Ibai Oihanguren Sala <Unknown>\n"
12"Last-Translator: Ibai Oihanguren Sala <Unknown>\n"
13"Language-Team: Basque <eu@li.org>\n"
13"Language-Team: Basque <eu@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-08-28 06:29+0000\n"
17+"X-Launchpad-Export-Date: 2014-09-03 07:05+0000\n"
18−"X-Generator: Launchpad (build 17174)\n"
18+"X-Generator: Launchpad (build 17196)\n"
19
19
20−#: plugins/LightDM/Greeter.cpp:129
20+#: plugins/LightDM/Greeter.cpp:130
21msgid "Password: "
21msgid "Password: "
22−msgstr ""
22+msgstr "Pasahitza: "
23
23
24#: plugins/Unity/Launcher/launcheritem.cpp:43
24#: plugins/Unity/Launcher/launcheritem.cpp:43
25#: plugins/Unity/Launcher/launcheritem.cpp:73
25#: plugins/Unity/Launcher/launcheritem.cpp:73
@@ -32,55 +32,55 @@ msgstr "Askatu lasterbidea"
32
32
33#: qml/Components/Dialogs.qml:70
33#: qml/Components/Dialogs.qml:70
34msgid "Log out"
34msgid "Log out"
35−msgstr ""
35+msgstr "Amaitu saioa"
36
36
37#: qml/Components/Dialogs.qml:71
37#: qml/Components/Dialogs.qml:71
38msgid "Are you sure you want to log out?"
38msgid "Are you sure you want to log out?"
39−msgstr ""
39+msgstr "Ziur saioa amaitu nahi duzula?"
40
40
41#: qml/Components/Dialogs.qml:73 qml/Components/Dialogs.qml:97
41#: qml/Components/Dialogs.qml:73 qml/Components/Dialogs.qml:97
42#: qml/Components/Dialogs.qml:122
42#: qml/Components/Dialogs.qml:122
43msgid "No"
43msgid "No"
44−msgstr ""
44+msgstr "Ez"
45
45
46#: qml/Components/Dialogs.qml:80 qml/Components/Dialogs.qml:104
46#: qml/Components/Dialogs.qml:80 qml/Components/Dialogs.qml:104
47#: qml/Components/Dialogs.qml:129
47#: qml/Components/Dialogs.qml:129
48msgid "Yes"
48msgid "Yes"
49−msgstr ""
49+msgstr "Bai"
50
50
51#: qml/Components/Dialogs.qml:94
51#: qml/Components/Dialogs.qml:94
52msgid "Shut down"
52msgid "Shut down"
53−msgstr ""
53+msgstr "Itzali"
54
54
55#: qml/Components/Dialogs.qml:95
55#: qml/Components/Dialogs.qml:95
56msgid "Are you sure you want to shut down?"
56msgid "Are you sure you want to shut down?"
57−msgstr ""
57+msgstr "Ziur itzali nahi duzula?"
58
58
59#: qml/Components/Dialogs.qml:119
59#: qml/Components/Dialogs.qml:119
60msgid "Reboot"
60msgid "Reboot"
61−msgstr ""
61+msgstr "Berrabiarazi"
62
62
63#: qml/Components/Dialogs.qml:120
63#: qml/Components/Dialogs.qml:120
64msgid "Are you sure you want to reboot?"
64msgid "Are you sure you want to reboot?"
65−msgstr ""
65+msgstr "Ziur berrabiarazi nahi duzula?"
66
66
67#: qml/Components/Dialogs.qml:144
67#: qml/Components/Dialogs.qml:144
68msgid "Power"
68msgid "Power"
69−msgstr ""
69+msgstr "Energia"
70
70
71#: qml/Components/Dialogs.qml:145
71#: qml/Components/Dialogs.qml:145
72msgid ""
72msgid ""
73"Are you sure you would like\n"
73"Are you sure you would like\n"
74"to power off?"
74"to power off?"
75−msgstr ""
75+msgstr "Ziur itzali nahi duzula?"
76
76
77−#: qml/Components/Dialogs.qml:144
77+#: qml/Components/Dialogs.qml:147
78msgid "Power off"
78msgid "Power off"
79−msgstr ""
79+msgstr "Itzali"
80
80
81−#: qml/Components/Dialogs.qml:162
81+#: qml/Components/Dialogs.qml:157
82msgid "Cancel"
82msgid "Cancel"
83−msgstr ""
83+msgstr "Utzi"
84
84
85#: qml/Components/EdgeDemoOverlay.qml:151
85#: qml/Components/EdgeDemoOverlay.qml:151
86msgid "Skip intro"
86msgid "Skip intro"
@@ -135,11 +135,11 @@ msgstr ""
135
135
136#: qml/Components/Lockscreen.qml:167
136#: qml/Components/Lockscreen.qml:167
137msgid "Please wait"
137msgid "Please wait"
138−msgstr ""
138+msgstr "Itxaron"
139
139
140#: qml/Components/Lockscreen.qml:172
140#: qml/Components/Lockscreen.qml:172
141msgid "Too many incorrect attempts"
141msgid "Too many incorrect attempts"
142−msgstr ""
142+msgstr "Okerreko saiakera gehiegi"
143
143
144#: qml/Components/Lockscreen.qml:206
144#: qml/Components/Lockscreen.qml:206
145msgid "Emergency Call"
145msgid "Emergency Call"
@@ -166,21 +166,22 @@ msgstr "Ikusi gutxiago"
166msgid "See all"
166msgid "See all"
167msgstr "Ikusi guztiak"
167msgstr "Ikusi guztiak"
168
168
169−#: qml/Dash/GenericScopeView.qml:424 qml/Panel/SearchIndicator.qml:27
169+#: qml/Dash/GenericScopeView.qml:424 qml/Dash/PageHeader.qml:260
170+#: qml/Panel/SearchIndicator.qml:27
170msgid "Search"
171msgid "Search"
171msgstr "Bilatu"
172msgstr "Bilatu"
172
173
173#: qml/Dash/PageHeader.qml:270
174#: qml/Dash/PageHeader.qml:270
174msgid "Settings"
175msgid "Settings"
175−msgstr ""
176+msgstr "Ezarpenak"
176
177
177#: qml/Dash/PageHeader.qml:279
178#: qml/Dash/PageHeader.qml:279
178msgid "Remove from Favorites"
179msgid "Remove from Favorites"
179−msgstr ""
180+msgstr "Kendu gogokoetatik"
180
181
181#: qml/Dash/PageHeader.qml:279
182#: qml/Dash/PageHeader.qml:279
182msgid "Add to Favorites"
183msgid "Add to Favorites"
183−msgstr ""
184+msgstr "Gehitu gogokoetara"
184
185
185#: qml/Dash/Previews/PreviewActionCombo.qml:34
186#: qml/Dash/Previews/PreviewActionCombo.qml:34
186msgid "More..."
187msgid "More..."
@@ -204,29 +205,29 @@ msgstr "Bidali"
204
205
205#: qml/Dash/ScopesOverview.qml:201
206#: qml/Dash/ScopesOverview.qml:201
206msgid "Manage Dash"
207msgid "Manage Dash"
207−msgstr ""
208+msgstr "Kudeatu abio-leihoa"
208
209
209−#: qml/Dash/ScopesOverview.qml:408
210+#: qml/Dash/ScopesOverview.qml:417
210msgid "Done"
211msgid "Done"
211−msgstr ""
212+msgstr "Eginda"
212
213
213−#: qml/Dash/ScopesOverview.qml:434
214+#: qml/Dash/ScopesOverview.qml:443
214msgid "Store"
215msgid "Store"
215−msgstr ""
216+msgstr "Denda"
216
217
217#: qml/Dash/ScopesOverviewTab.qml:36
218#: qml/Dash/ScopesOverviewTab.qml:36
218msgid "Favorites"
219msgid "Favorites"
219−msgstr ""
220+msgstr "Gogokoak"
220
221
221#: qml/Dash/ScopesOverviewTab.qml:54
222#: qml/Dash/ScopesOverviewTab.qml:54
222msgid "All"
223msgid "All"
223−msgstr ""
224+msgstr "Guztiak"
224
225
225#: qml/Greeter/Greeter.qml:157
226#: qml/Greeter/Greeter.qml:157
226msgid "Swipe to unlock"
227msgid "Swipe to unlock"
227msgstr "Pasatu hatza desblokeatzeko"
228msgstr "Pasatu hatza desblokeatzeko"
228
229
229−#: qml/Hud/HudParametrizedActionsPage.qml:132
230+#: qml/Hud/HudParametrizedActionsPage.qml:139
230msgid "Confirm"
231msgid "Confirm"
231msgstr "Baieztatu"
232msgstr "Baieztatu"
232
233
@@ -252,11 +253,11 @@ msgstr "Erakutsi pasahitza"
252
253
253#: qml/Notifications/NotificationMenuItemFactory.qml:120
254#: qml/Notifications/NotificationMenuItemFactory.qml:120
254msgid "Enter SIM PIN"
255msgid "Enter SIM PIN"
255−msgstr ""
256+msgstr "Sartu SIM PINa"
256
257
257−#: qml/Notifications/NotificationMenuItemFactory.qml:121 qml/Shell.qml:270
258+#: qml/Notifications/NotificationMenuItemFactory.qml:121
258msgid "Sorry, incorrect PIN"
259msgid "Sorry, incorrect PIN"
259−msgstr ""
260+msgstr "Sentitzen dugu, PINa okerrekoa da"
260
261
261#: qml/Panel/ActiveCallHint.qml:77
262#: qml/Panel/ActiveCallHint.qml:77
262msgid "Tap to return to call..."
263msgid "Tap to return to call..."
@@ -292,58 +293,62 @@ msgstr "Huts egin du, sakatu berriro saiatzeko"
292
293
293#: qml/Panel/Indicators/ModemInfoItem.qml:105
294#: qml/Panel/Indicators/ModemInfoItem.qml:105
294msgid "Unlock SIM"
295msgid "Unlock SIM"
295−msgstr ""
296+msgstr "Desblokeatu SIMa"
296
297
297#: qml/Panel/Indicators/RoamingIndication.qml:27
298#: qml/Panel/Indicators/RoamingIndication.qml:27
298msgid "Roaming"
299msgid "Roaming"
299−msgstr ""
300+msgstr "Ibiltaritza"
300
301
301−#: qml/Shell.qml:266
302+#: qml/Shell.qml:279
302msgid "Enter your passphrase"
303msgid "Enter your passphrase"
303−msgstr ""
304+msgstr "Sartu pasaesaldia"
304
305
305−#: qml/Shell.qml:267
306+#: qml/Shell.qml:280
306msgid "Sorry, incorrect passphrase"
307msgid "Sorry, incorrect passphrase"
307−msgstr ""
308+msgstr "Sentitzen dugu, pasaesaldia okerrekoa da"
308
309
309#: qml/Shell.qml:282
310#: qml/Shell.qml:282
310msgid "Enter your passcode"
311msgid "Enter your passcode"
311−msgstr ""
312+msgstr "Sartu pasakodea"
312
313
313#: qml/Shell.qml:283
314#: qml/Shell.qml:283
314msgid "Sorry, incorrect passcode"
315msgid "Sorry, incorrect passcode"
315−msgstr ""
316+msgstr "Sentitzen dugu, pasakodea okerrekoa da"
316
317
317−#: qml/Shell.qml:273
318+#: qml/Shell.qml:286
318#, qt-format
319#, qt-format
319msgid "Enter your %1"
320msgid "Enter your %1"
320−msgstr ""
321+msgstr "Sartu %1"
321
322
322−#: qml/Shell.qml:274
323+#: qml/Shell.qml:287
323#, qt-format
324#, qt-format
324msgid "Sorry, incorrect %1"
325msgid "Sorry, incorrect %1"
325−msgstr ""
326+msgstr "Sentitzen dugu, %1 okerrekoa da"
326
327
327−#: qml/Shell.qml:310
328+#: qml/Shell.qml:323
328msgid "Sorry, incorrect passphrase."
329msgid "Sorry, incorrect passphrase."
329−msgstr ""
330+msgstr "Sentitzen dugu, pasaesaldia okerrekoa da."
330
331
331−#: qml/Shell.qml:311
332+#: qml/Shell.qml:324
332msgid "Sorry, incorrect passcode."
333msgid "Sorry, incorrect passcode."
333−msgstr ""
334+msgstr "Sentitzen dugu, pasakodea okerrekoa da."
334
335
335−#: qml/Shell.qml:312
336+#: qml/Shell.qml:325
336msgid "This will be your last attempt."
337msgid "This will be your last attempt."
337−msgstr ""
338+msgstr "Hau duzu azken saiakera."
338
339
339−#: qml/Shell.qml:314
340+#: qml/Shell.qml:327
340msgid ""
341msgid ""
341"If passphrase is entered incorrectly, your phone will conduct a factory "
342"If passphrase is entered incorrectly, your phone will conduct a factory "
342"reset and all personal data will be deleted."
343"reset and all personal data will be deleted."
343msgstr ""
344msgstr ""
345+"Okerreko pasaesaldia sartzen baduzu, telefonoaren jatorrizko ezarpenak "
346+"berrezarri eta datu pertsonal guztiak ezabatuko dira."
344
347
345−#: qml/Shell.qml:315
348+#: qml/Shell.qml:328
346msgid ""
349msgid ""
347"If passcode is entered incorrectly, your phone will conduct a factory reset "
350"If passcode is entered incorrectly, your phone will conduct a factory reset "
348"and all personal data will be deleted."
351"and all personal data will be deleted."
349msgstr ""
352msgstr ""
353+"Okerreko pasakodea sartzen baduzu, telefonoaren jatorrizko ezarpenak "
354+"berrezarri eta datu pertsonal guztiak ezabatuko dira."
po/sv.po+56−52
@@ -8,17 +8,17 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2014-08-26 18:24+0200\n"
10"POT-Creation-Date: 2014-08-26 18:24+0200\n"
11−"PO-Revision-Date: 2014-08-14 18:22+0000\n"
11+"PO-Revision-Date: 2014-09-08 15:57+0000\n"
12−"Last-Translator: Erik Simmesgård <Unknown>\n"
12+"Last-Translator: Josef Andersson <Unknown>\n"
13"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
13"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-08-28 06:30+0000\n"
17+"X-Launchpad-Export-Date: 2014-09-10 08:02+0000\n"
18−"X-Generator: Launchpad (build 17174)\n"
18+"X-Generator: Launchpad (build 17196)\n"
19"Language: sv\n"
19"Language: sv\n"
20
20
21−#: plugins/LightDM/Greeter.cpp:129
21+#: plugins/LightDM/Greeter.cpp:130
22msgid "Password: "
22msgid "Password: "
23msgstr "Lösenord: "
23msgstr "Lösenord: "
24
24
@@ -33,53 +33,55 @@ msgstr "Släpp genväg"
33
33
34#: qml/Components/Dialogs.qml:70
34#: qml/Components/Dialogs.qml:70
35msgid "Log out"
35msgid "Log out"
36−msgstr ""
36+msgstr "Logga ut"
37
37
38#: qml/Components/Dialogs.qml:71
38#: qml/Components/Dialogs.qml:71
39msgid "Are you sure you want to log out?"
39msgid "Are you sure you want to log out?"
40−msgstr ""
40+msgstr "Är du säker på att du vill logga ut?"
41
41
42#: qml/Components/Dialogs.qml:73 qml/Components/Dialogs.qml:97
42#: qml/Components/Dialogs.qml:73 qml/Components/Dialogs.qml:97
43#: qml/Components/Dialogs.qml:122
43#: qml/Components/Dialogs.qml:122
44msgid "No"
44msgid "No"
45−msgstr ""
45+msgstr "Nej"
46
46
47#: qml/Components/Dialogs.qml:80 qml/Components/Dialogs.qml:104
47#: qml/Components/Dialogs.qml:80 qml/Components/Dialogs.qml:104
48#: qml/Components/Dialogs.qml:129
48#: qml/Components/Dialogs.qml:129
49msgid "Yes"
49msgid "Yes"
50−msgstr ""
50+msgstr "Ja"
51
51
52#: qml/Components/Dialogs.qml:94
52#: qml/Components/Dialogs.qml:94
53msgid "Shut down"
53msgid "Shut down"
54−msgstr ""
54+msgstr "Stäng av"
55
55
56#: qml/Components/Dialogs.qml:95
56#: qml/Components/Dialogs.qml:95
57msgid "Are you sure you want to shut down?"
57msgid "Are you sure you want to shut down?"
58−msgstr ""
58+msgstr "Är du säker på att du vill stänga av?"
59
59
60#: qml/Components/Dialogs.qml:119
60#: qml/Components/Dialogs.qml:119
61msgid "Reboot"
61msgid "Reboot"
62−msgstr ""
62+msgstr "Starta om"
63
63
64#: qml/Components/Dialogs.qml:120
64#: qml/Components/Dialogs.qml:120
65msgid "Are you sure you want to reboot?"
65msgid "Are you sure you want to reboot?"
66−msgstr ""
66+msgstr "Är du säker på att du vill starta om?"
67
67
68#: qml/Components/Dialogs.qml:144
68#: qml/Components/Dialogs.qml:144
69msgid "Power"
69msgid "Power"
70−msgstr ""
70+msgstr "Ström"
71
71
72#: qml/Components/Dialogs.qml:145
72#: qml/Components/Dialogs.qml:145
73msgid ""
73msgid ""
74"Are you sure you would like\n"
74"Are you sure you would like\n"
75"to power off?"
75"to power off?"
76msgstr ""
76msgstr ""
77+"Är du säker på att du vill \n"
78+"stänga av?"
77
79
78−#: qml/Components/Dialogs.qml:144
80+#: qml/Components/Dialogs.qml:147
79msgid "Power off"
81msgid "Power off"
80−msgstr ""
82+msgstr "Stäng av"
81
83
82−#: qml/Components/Dialogs.qml:162
84+#: qml/Components/Dialogs.qml:157
83msgid "Cancel"
85msgid "Cancel"
84msgstr "Avbryt"
86msgstr "Avbryt"
85
87
@@ -137,7 +139,7 @@ msgstr "Var god vänta"
137
139
138#: qml/Components/Lockscreen.qml:172
140#: qml/Components/Lockscreen.qml:172
139msgid "Too many incorrect attempts"
141msgid "Too many incorrect attempts"
140−msgstr ""
142+msgstr "För många felaktiga försök"
141
143
142#: qml/Components/Lockscreen.qml:206
144#: qml/Components/Lockscreen.qml:206
143msgid "Emergency Call"
145msgid "Emergency Call"
@@ -164,21 +166,22 @@ msgstr "Visa mindre"
164msgid "See all"
166msgid "See all"
165msgstr "Visa alla"
167msgstr "Visa alla"
166
168
167−#: qml/Dash/GenericScopeView.qml:424 qml/Panel/SearchIndicator.qml:27
169+#: qml/Dash/GenericScopeView.qml:424 qml/Dash/PageHeader.qml:260
170+#: qml/Panel/SearchIndicator.qml:27
168msgid "Search"
171msgid "Search"
169msgstr "Sök"
172msgstr "Sök"
170
173
171#: qml/Dash/PageHeader.qml:270
174#: qml/Dash/PageHeader.qml:270
172msgid "Settings"
175msgid "Settings"
173−msgstr ""
176+msgstr "Inställningar"
174
177
175#: qml/Dash/PageHeader.qml:279
178#: qml/Dash/PageHeader.qml:279
176msgid "Remove from Favorites"
179msgid "Remove from Favorites"
177−msgstr ""
180+msgstr "Ta bort från Favoriter"
178
181
179#: qml/Dash/PageHeader.qml:279
182#: qml/Dash/PageHeader.qml:279
180msgid "Add to Favorites"
183msgid "Add to Favorites"
181−msgstr ""
184+msgstr "Lägg till Favoriter"
182
185
183#: qml/Dash/Previews/PreviewActionCombo.qml:34
186#: qml/Dash/Previews/PreviewActionCombo.qml:34
184msgid "More..."
187msgid "More..."
@@ -202,15 +205,15 @@ msgstr "Skicka"
202
205
203#: qml/Dash/ScopesOverview.qml:201
206#: qml/Dash/ScopesOverview.qml:201
204msgid "Manage Dash"
207msgid "Manage Dash"
205−msgstr ""
208+msgstr "Hantera Dash"
206
209
207−#: qml/Dash/ScopesOverview.qml:408
210+#: qml/Dash/ScopesOverview.qml:417
208msgid "Done"
211msgid "Done"
209−msgstr ""
212+msgstr "Klar"
210
213
211−#: qml/Dash/ScopesOverview.qml:434
214+#: qml/Dash/ScopesOverview.qml:443
212msgid "Store"
215msgid "Store"
213−msgstr ""
216+msgstr "Butik"
214
217
215#: qml/Dash/ScopesOverviewTab.qml:36
218#: qml/Dash/ScopesOverviewTab.qml:36
216msgid "Favorites"
219msgid "Favorites"
@@ -218,13 +221,13 @@ msgstr "Favoriter"
218
221
219#: qml/Dash/ScopesOverviewTab.qml:54
222#: qml/Dash/ScopesOverviewTab.qml:54
220msgid "All"
223msgid "All"
221−msgstr ""
224+msgstr "Alla"
222
225
223#: qml/Greeter/Greeter.qml:157
226#: qml/Greeter/Greeter.qml:157
224msgid "Swipe to unlock"
227msgid "Swipe to unlock"
225msgstr "Svep för att låsa upp"
228msgstr "Svep för att låsa upp"
226
229
227−#: qml/Hud/HudParametrizedActionsPage.qml:132
230+#: qml/Hud/HudParametrizedActionsPage.qml:139
228msgid "Confirm"
231msgid "Confirm"
229msgstr "Bekräfta"
232msgstr "Bekräfta"
230
233
@@ -250,11 +253,11 @@ msgstr "Visa lösenord"
250
253
251#: qml/Notifications/NotificationMenuItemFactory.qml:120
254#: qml/Notifications/NotificationMenuItemFactory.qml:120
252msgid "Enter SIM PIN"
255msgid "Enter SIM PIN"
253−msgstr ""
256+msgstr "Ange SIM PIN-kod"
254
257
255−#: qml/Notifications/NotificationMenuItemFactory.qml:121 qml/Shell.qml:270
258+#: qml/Notifications/NotificationMenuItemFactory.qml:121
256msgid "Sorry, incorrect PIN"
259msgid "Sorry, incorrect PIN"
257−msgstr ""
260+msgstr "Felaktig PIN"
258
261
259#: qml/Panel/ActiveCallHint.qml:77
262#: qml/Panel/ActiveCallHint.qml:77
260msgid "Tap to return to call..."
263msgid "Tap to return to call..."
@@ -296,55 +299,56 @@ msgstr "Lås upp SIM-kort"
296msgid "Roaming"
299msgid "Roaming"
297msgstr "Roaming"
300msgstr "Roaming"
298
301
299−#: qml/Shell.qml:266
302+#: qml/Shell.qml:279
300msgid "Enter your passphrase"
303msgid "Enter your passphrase"
301−msgstr ""
304+msgstr "Ange din lösenfras"
302
305
303−#: qml/Shell.qml:267
306+#: qml/Shell.qml:280
304msgid "Sorry, incorrect passphrase"
307msgid "Sorry, incorrect passphrase"
305−msgstr ""
308+msgstr "Felaktig lösenfras"
306
309
307#: qml/Shell.qml:282
310#: qml/Shell.qml:282
308msgid "Enter your passcode"
311msgid "Enter your passcode"
309−msgstr ""
312+msgstr "Ange din lösenkod"
310
313
311#: qml/Shell.qml:283
314#: qml/Shell.qml:283
312msgid "Sorry, incorrect passcode"
315msgid "Sorry, incorrect passcode"
313−msgstr ""
316+msgstr "Felaktig lösenkod"
314
317
315−#: qml/Shell.qml:273
318+#: qml/Shell.qml:286
316#, qt-format
319#, qt-format
317msgid "Enter your %1"
320msgid "Enter your %1"
318msgstr "Skriv in din %1"
321msgstr "Skriv in din %1"
319
322
320−#: qml/Shell.qml:274
323+#: qml/Shell.qml:287
321#, qt-format
324#, qt-format
322msgid "Sorry, incorrect %1"
325msgid "Sorry, incorrect %1"
323−msgstr ""
326+msgstr "Felaktig %1"
324
327
325−#: qml/Shell.qml:310
328+#: qml/Shell.qml:323
326msgid "Sorry, incorrect passphrase."
329msgid "Sorry, incorrect passphrase."
327−msgstr ""
330+msgstr "Felaktig lösenfras."
328
331
329−#: qml/Shell.qml:311
332+#: qml/Shell.qml:324
330msgid "Sorry, incorrect passcode."
333msgid "Sorry, incorrect passcode."
331−msgstr ""
334+msgstr "Felaktig lösenkod."
332
335
333−#: qml/Shell.qml:312
336+#: qml/Shell.qml:325
334msgid "This will be your last attempt."
337msgid "This will be your last attempt."
335−msgstr ""
338+msgstr "Detta är ditt sista försök."
336
339
337−#: qml/Shell.qml:314
340+#: qml/Shell.qml:327
338msgid ""
341msgid ""
339"If passphrase is entered incorrectly, your phone will conduct a factory "
342"If passphrase is entered incorrectly, your phone will conduct a factory "
340"reset and all personal data will be deleted."
343"reset and all personal data will be deleted."
341msgstr ""
344msgstr ""
345+"Om lösenfrasen anges inkorrekt kommer telefonen att fabrikåterställas och "
346+"all personlig data kommer att tas bort."
342
347
343−#: qml/Shell.qml:315
348+#: qml/Shell.qml:328
344msgid ""
349msgid ""
345"If passcode is entered incorrectly, your phone will conduct a factory reset "
350"If passcode is entered incorrectly, your phone will conduct a factory reset "
346"and all personal data will be deleted."
351"and all personal data will be deleted."
347msgstr ""
352msgstr ""
348−
353+"Om lösenkoden anges felaktigt kommer telefonen att fabrikåterställas och all "
349−#~ msgid "Restart"
354+"personlig data kommer att tas bort."
350−#~ msgstr "Starta om"
qml/Components/Background.qml+1−1
@@ -78,7 +78,7 @@ Loader {
78 Image {
78 Image {
79 objectName: "image"
79 objectName: "image"
80
80
81− source: width > 0 && height > 0 && root.style
81+ source: width > 0 && height > 0 && root.style || ""
82
82
83 sourceSize.width: width
83 sourceSize.width: width
84 sourceSize.height: height
84 sourceSize.height: height
qml/Dash/CardTool.qml+7−10
@@ -169,19 +169,16 @@ Item {
169
169
170 Item {
170 Item {
171 id: attributesModel
171 id: attributesModel
172− property int numOfAttributes: 0
172+ property int numOfAttributes: {
173− property var model: []
174− property bool hasAttributes: {
175 var attributes = components["attributes"];
173 var attributes = components["attributes"];
176− var hasAttributesFlag = (attributes != undefined) && attributes["field"];
174+ if ((attributes != undefined) && attributes["field"]) {
177−
178− if (hasAttributesFlag) {
179 if (attributes["max-count"]) {
175 if (attributes["max-count"]) {
180− numOfAttributes = attributes["max-count"];
176+ return attributes["max-count"];
181 }
177 }
182 }
178 }
183− return hasAttributesFlag
179+ return 0;
184 }
180 }
181+ property var model: []
185
182
186 onNumOfAttributesChanged: {
183 onNumOfAttributesChanged: {
187 model = []
184 model = []
@@ -195,8 +192,8 @@ Item {
195 id: cardLoader
192 id: cardLoader
196 property var fields: ["art", "mascot", "title", "subtitle", "summary", "attributes"]
193 property var fields: ["art", "mascot", "title", "subtitle", "summary", "attributes"]
197 property var maxData: {
194 property var maxData: {
198− "art": Qt.resolvedUrl("graphics/checkers.png"),
195+ "art": Qt.resolvedUrl("graphics/pixel.png"),
199− "mascot": Qt.resolvedUrl("graphics/checkers.png"),
196+ "mascot": Qt.resolvedUrl("graphics/pixel.png"),
200 "title": "—\n—",
197 "title": "—\n—",
201 "subtitle": "—",
198 "subtitle": "—",
202 "summary": "—\n—\n—\n—\n—",
199 "summary": "—\n—\n—\n—\n—",
qml/Dash/Dash.qml+12−1
@@ -34,7 +34,17 @@ Showable {
34 DashCommunicatorService {
34 DashCommunicatorService {
35 objectName: "dashCommunicatorService"
35 objectName: "dashCommunicatorService"
36 onSetCurrentScopeRequested: {
36 onSetCurrentScopeRequested: {
37+ if (!isSwipe || !window.active || overviewController.progress != 0) {
38+ if (overviewController.progress != 0 && window.active) animate = false;
37− dash.setCurrentScope(scopeId, animate, reset)
39+ dash.setCurrentScope(scopeId, animate, isSwipe)
40+ if (overviewController.progress != 0) {
41+ if (window.active) {
42+ dashContentCache.scheduleUpdate();
43+ }
44+ overviewController.enableAnimation = window.active;
45+ overviewController.progress = 0;
46+ }
47+ }
38 }
48 }
39 }
49 }
40
50
@@ -344,6 +354,7 @@ Showable {
344 enabled: !dashContent.subPageShown &&
354 enabled: !dashContent.subPageShown &&
345 dashContent.currentScope &&
355 dashContent.currentScope &&
346 dashContent.currentScope.searchQuery == "" &&
356 dashContent.currentScope.searchQuery == "" &&
357+ !scopeItem.subPageShown &&
347 (overviewController.progress == 0 || dragging)
358 (overviewController.progress == 0 || dragging)
348
359
349 readonly property real fullMovement: units.gu(20)
360 readonly property real fullMovement: units.gu(20)
qml/Dash/DashApplication.qml−6
@@ -24,12 +24,6 @@ MainView {
24
24
25 useDeprecatedToolbar: false
25 useDeprecatedToolbar: false
26
26
27− Binding {
28− target: i18n
29− property: "domain"
30− value: "unity8"
31− }
32−
33 Dash {
27 Dash {
34 anchors.fill: parent
28 anchors.fill: parent
35 }
29 }
qml/Dash/GenericScopeView.qml+1−2
@@ -25,7 +25,7 @@ import "../Components/ListItems" as ListItems
25FocusScope {
25FocusScope {
26 id: scopeView
26 id: scopeView
27
27
28− readonly property bool navigationShown: pageHeaderLoader.item ? pageHeaderLoader.item.bottomItem[0].showList : false
28+ readonly property bool navigationShown: pageHeaderLoader.item ? pageHeaderLoader.item.bottomItem[0].openList : false
29 property var scope: null
29 property var scope: null
30 property SortFilterProxyModel categories: categoryFilter
30 property SortFilterProxyModel categories: categoryFilter
31 property bool isCurrent: false
31 property bool isCurrent: false
@@ -151,7 +151,6 @@ FocusScope {
151 model: scopeView.categories
151 model: scopeView.categories
152 forceNoClip: subPageLoader.open
152 forceNoClip: subPageLoader.open
153 pixelAligned: true
153 pixelAligned: true
154− interactive: !navigationShown
155
154
156 property Item expandedCategoryItem: null
155 property Item expandedCategoryItem: null
157
156
qml/Dash/PageHeader.qml+19−14
@@ -64,9 +64,12 @@ Item {
64 }
64 }
65 }
65 }
66
66
67− function closePopup() {
67+ function closePopup(keepFocus) {
68 if (headerContainer.popover != null) {
68 if (headerContainer.popover != null) {
69+ headerContainer.popover.unfocusOnDestruction = !keepFocus;
69 PopupUtils.close(headerContainer.popover);
70 PopupUtils.close(headerContainer.popover);
71+ } else if (!keepFocus) {
72+ unfocus();
70 }
73 }
71 }
74 }
72
75
@@ -74,11 +77,8 @@ Item {
74 if (searchHistory) {
77 if (searchHistory) {
75 searchHistory.addQuery(searchTextField.text);
78 searchHistory.addQuery(searchTextField.text);
76 }
79 }
77− if (!keepFocus) {
78− unfocus();
79− }
80 searchTextField.text = "";
80 searchTextField.text = "";
81− closePopup();
81+ closePopup(keepFocus);
82 }
82 }
83
83
84 function unfocus() {
84 function unfocus() {
@@ -102,7 +102,7 @@ Item {
102 }
102 }
103
103
104 function refreshLogo() {
104 function refreshLogo() {
105− if (scopeStyle ? scopeStyle.headerLogo != "" : false) {
105+ if (root.scopeStyle ? root.scopeStyle.headerLogo != "" : false) {
106 header.contents = imageComponent.createObject();
106 header.contents = imageComponent.createObject();
107 } else if (header.contents) {
107 } else if (header.contents) {
108 header.contents.destroy();
108 header.contents.destroy();
@@ -119,11 +119,10 @@ Item {
119 anchors { fill: parent; margins: units.gu(1); bottomMargin: units.gu(3) + bottomContainer.height }
119 anchors { fill: parent; margins: units.gu(1); bottomMargin: units.gu(3) + bottomContainer.height }
120 visible: headerContainer.showSearch
120 visible: headerContainer.showSearch
121 onPressed: {
121 onPressed: {
122− closePopup();
122+ closePopup(/* keepFocus */false);
123 if (!searchTextField.text) {
123 if (!searchTextField.text) {
124 headerContainer.showSearch = false;
124 headerContainer.showSearch = false;
125 }
125 }
126− searchTextField.focus = false;
127 mouse.accepted = false;
126 mouse.accepted = false;
128 }
127 }
129 }
128 }
@@ -228,7 +227,7 @@ Item {
228
227
229 onTextChanged: {
228 onTextChanged: {
230 if (text != "") {
229 if (text != "") {
231− closePopup();
230+ closePopup(/* keepFocus */true);
232 }
231 }
233 }
232 }
234 }
233 }
@@ -310,8 +309,13 @@ Item {
310 id: popover
309 id: popover
311 autoClose: false
310 autoClose: false
312
311
312+ property bool unfocusOnDestruction: false
313+
313 Component.onDestruction: {
314 Component.onDestruction: {
314 headerContainer.popover = null;
315 headerContainer.popover = null;
316+ if (unfocusOnDestruction) {
317+ root.unfocus();
318+ }
315 }
319 }
316
320
317 Column {
321 Column {
@@ -332,8 +336,7 @@ Item {
332 onClicked: {
336 onClicked: {
333 searchHistory.addQuery(text);
337 searchHistory.addQuery(text);
334 searchTextField.text = text;
338 searchTextField.text = text;
335− closePopup();
339+ closePopup(/* keepFocus */false);
336− unfocus();
337 }
340 }
338 }
341 }
339 }
342 }
@@ -350,7 +353,7 @@ Item {
350 bottom: bottomContainer.top
353 bottom: bottomContainer.top
351 }
354 }
352
355
353− color: scopeStyle ? scopeStyle.headerDividerColor : "#e0e0e0"
356+ color: root.scopeStyle ? root.scopeStyle.headerDividerColor : "#e0e0e0"
354
357
355 Rectangle {
358 Rectangle {
356 anchors {
359 anchors {
@@ -404,8 +407,10 @@ Item {
404 Qt.lighter(Qt.rgba(bottomItem.background.topColor.r,
407 Qt.lighter(Qt.rgba(bottomItem.background.topColor.r,
405 bottomItem.background.topColor.g,
408 bottomItem.background.topColor.g,
406 bottomItem.background.topColor.b, 1.0), 1.2);
409 bottomItem.background.topColor.b, 1.0), 1.2);
407− } else if (!bottomItem && scopeStyle) {
410+ } else if (!bottomItem && root.scopeStyle) {
408− Qt.lighter(Qt.rgba(scopeStyle.background.r, scopeStyle.background.g, scopeStyle.background.b, 1.0), 1.2);
411+ Qt.lighter(Qt.rgba(root.scopeStyle.background.r,
412+ root.scopeStyle.background.g,
413+ root.scopeStyle.background.b, 1.0), 1.2);
409 } else "#CCFFFFFF"
414 } else "#CCFFFFFF"
410 }
415 }
411 }
416 }
qml/Dash/PreviewListView.qml+2−2
@@ -44,7 +44,7 @@ Item {
44 id: header
44 id: header
45 objectName: "pageHeader"
45 objectName: "pageHeader"
46 width: parent.width
46 width: parent.width
47− title: scope ? scope.name : ""
47+ title: root.scope ? root.scope.name : ""
48 showBackButton: true
48 showBackButton: true
49 searchEntryEnabled: false
49 searchEntryEnabled: false
50 scopeStyle: root.scopeStyle
50 scopeStyle: root.scopeStyle
@@ -78,7 +78,7 @@ Item {
78 if (previewListView.currentItem && previewListView.currentItem.previewData !== undefined) {
78 if (previewListView.currentItem && previewListView.currentItem.previewData !== undefined) {
79 previewListView.currentItem.previewData.cancelAction();
79 previewListView.currentItem.previewData.cancelAction();
80 }
80 }
81− scope.cancelActivation();
81+ root.scope.cancelActivation();
82 model = undefined;
82 model = undefined;
83 }
83 }
84 }
84 }
qml/Dash/Previews/PreviewPayments.qml+2
@@ -49,6 +49,7 @@ PreviewWidget {
49
49
50 Payments {
50 Payments {
51 id: paymentClient
51 id: paymentClient
52+ objectName: "paymentClient"
52
53
53 property var source: widgetData["source"]
54 property var source: widgetData["source"]
54
55
@@ -59,6 +60,7 @@ PreviewWidget {
59 root.triggered(widgetId, "purchaseCompleted", source);
60 root.triggered(widgetId, "purchaseCompleted", source);
60 }
61 }
61 onPurchaseError: {
62 onPurchaseError: {
63+ paymentButton.opacity = 1;
62 root.triggered(widgetId, "purchaseError", source);
64 root.triggered(widgetId, "purchaseError", source);
63 }
65 }
64 }
66 }
qml/Dash/ScopesOverview.qml+6
@@ -386,6 +386,7 @@ Item {
386
386
387 Rectangle {
387 Rectangle {
388 id: bottomBar
388 id: bottomBar
389+ objectName: "bottomBar"
389 color: "black"
390 color: "black"
390 height: units.gu(8)
391 height: units.gu(8)
391 width: parent.width
392 width: parent.width
@@ -400,6 +401,11 @@ Item {
400 }
401 }
401 }
402 }
402
403
404+ MouseArea {
405+ // Just eat any other press since this parent is black opaque
406+ anchors.fill: parent
407+ }
408+
403 AbstractButton {
409 AbstractButton {
404 objectName: "scopesOverviewDoneButton"
410 objectName: "scopesOverviewDoneButton"
405 width: Math.max(label.width + units.gu(2), units.gu(10))
411 width: Math.max(label.width + units.gu(2), units.gu(10))
qml/Dash/graphics/checkers.pngdeleted

Binary file not shown.

qml/Dash/graphics/pixel.pngnew file

Binary file not shown.

qml/Notifications/Notification.qml+132−46
@@ -39,19 +39,17 @@ Item {
39 property bool fullscreen: false
39 property bool fullscreen: false
40 property int maxHeight
40 property int maxHeight
41 property int margins
41 property int margins
42− property Gradient greenGradient : Gradient {
42+ readonly property color red: "#fc4949"
43− GradientStop { position: 0.0; color: "#3fb24f" }
43+ readonly property color green: "#3fb24f"
44− GradientStop { position: 1.0; color: "#3fb24f" }
44+ readonly property color sdLightGrey: "#eaeaea"
45− }
45+ readonly property color sdDarkGrey: "#dddddd"
46− property Gradient darkgreyGradient: Gradient {
46+ readonly property color sdFontColor: "#5d5d5d"
47− GradientStop { position: 0.0; color: "#4d4745" }
47+ readonly property real contentSpacing: units.gu(2)
48− GradientStop { position: 1.0; color: "#4d4745" }
49− }
50
48
51 objectName: "background"
49 objectName: "background"
52− implicitHeight: type !== Notification.PlaceHolder ? (fullscreen ? maxHeight : contentColumn.height + contentColumn.spacing * 2) : 0
50+ implicitHeight: type !== Notification.PlaceHolder ? (fullscreen ? maxHeight : outterColumn.height + contentSpacing * 2) : 0
53
51
54− color: Qt.rgba(0.132, 0.117, 0.109, 0.97)
52+ color: type == Notification.SnapDecision ? sdLightGrey : Qt.rgba(0.132, 0.117, 0.109, 0.97)
55 opacity: 1 // FIXME: 1 because of LP: #1354406 workaround, has to be 0 really
53 opacity: 1 // FIXME: 1 because of LP: #1354406 workaround, has to be 0 really
56
54
57 state: {
55 state: {
@@ -107,7 +105,7 @@ Item {
107 states:[
105 states:[
108 State {
106 State {
109 name: "contracted"
107 name: "contracted"
110− PropertyChanges {target: notification; height: units.gu(8)}
108+ PropertyChanges {target: notification; height: units.gu(10)}
111 },
109 },
112 State {
110 State {
113 name: "expanded"
111 name: "expanded"
@@ -131,6 +129,7 @@ Item {
131 color: parent.color
129 color: parent.color
132 opacity: parent.opacity
130 opacity: parent.opacity
133 radius: "medium"
131 radius: "medium"
132+ borderSource: "none"
134 }
133 }
135
134
136 Rectangle {
135 Rectangle {
@@ -199,50 +198,41 @@ Item {
199 }
198 }
200
199
201 Column {
200 Column {
202− id: contentColumn
201+ id: outterColumn
203− objectName: "contentColumn"
204
202
205 anchors {
203 anchors {
206 left: parent.left
204 left: parent.left
207 right: parent.right
205 right: parent.right
208 top: parent.top
206 top: parent.top
209− margins: fullscreen ? 0 : spacing
207+ margins: 0
208+ topMargin: fullscreen ? 0 : units.gu(2)
210 }
209 }
211
210
212− spacing: units.gu(1)
211+ spacing: units.gu(2)
213
212
214 Row {
213 Row {
215 id: topRow
214 id: topRow
216
215
217− spacing: contentColumn.spacing
216+ spacing: contentSpacing
218 anchors {
217 anchors {
219 left: parent.left
218 left: parent.left
220 right: parent.right
219 right: parent.right
220+ margins: contentSpacing
221 }
221 }
222
222
223 ShapedIcon {
223 ShapedIcon {
224 id: icon
224 id: icon
225
225
226 objectName: "icon"
226 objectName: "icon"
227− width: units.gu(6)
227+ width: type == Notification.Ephemeral && !bodyLabel.visible ? units.gu(3) : units.gu(6)
228− height: units.gu(6)
228+ height: width
229 shaped: notification.hints["x-canonical-non-shaped-icon"] == "true" ? false : true
229 shaped: notification.hints["x-canonical-non-shaped-icon"] == "true" ? false : true
230 visible: iconSource !== undefined && iconSource != ""
230 visible: iconSource !== undefined && iconSource != ""
231− }
232−
233− Image {
234− id: secondaryIcon
235−
236− objectName: "secondaryIcon"
237− width: units.gu(2)
238− height: units.gu(2)
239− visible: source !== undefined && source != ""
240− fillMode: Image.PreserveAspectCrop
241− }
231+ }
242
232
243 Column {
233 Column {
244 id: labelColumn
234 id: labelColumn
245− width: parent.width - x
235+ width: secondaryIcon.visible ? parent.width - x - units.gu(4.5) : parent.width - x
246
236
247 anchors.verticalCenter: (icon.visible && !bodyLabel.visible) ? icon.verticalCenter : undefined
237 anchors.verticalCenter: (icon.visible && !bodyLabel.visible) ? icon.verticalCenter : undefined
248
238
@@ -255,8 +245,7 @@ Item {
255 right: parent.right
245 right: parent.right
256 }
246 }
257 fontSize: "medium"
247 fontSize: "medium"
258− font.bold: true
259− color: Theme.palette.selected.backgroundText
248+ color: type == Notification.SnapDecision ? sdFontColor : Theme.palette.selected.backgroundText
260 elide: Text.ElideRight
249 elide: Text.ElideRight
261 textFormat: Text.PlainText
250 textFormat: Text.PlainText
262 }
251 }
@@ -271,14 +260,27 @@ Item {
271 }
260 }
272 visible: body != ""
261 visible: body != ""
273 fontSize: "small"
262 fontSize: "small"
274− color: Theme.palette.selected.backgroundText
263+ color: type == Notification.SnapDecision ? sdFontColor : Theme.palette.selected.backgroundText
275− opacity: 0.6
276 wrapMode: Text.WordWrap
264 wrapMode: Text.WordWrap
277− maximumLineCount: 10
265+ maximumLineCount: 2
278 elide: Text.ElideRight
266 elide: Text.ElideRight
279 textFormat: Text.PlainText
267 textFormat: Text.PlainText
280 }
268 }
281 }
269 }
270+
271+ Image {
272+ id: secondaryIcon
273+
274+ objectName: "secondaryIcon"
275+ width: units.gu(3)
276+ height: units.gu(3)
277+ visible: status === Image.Ready
278+ fillMode: Image.PreserveAspectCrop
279+ }
280+ }
281+
282+ ListItem.ThinDivider {
283+ visible: type == Notification.SnapDecision
282 }
284 }
283
285
284 Column {
286 Column {
@@ -321,6 +323,74 @@ Item {
321 }
323 }
322 }
324 }
323
325
326+ Column {
327+ id: oneOverTwoCase
328+
329+ anchors {
330+ left: parent.left
331+ right: parent.right
332+ margins: contentSpacing
333+ }
334+
335+ spacing: contentSpacing
336+
337+ visible: notification.type == Notification.SnapDecision && oneOverTwoRepeaterTop.count == 3
338+
339+ Repeater {
340+ id: oneOverTwoRepeaterTop
341+
342+ model: notification.actions
343+ delegate: Loader {
344+ id: oneOverTwoLoaderTop
345+
346+ property string actionId: id
347+ property string actionLabel: label
348+
349+ Component {
350+ id: oneOverTwoButtonTop
351+
352+ Button {
353+ objectName: "notify_oot_button" + index
354+ width: oneOverTwoCase.width
355+ text: oneOverTwoLoaderTop.actionLabel
356+ color: notification.hints["x-canonical-private-affirmative-tint"] == "true" ? green : sdDarkGrey
357+ onClicked: notification.notification.invokeAction(oneOverTwoLoaderTop.actionId)
358+ }
359+ }
360+ sourceComponent: index == 0 ? oneOverTwoButtonTop : undefined
361+ }
362+ }
363+
364+ Row {
365+ spacing: contentSpacing
366+
367+ Repeater {
368+ id: oneOverTwoRepeaterBottom
369+
370+ model: notification.actions
371+ delegate: Loader {
372+ id: oneOverTwoLoaderBottom
373+
374+ property string actionId: id
375+ property string actionLabel: label
376+
377+ Component {
378+ id: oneOverTwoButtonBottom
379+
380+ Button {
381+ objectName: "notify_oot_button" + index
382+ width: oneOverTwoCase.width / 2 - spacing * 2
383+ text: oneOverTwoLoaderBottom.actionLabel
384+ color: index == 1 && notification.hints["x-canonical-private-rejection-tint"] == "true" ? red : sdDarkGrey
385+ onClicked: notification.notification.invokeAction(oneOverTwoLoaderBottom.actionId)
386+ }
387+ }
388+ sourceComponent: (index == 1 || index == 2) ? oneOverTwoButtonBottom : undefined
389+ }
390+ }
391+ }
392+ }
393+
324 Row {
394 Row {
325 id: buttonRow
395 id: buttonRow
326
396
@@ -328,9 +398,10 @@ Item {
328 anchors {
398 anchors {
329 left: parent.left
399 left: parent.left
330 right: parent.right
400 right: parent.right
401+ margins: contentSpacing
331 }
402 }
332− visible: notification.type == Notification.SnapDecision && actionRepeater.count > 0
403+ visible: notification.type == Notification.SnapDecision && actionRepeater.count > 0 && !oneOverTwoCase.visible
333− spacing: units.gu(1)
404+ spacing: units.gu(2)
334 layoutDirection: Qt.RightToLeft
405 layoutDirection: Qt.RightToLeft
335
406
336 Repeater {
407 Repeater {
@@ -347,10 +418,19 @@ Item {
347 id: actionButton
418 id: actionButton
348
419
349 Button {
420 Button {
350− objectName: "button" + index
421+ objectName: "notify_button" + index
351− width: buttonRow.width / 2 - spacing
422+ width: buttonRow.width / 2 - spacing*2
352 text: loader.actionLabel
423 text: loader.actionLabel
353− gradient: notification.hints["x-canonical-private-button-tint"] == "true" && index == 0 ? greenGradient : darkgreyGradient
424+ color: {
425+ var result = sdDarkGrey;
426+ if (index == 0 && notification.hints["x-canonical-private-affirmative-tint"] == "true") {
427+ result = green;
428+ }
429+ if (index == 1 && notification.hints["x-canonical-private-rejection-tint"] == "true") {
430+ result = red;
431+ }
432+ return result;
433+ }
354 onClicked: notification.notification.invokeAction(loader.actionId)
434 onClicked: notification.notification.invokeAction(loader.actionId)
355 }
435 }
356 }
436 }
@@ -362,10 +442,16 @@ Item {
362 ComboButton {
442 ComboButton {
363 id: comboButton
443 id: comboButton
364
444
365− objectName: "button2"
445+ objectName: "notify_button2"
366 width: parent.width
446 width: parent.width
447+ anchors {
448+ left: parent.left
449+ right: parent.right
450+ margins: contentSpacing
451+ }
452+
367− visible: notification.type == Notification.SnapDecision && actionRepeater.count > 3
453+ visible: notification.type == Notification.SnapDecision && actionRepeater.count > 3 && !oneOverTwoCase.visible
368− gradient: darkgreyGradient
454+ color: sdDarkGrey
369 onClicked: notification.notification.invokeAction(comboRepeater.itemAt(2).actionId)
455 onClicked: notification.notification.invokeAction(comboRepeater.itemAt(2).actionId)
370 expanded: false
456 expanded: false
371 expandedHeight: (comboRepeater.count - 2) * units.gu(4) + units.gu(.5)
457 expandedHeight: (comboRepeater.count - 2) * units.gu(4) + units.gu(.5)
@@ -399,7 +485,7 @@ Item {
399 MouseArea {
485 MouseArea {
400 id: comboInputArea
486 id: comboInputArea
401
487
402− objectName: "button" + index
488+ objectName: "notify_button" + index
403 width: comboButton.width
489 width: comboButton.width
404 height: comboIcon.height + units.gu(2)
490 height: comboIcon.height + units.gu(2)
405
491
@@ -421,7 +507,7 @@ Item {
421 }
507 }
422 width: units.gu(2)
508 width: units.gu(2)
423 height: units.gu(2)
509 height: units.gu(2)
424− color: "white"
510+ color: sdFontColor
425 name: splitLabel[2]
511 name: splitLabel[2]
426 }
512 }
427
513
@@ -434,7 +520,7 @@ Item {
434 verticalCenter: comboIcon.verticalCenter
520 verticalCenter: comboIcon.verticalCenter
435 }
521 }
436 fontSize: "small"
522 fontSize: "small"
437− color: "white"
523+ color: sdFontColor
438 text: splitLabel[3]
524 text: splitLabel[3]
439 }
525 }
440 }
526 }
qml/Notifications/NotificationMenuItemFactory.qml+4
@@ -55,6 +55,7 @@ Loader {
55 anchors {
55 anchors {
56 left: parent.left
56 left: parent.left
57 right: parent.right
57 right: parent.right
58+ margins: spacing
58 }
59 }
59
60
60 Component.onCompleted: {
61 Component.onCompleted: {
@@ -65,6 +66,7 @@ Loader {
65
66
66 Label {
67 Label {
67 text: menuData.label
68 text: menuData.label
69+ color: notification.sdFontColor
68 }
70 }
69
71
70 TextField {
72 TextField {
@@ -98,11 +100,13 @@ Loader {
98 id: checkBox
100 id: checkBox
99
101
100 checked: false
102 checked: false
103+ activeFocusOnPress: false
101 }
104 }
102
105
103 Label {
106 Label {
104 anchors.verticalCenter: checkBox.verticalCenter
107 anchors.verticalCenter: checkBox.verticalCenter
105 text: i18n.tr("Show password")
108 text: i18n.tr("Show password")
109+ color: notification.sdFontColor
106 }
110 }
107 }
111 }
108 }
112 }
qml/Notifications/Notifications.qml+1−1
@@ -33,7 +33,7 @@ ListView {
33 id: snapDecisionProxyModel
33 id: snapDecisionProxyModel
34
34
35 model: notificationList.model
35 model: notificationList.model
36− filterRole: UnityNotifications.ModelInterface.RoleType
36+ filterRole: UnityNotifications.ModelInterface != undefined ? UnityNotifications.ModelInterface.RoleType : 0
37 filterRegExp: RegExp(UnityNotifications.Notification.SnapDecision)
37 filterRegExp: RegExp(UnityNotifications.Notification.SnapDecision)
38 }
38 }
39
39
qml/Panel/Indicators/IndicatorsLight.qml+4−7
@@ -27,12 +27,9 @@ QtObject {
27 Component.onDestruction: Lights.state = Lights.Off
27 Component.onDestruction: Lights.state = Lights.Off
28
28
29 // QtObject does not have children
29 // QtObject does not have children
30− property var _connections: Connections {
30+ property var _binding: Binding {
31− id: powerConnection
32−
33− target: Powerd
31+ target: Lights
34− onDisplayPowerStateChange: {
32+ property: "state"
35− Lights.state = (status === Powerd.Off) ? Lights.On : Lights.Off
33+ value: (Powerd.status === Powerd.Off) ? Lights.On : Lights.Off
36− }
37 }
34 }
38}
35}
qml/Shell.qml+18−20
@@ -22,6 +22,7 @@ import Ubuntu.Components 0.1
22import Ubuntu.Components.Popups 1.0
22import Ubuntu.Components.Popups 1.0
23import Ubuntu.Gestures 0.1
23import Ubuntu.Gestures 0.1
24import Ubuntu.SystemImage 0.1
24import Ubuntu.SystemImage 0.1
25+import Ubuntu.Telephony 0.1 as Telephony
25import Unity.Connectivity 0.1
26import Unity.Connectivity 0.1
26import Unity.Launcher 0.1
27import Unity.Launcher 0.1
27import Utils 0.1
28import Utils 0.1
@@ -146,6 +147,7 @@ Item {
146 lockscreen.show();
147 lockscreen.show();
147 }
148 }
148 greeter.hide();
149 greeter.hide();
150+ launcher.hide();
149 }
151 }
150
152
151 onFocusedApplicationIdChanged: {
153 onFocusedApplicationIdChanged: {
@@ -164,6 +166,7 @@ Item {
164 // for an emergency call or accepted an incoming call.
166 // for an emergency call or accepted an incoming call.
165 setFakeActiveForApp(appId)
167 setFakeActiveForApp(appId)
166 }
168 }
169+ launcher.hide();
167 }
170 }
168 }
171 }
169
172
@@ -233,6 +236,15 @@ Item {
233 }
236 }
234 }
237 }
235 }
238 }
239+ Connections {
240+ target: SessionManager
241+ onSessionStopping: {
242+ if (!session.parentSession && !session.application) {
243+ // nothing is using it. delete it right away
244+ session.release();
245+ }
246+ }
247+ }
236
248
237 Lockscreen {
249 Lockscreen {
238 id: lockscreen
250 id: lockscreen
@@ -448,18 +460,9 @@ Item {
448 id: powerConnection
460 id: powerConnection
449 target: Powerd
461 target: Powerd
450
462
451− onDisplayPowerStateChange: {
463+ onStatusChanged: {
452− // We ignore any display-off signals when the proximity sensor
453− // is active. This usually indicates something like a phone call.
454− if (status == Powerd.Off && reason != Powerd.Proximity && !edgeDemo.running) {
464+ if (Powerd.status === Powerd.Off && !callManager.hasCalls && !edgeDemo.running) {
455− greeter.showNow();
465+ greeter.showNow()
456− }
457−
458− // No reason to chew demo CPU when user isn't watching
459− if (status == Powerd.Off) {
460− edgeDemo.paused = true;
461− } else if (status == Powerd.On) {
462− edgeDemo.paused = false;
463 }
466 }
464 }
467 }
465 }
468 }
@@ -539,7 +542,7 @@ Item {
539 }
542 }
540 }
543 }
541 onDashSwipeChanged: {
544 onDashSwipeChanged: {
542− if (dashSwipe && ApplicationManager.focusedApplicationId !== "unity8-dash") {
545+ if (dashSwipe) {
543 dash.setCurrentScope("clickscope", false, true)
546 dash.setCurrentScope("clickscope", false, true)
544 }
547 }
545 }
548 }
@@ -563,7 +566,7 @@ Item {
563 visible: notifications.useModal && !greeter.shown && (notifications.state == "narrow")
566 visible: notifications.useModal && !greeter.shown && (notifications.state == "narrow")
564 color: "#000000"
567 color: "#000000"
565 anchors.fill: parent
568 anchors.fill: parent
566− opacity: 0.5
569+ opacity: 0.9
567
570
568 MouseArea {
571 MouseArea {
569 anchors.fill: parent
572 anchors.fill: parent
@@ -596,12 +599,6 @@ Item {
596 }
599 }
597 }
600 }
598
601
599− Binding {
600− target: i18n
601− property: "domain"
602− value: "unity8"
603− }
604−
605 Dialogs {
602 Dialogs {
606 id: dialogs
603 id: dialogs
607 anchors.fill: parent
604 anchors.fill: parent
@@ -632,6 +629,7 @@ Item {
632 EdgeDemo {
629 EdgeDemo {
633 id: edgeDemo
630 id: edgeDemo
634 z: alphaDisclaimerLabel.z + 10
631 z: alphaDisclaimerLabel.z + 10
632+ paused: Powerd.status === Powerd.Off // Saves power
635 greeter: greeter
633 greeter: greeter
636 launcher: launcher
634 launcher: launcher
637 indicators: panel.indicators
635 indicators: panel.indicators
qml/Stages/Animations/BaseSurfaceAnimation.qml → qml/Stages/Animations/BaseSessionAnimation.qmlrenamed+23−20
@@ -37,57 +37,60 @@ import QtQuick 2.0
37 */
37 */
38Item {
38Item {
39 id: base
39 id: base
40− property Item surface: null
40+ property var container
41+ objectName: "sessionAnimation"
41
42
42− // changes applied when state changes to "in"
43+ // changes applied when state changes to "from"
43− property list<QtObject> outChanges
44+ property list<QtObject> fromChanges
44− // transition animations when changing state to "in"
45+ // transition animations when changing state to "from"
45− property list<QtObject> outAnimations
46+ property list<QtObject> fromAnimations
46
47
47− // changes applied when state changes to "out"
48+ // changes applied when state changes to "to"
48− property list<QtObject> inChanges
49+ property list<QtObject> toChanges
49− // transition animations when changing state to "out"
50+ // transition animations when changing state to "to"
50− property list<QtObject> inAnimations
51+ property list<QtObject> toAnimations
51
52
52 function start() {
53 function start() {
53− // "prep" state forces outChanges without transition animations.
54+ // "prep" state forces toChanges without transition animations.
54 state = "prep"
55 state = "prep"
55− state = "in";
56+ state = "to";
56 }
57 }
57 function end() {
58 function end() {
58− state = "out";
59+ state = "from";
59 }
60 }
60
61
62+ signal completed()
63+
61 states: [
64 states: [
62 State {
65 State {
63 name: "baseAnimation"
66 name: "baseAnimation"
64− PropertyChanges { target: base.surface; anchors.fill: undefined }
67+ PropertyChanges { target: container; anchors.fill: undefined }
65 },
68 },
66
69
67 State {
70 State {
68 name: "prep"
71 name: "prep"
69 extend: "baseAnimation"
72 extend: "baseAnimation"
70− changes: outChanges
73+ changes: fromChanges
71 },
74 },
72 State {
75 State {
73− name: "out"
76+ name: "from"
74 extend: "prep"
77 extend: "prep"
75 },
78 },
76 State {
79 State {
77 name: "in"
80 name: "in"
78 extend: "baseAnimation"
81 extend: "baseAnimation"
79− changes: inChanges
82+ changes: toChanges
80 }
83 }
81 ]
84 ]
82
85
83 transitions: [
86 transitions: [
84 Transition {
87 Transition {
85− to: "out"
88+ to: "from"
86− animations: outAnimations
89+ animations: fromAnimations
87 },
90 },
88 Transition {
91 Transition {
89− to: "in"
92+ to: "to"
90− animations: inAnimations
93+ animations: toAnimations
91 }
94 }
92 ]
95 ]
93}
96}
qml/Stages/Animations/DarkenAndFadeInAnimation.qmldeleted−48
@@ -1,48 +0,0 @@
1−/*
2− * Copyright (C) 2014 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 1.1
19−
20−BaseSurfaceAnimation {
21− id: animation
22−
23− property Rectangle darkenItem: Rectangle {
24− parent: animation.surface.parent
25− anchors.fill: parent
26− color: Qt.rgba(0,0,0,0.0)
27− }
28−
29− outChanges: [ PropertyChanges { target: animation.surface; opacity: 0.0 } ]
30− outAnimations: [
31− SequentialAnimation {
32− UbuntuNumberAnimation { target: animation.surface; property: "opacity"; duration: UbuntuAnimation.FastDuration }
33− ColorAnimation { target: darkenItem; duration: UbuntuAnimation.FastDuration }
34− ScriptAction { script: { if (animation.parent.removing) animation.surface.release(); } }
35− }
36− ]
37−
38− inChanges: [
39− PropertyChanges { target: darkenItem; color: Qt.rgba(0,0,0,0.7) },
40− PropertyChanges { target: animation.surface; opacity: 1.0 }
41− ]
42− inAnimations: [
43− SequentialAnimation {
44− ColorAnimation { target: darkenItem; duration: UbuntuAnimation.FastDuration }
45− UbuntuNumberAnimation { target: animation.surface; property: "opacity"; duration: UbuntuAnimation.FastDuration }
46− }
47− ]
48−}
qml/Stages/Animations/SwipeFromBottomAnimation.qml+24−19
@@ -15,34 +15,39 @@
15 */
15 */
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18+import Ubuntu.Components 1.1
18
19
19−BaseSurfaceAnimation {
20+BaseSessionAnimation {
20 id: animation
21 id: animation
21
22
23+ fromChanges: [
24+ AnchorChanges {
25+ target: container;
22− outChanges: [ AnchorChanges { target: animation.surface; anchors.top: animation.parent.bottom } ]
26+ anchors.top: container.parent.bottom
23− outAnimations: [
27+ }
28+ ]
29+ fromAnimations: [
24 SequentialAnimation {
30 SequentialAnimation {
31+ // clip so we don't go out of parent's bounds during spread
25− PropertyAction { target: animation.parent; property: "clip"; value: true }
32+ PropertyAction { target: container.parent; property: "clip"; value: true }
26− AnchorAnimation { easing.type: Easing.InOutQuad; duration: 400 }
33+ AnchorAnimation { easing: UbuntuAnimation.StandardEasing; duration: UbuntuAnimation.BriskDuration }
27− PropertyAction { target: animation.surface; property: "visible"; value: !animation.parent.removing }
28− PropertyAction { target: animation.parent; property: "clip"; value: false }
34+ PropertyAction { target: container.parent; property: "clip"; value: false }
29− ScriptAction { script: { if (animation.parent.removing) animation.surface.release(); } }
35+ ScriptAction { script: { animation.completed(); } }
30 }
36 }
31 ]
37 ]
32
38
33− inChanges: [
39+ toChanges: [
34 AnchorChanges {
40 AnchorChanges {
35− target: animation.surface;
41+ target: container;
36− anchors.top: animation.parent.top
42+ anchors.top: container.parent.top
37− anchors.right: undefined
38− anchors.bottom: undefined
39− anchors.left: undefined
40− } ]
43+ }
41− inAnimations: [
44+ ]
45+ toAnimations: [
42 SequentialAnimation {
46 SequentialAnimation {
47+ // clip so we don't go out of parent's bounds during spread
43− PropertyAction { target: animation.parent; property: "clip"; value: true }
48+ PropertyAction { target: container.parent; property: "clip"; value: true }
44− AnchorAnimation { easing.type: Easing.InOutQuad; duration: 400 }
49+ AnchorAnimation { easing: UbuntuAnimation.StandardEasing; duration: UbuntuAnimation.BriskDuration }
45− PropertyAction { target: animation.parent; property: "clip"; value: false }
50+ PropertyAction { target: container.parent; property: "clip"; value: false }
46 }
51 }
47 ]
52 ]
48}
53}
qml/Stages/Animations/SwipeUpAnimation.qmldeleted−49
@@ -1,49 +0,0 @@
1−/*
2− * Copyright (C) 2014 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−
19−BaseSurfaceAnimation {
20− id: animation
21−
22− outAnimations: [
23− SequentialAnimation {
24− PropertyAction { target: animation.parent; property: "clip"; value: true }
25− PropertyAction { target: animation.surface; property: "visible"; value: true }
26− AnchorAnimation { easing.type: Easing.InOutQuad; duration: 400 }
27− PropertyAction { target: animation.parent; property: "clip"; value: false }
28− ScriptAction { script: { if (animation.parent.removing) animation.surface.release(); } }
29− }
30− ]
31−
32− inChanges: [
33− AnchorChanges {
34− target: animation.surface;
35− anchors.top: undefined
36− anchors.right: undefined
37− anchors.bottom: animation.parent.top
38− anchors.left: undefined
39− }
40− ]
41− inAnimations: [
42− SequentialAnimation {
43− PropertyAction { target: animation.parent; property: "clip"; value: true }
44− AnchorAnimation { easing.type: Easing.InOutQuad; duration: 400 }
45− PropertyAction { target: animation.surface; property: "visible"; value: false}
46− PropertyAction { target: animation.parent; property: "clip"; value: false }
47− }
48− ]
49−}
qml/Stages/ApplicationWindow.qml+51−71
@@ -23,9 +23,9 @@ Item {
23
23
24 // to be read from outside
24 // to be read from outside
25 readonly property bool fullscreen: application ? application.fullscreen : false
25 readonly property bool fullscreen: application ? application.fullscreen : false
26+ property alias interactive: sessionContainer.interactive
26
27
27 // to be set from outside
28 // to be set from outside
28− property bool interactive: true
29 property QtObject application
29 property QtObject application
30
30
31 QtObject {
31 QtObject {
@@ -35,16 +35,14 @@ Item {
35 // (in order to avoid breaking qml binding due to a javascript exception)
35 // (in order to avoid breaking qml binding due to a javascript exception)
36 readonly property string name: root.application ? root.application.name : ""
36 readonly property string name: root.application ? root.application.name : ""
37 readonly property url icon: root.application ? root.application.icon : ""
37 readonly property url icon: root.application ? root.application.icon : ""
38− readonly property Item surface: root.application ? root.application.surface : null
39 readonly property int applicationState: root.application ? root.application.state : -1
38 readonly property int applicationState: root.application ? root.application.state : -1
40− readonly property var promptSurfaces: root.application ? root.application.promptSurfaces : null
41
39
42 // Whether the Application had a surface before but lost it.
40 // Whether the Application had a surface before but lost it.
43− property bool hadSurface: false
41+ property bool hadSurface: sessionContainer.surfaceContainer.hadSurface
44
42
45 property bool needToTakeScreenshot:
43 property bool needToTakeScreenshot:
46− d.surface && d.surfaceInitialized && screenshotImage.status === Image.Null
44+ sessionContainer.surface && d.surfaceInitialized && screenshotImage.status === Image.Null
47− && d.applicationState === ApplicationInfo.Stopped
45+ && d.applicationState === ApplicationInfoInterface.Stopped
48 onNeedToTakeScreenshotChanged: {
46 onNeedToTakeScreenshotChanged: {
49 if (needToTakeScreenshot) {
47 if (needToTakeScreenshot) {
50 screenshotImage.take();
48 screenshotImage.take();
@@ -55,12 +53,13 @@ Item {
55 // might show the UI accommodating due to surface resizes on startup.
53 // might show the UI accommodating due to surface resizes on startup.
56 // Remove this when possible
54 // Remove this when possible
57 property bool surfaceInitialized: false
55 property bool surfaceInitialized: false
58− onSurfaceChanged: {
56+
57+ function forceSurfaceActiveFocusIfReady() {
59− if (surface) {
58+ if (sessionContainer.surface !== null &&
60− surfaceInitTimer.start();
59+ sessionContainer.surface.focus &&
61− } else {
60+ sessionContainer.surface.parent === sessionContainer.surfaceContainer &&
62− hadSurface = true;
61+ sessionContainer.surface.enabled) {
63− surfaceInitialized = false;
62+ sessionContainer.surface.forceActiveFocus();
64 }
63 }
65 }
64 }
66 }
65 }
@@ -68,40 +67,16 @@ Item {
68 Timer {
67 Timer {
69 id: surfaceInitTimer
68 id: surfaceInitTimer
70 interval: 100
69 interval: 100
71− onTriggered: { if (d.surface) {d.surfaceInitialized = true;} }
70+ onTriggered: { if (sessionContainer.surface) {d.surfaceInitialized = true;} }
72 }
71 }
73
72
74− Binding {
75− target: d.surface
76− when: d.surface
77− property: "enabled"
78− value: root.interactive
79− }
80− Binding {
81− target: d.surface
82− when: d.surface
83− property: "focus"
84− value: root.interactive
85− }
86 Connections {
73 Connections {
87− target: d.surface
74+ target: sessionContainer.surface
88 // FIXME: I would rather not need to do this, but currently it doesn't get
75 // FIXME: I would rather not need to do this, but currently it doesn't get
89 // active focus without it and I don't know why.
76 // active focus without it and I don't know why.
90− onFocusChanged: forceSurfaceActiveFocusIfReady();
77+ onFocusChanged: d.forceSurfaceActiveFocusIfReady();
91− onParentChanged: forceSurfaceActiveFocusIfReady();
78+ onParentChanged: d.forceSurfaceActiveFocusIfReady();
92− onEnabledChanged: forceSurfaceActiveFocusIfReady();
79+ onEnabledChanged: d.forceSurfaceActiveFocusIfReady();
93− function forceSurfaceActiveFocusIfReady() {
94− if (d.surface.focus && d.surface.parent === surfaceContainer && d.surface.enabled) {
95− d.surface.forceActiveFocus();
96− }
97− }
98− }
99−
100− SurfaceContainer {
101− id: surfaceContainer
102− objectName: "surfaceContainer"
103− anchors.fill: parent
104− surface: d.surface
105 }
80 }
106
81
107 Image {
82 Image {
@@ -126,24 +101,23 @@ Item {
126 id: splashLoader
101 id: splashLoader
127 visible: active
102 visible: active
128 active: false
103 active: false
129− anchors.fill: surfaceContainer
104+ anchors.fill: parent
130 sourceComponent: Component {
105 sourceComponent: Component {
131 Splash { name: d.name; image: d.icon }
106 Splash { name: d.name; image: d.icon }
132 }
107 }
133 }
108 }
134
109
135− Repeater {
110+ SessionContainer {
136− model: d.promptSurfaces
111+ id: sessionContainer
137−
112+ session: application ? application.session : null
138− delegate: SurfaceContainer {
139− anchors {
113+ anchors.fill: parent
140− fill: surfaceContainer
141− }
142−
143− surface: modelData
144
114
145− Component.onCompleted: {
115+ onSurfaceChanged: {
146− animateIn();
116+ if (sessionContainer.surface) {
117+ surfaceInitTimer.start();
118+ d.forceSurfaceActiveFocusIfReady();
119+ } else {
120+ d.surfaceInitialized = false;
147 }
121 }
148 }
122 }
149 }
123 }
@@ -154,23 +128,23 @@ Item {
154 State {
128 State {
155 name: "void"
129 name: "void"
156 when:
130 when:
157− d.hadSurface && (!d.surface || !d.surfaceInitialized)
131+ d.hadSurface && (!sessionContainer.surface || !d.surfaceInitialized)
158 &&
132 &&
159 screenshotImage.status !== Image.Ready
133 screenshotImage.status !== Image.Ready
160 },
134 },
161 State {
135 State {
162 name: "splashScreen"
136 name: "splashScreen"
163 when:
137 when:
164− !d.hadSurface && (!d.surface || !d.surfaceInitialized)
138+ !d.hadSurface && (!sessionContainer.surface || !d.surfaceInitialized)
165 &&
139 &&
166 screenshotImage.status !== Image.Ready
140 screenshotImage.status !== Image.Ready
167 },
141 },
168 State {
142 State {
169 name: "surface"
143 name: "surface"
170 when:
144 when:
171− (d.surface && d.surfaceInitialized)
145+ (sessionContainer.surface && d.surfaceInitialized)
172 &&
146 &&
173− (d.applicationState !== ApplicationInfo.Stopped
147+ (d.applicationState !== ApplicationInfoInterface.Stopped
174 || screenshotImage.status !== Image.Ready)
148 || screenshotImage.status !== Image.Ready)
175 },
149 },
176 State {
150 State {
@@ -178,8 +152,8 @@ Item {
178 when:
152 when:
179 screenshotImage.status === Image.Ready
153 screenshotImage.status === Image.Ready
180 &&
154 &&
181− (d.applicationState === ApplicationInfo.Stopped
155+ (d.applicationState === ApplicationInfoInterface.Stopped
182− || !d.surface || !d.surfaceInitialized)
156+ || !sessionContainer.surface || !d.surfaceInitialized)
183 }
157 }
184 ]
158 ]
185
159
@@ -187,14 +161,18 @@ Item {
187 Transition {
161 Transition {
188 from: ""; to: "splashScreen"
162 from: ""; to: "splashScreen"
189 PropertyAction { target: splashLoader; property: "active"; value: true }
163 PropertyAction { target: splashLoader; property: "active"; value: true }
164+ PropertyAction { target: sessionContainer.surfaceContainer
165+ property: "visible"; value: false }
190 },
166 },
191 Transition {
167 Transition {
192 from: "splashScreen"; to: "surface"
168 from: "splashScreen"; to: "surface"
193 SequentialAnimation {
169 SequentialAnimation {
194− PropertyAction { target: surfaceContainer
170+ PropertyAction { target: sessionContainer.surfaceContainer
171+ property: "opacity"; value: 0.0 }
172+ PropertyAction { target: sessionContainer.surfaceContainer
195 property: "visible"; value: true }
173 property: "visible"; value: true }
196− UbuntuNumberAnimation { target: splashLoader; property: "opacity";
174+ UbuntuNumberAnimation { target: sessionContainer.surfaceContainer; property: "opacity";
197− from: 1.0; to: 0.0
175+ from: 0.0; to: 1.0
198 duration: UbuntuAnimation.BriskDuration }
176 duration: UbuntuAnimation.BriskDuration }
199 PropertyAction { target: splashLoader; property: "active"; value: false }
177 PropertyAction { target: splashLoader; property: "active"; value: false }
200 }
178 }
@@ -203,11 +181,13 @@ Item {
203 from: "surface"; to: "splashScreen"
181 from: "surface"; to: "splashScreen"
204 SequentialAnimation {
182 SequentialAnimation {
205 PropertyAction { target: splashLoader; property: "active"; value: true }
183 PropertyAction { target: splashLoader; property: "active"; value: true }
206− PropertyAction { target: surfaceContainer
184+ PropertyAction { target: sessionContainer.surfaceContainer
207 property: "visible"; value: true }
185 property: "visible"; value: true }
208 UbuntuNumberAnimation { target: splashLoader; property: "opacity";
186 UbuntuNumberAnimation { target: splashLoader; property: "opacity";
209 from: 0.0; to: 1.0
187 from: 0.0; to: 1.0
210 duration: UbuntuAnimation.BriskDuration }
188 duration: UbuntuAnimation.BriskDuration }
189+ PropertyAction { target: sessionContainer.surfaceContainer
190+ property: "visible"; value: false }
211 }
191 }
212 },
192 },
213 Transition {
193 Transition {
@@ -218,15 +198,15 @@ Item {
218 UbuntuNumberAnimation { target: screenshotImage; property: "opacity";
198 UbuntuNumberAnimation { target: screenshotImage; property: "opacity";
219 from: 0.0; to: 1.0
199 from: 0.0; to: 1.0
220 duration: UbuntuAnimation.BriskDuration }
200 duration: UbuntuAnimation.BriskDuration }
221− PropertyAction { target: surfaceContainer
201+ PropertyAction { target: sessionContainer.surfaceContainer
222 property: "visible"; value: false }
202 property: "visible"; value: false }
223− ScriptAction { script: { if (d.surface) { d.surface.release(); } } }
203+ ScriptAction { script: { if (sessionContainer.session) { sessionContainer.session.release(); } } }
224 }
204 }
225 },
205 },
226 Transition {
206 Transition {
227 from: "screenshot"; to: "surface"
207 from: "screenshot"; to: "surface"
228 SequentialAnimation {
208 SequentialAnimation {
229− PropertyAction { target: surfaceContainer
209+ PropertyAction { target: sessionContainer.surfaceContainer
230 property: "visible"; value: true }
210 property: "visible"; value: true }
231 UbuntuNumberAnimation { target: screenshotImage; property: "opacity";
211 UbuntuNumberAnimation { target: screenshotImage; property: "opacity";
232 from: 1.0; to: 0.0
212 from: 1.0; to: 0.0
@@ -238,16 +218,16 @@ Item {
238 Transition {
218 Transition {
239 from: "surface"; to: "void"
219 from: "surface"; to: "void"
240 SequentialAnimation {
220 SequentialAnimation {
241− PropertyAction { target: surfaceContainer; property: "visible"; value: false }
221+ PropertyAction { target: sessionContainer.surfaceContainer; property: "visible"; value: false }
242− ScriptAction { script: { if (d.surface) { d.surface.release(); } } }
222+ ScriptAction { script: { if (sessionContainer.session) { sessionContainer.session.release(); } } }
243 }
223 }
244 },
224 },
245 Transition {
225 Transition {
246 from: "void"; to: "surface"
226 from: "void"; to: "surface"
247 SequentialAnimation {
227 SequentialAnimation {
248− PropertyAction { target: surfaceContainer; property: "opacity"; value: 0.0 }
228+ PropertyAction { target: sessionContainer.surfaceContainer; property: "opacity"; value: 0.0 }
249− PropertyAction { target: surfaceContainer; property: "visible"; value: true }
229+ PropertyAction { target: sessionContainer.surfaceContainer; property: "visible"; value: true }
250− UbuntuNumberAnimation { target: surfaceContainer; property: "opacity";
230+ UbuntuNumberAnimation { target: sessionContainer.surfaceContainer; property: "opacity";
251 from: 0.0; to: 1.0
231 from: 0.0; to: 1.0
252 duration: UbuntuAnimation.BriskDuration }
232 duration: UbuntuAnimation.BriskDuration }
253 }
233 }
qml/Stages/PhoneStage.qml+6−1
@@ -44,6 +44,9 @@ Rectangle {
44 }
44 }
45
45
46 onInverseProgressChanged: {
46 onInverseProgressChanged: {
47+ // This can't be a simple binding because that would be triggered after this handler
48+ // while we need it active before doing the anition left/right
49+ priv.animateX = (inverseProgress == 0)
47 if (inverseProgress == 0 && priv.oldInverseProgress > 0) {
50 if (inverseProgress == 0 && priv.oldInverseProgress > 0) {
48 // left edge drag released. Minimum distance is given by design.
51 // left edge drag released. Minimum distance is given by design.
49 if (priv.oldInverseProgress > units.gu(22)) {
52 if (priv.oldInverseProgress > units.gu(22)) {
@@ -92,6 +95,7 @@ Rectangle {
92 property var focusedAppDelegate: null
95 property var focusedAppDelegate: null
93
96
94 property real oldInverseProgress: 0
97 property real oldInverseProgress: 0
98+ property bool animateX: true
95
99
96 onFocusedAppIdChanged: focusedAppDelegate = spreadRepeater.itemAt(0);
100 onFocusedAppIdChanged: focusedAppDelegate = spreadRepeater.itemAt(0);
97
101
@@ -311,7 +315,8 @@ Rectangle {
311 Behavior on x {
315 Behavior on x {
312 enabled: root.spreadEnabled &&
316 enabled: root.spreadEnabled &&
313 !spreadView.active &&
317 !spreadView.active &&
314− !snapAnimation.running
318+ !snapAnimation.running &&
319+ priv.animateX
315 UbuntuNumberAnimation {
320 UbuntuNumberAnimation {
316 duration: UbuntuAnimation.FastDuration
321 duration: UbuntuAnimation.FastDuration
317 onRunningChanged: {
322 onRunningChanged: {
qml/Stages/SessionContainer.qmlnew file+143
@@ -0,0 +1,143 @@
1+/*
2+ * Copyright 2014 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+*/
16+
17+import QtQuick 2.0
18+import "Animations"
19+
20+Item {
21+ id: root
22+ objectName: "sessionContainer"
23+ property QtObject session
24+ readonly property var childSessions: session ? session.childSessions : null
25+ readonly property alias surface: _surfaceContainer.surface
26+ property bool interactive: true
27+
28+ readonly property alias surfaceContainer: _surfaceContainer
29+ SurfaceContainer {
30+ id: _surfaceContainer
31+ anchors.fill: parent
32+ surface: session ? session.surface : null
33+ }
34+
35+ Binding {
36+ target: surfaceContainer.surface
37+ when: surfaceContainer.surface
38+ property: "enabled"
39+ value: root.interactive
40+ }
41+ Binding {
42+ target: surfaceContainer.surface
43+ when: surfaceContainer.surface
44+ property: "focus"
45+ value: root.interactive
46+ }
47+
48+ Repeater {
49+ model: root.childSessions
50+
51+ delegate: Loader {
52+ objectName: "childDelegate" + index
53+ anchors.fill: surfaceContainer
54+
55+ // Only way to do recursive qml items.
56+ source: Qt.resolvedUrl("SessionContainer.qml")
57+
58+ Binding {
59+ target: item; when: item
60+ property: "interactive"; value: root.interactive
61+ }
62+
63+ Binding {
64+ target: item; when: item
65+ property: "session"; value: modelData
66+ }
67+
68+ Binding {
69+ target: item; when: item
70+ property: "width"; value: root.width
71+ }
72+
73+ Binding {
74+ target: item; when: item
75+ property: "height"; value: root.height
76+ }
77+ }
78+ }
79+
80+ states: [
81+ State {
82+ name: "rootSession"
83+ when: root.session && !root.session.parentSession
84+ },
85+
86+ State {
87+ name: "childSession"
88+ when: root.session && root.session.parentSession !== null && root.session.live
89+ && !root.session.surface
90+ },
91+
92+ State {
93+ name: "childSessionReady"
94+ when: root.session && root.session.parentSession !== null && root.session.live
95+ && root.session.surface !== null
96+ },
97+
98+ State {
99+ name: "childSessionZombie"
100+ when: root.session && root.session.parentSession !== null && !root.session.live
101+ }
102+ ]
103+
104+ transitions: [
105+ Transition {
106+ to: "childSessionReady"
107+ ScriptAction { script: { if (!surfaceContainer.hadSurface) { animateIn(swipeFromBottom); } } }
108+ },
109+ Transition {
110+ to: "childSessionZombie"
111+ ScriptAction { script: { animateOut(); } }
112+ }
113+ ]
114+
115+ function animateIn(component) {
116+ var animation = component.createObject(root, { "container": root, });
117+ animation.start();
118+
119+ var tmp = d.animations;
120+ tmp.push(animation);
121+ d.animations = tmp;
122+ }
123+
124+ function animateOut() {
125+ if (d.animations.length > 0) {
126+ var tmp = d.animations;
127+ var popped = tmp.pop();
128+ popped.completed.connect(function() { root.session.release(); } );
129+ popped.end();
130+ d.animations = tmp;
131+ }
132+ }
133+
134+ Component {
135+ id: swipeFromBottom
136+ SwipeFromBottomAnimation {}
137+ }
138+
139+ QtObject {
140+ id: d
141+ property var animations: []
142+ }
143+}
qml/Stages/SurfaceContainer.qml+22−67
@@ -15,86 +15,41 @@
15*/
15*/
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18−import "Animations"
18+import Ubuntu.Components 1.1
19
19
20Item {
20Item {
21− id: container
21+ id: root
22+ objectName: "surfaceContainer"
22 property Item surface: null
23 property Item surface: null
23− property bool removing: false
24+ property bool hadSurface: false
24
25
25 onSurfaceChanged: {
26 onSurfaceChanged: {
26 if (surface) {
27 if (surface) {
27− surface.parent = container;
28+ surface.parent = root;
28− surface.z = 1;
29+ } else {
30+ hadSurface = true;
29 }
31 }
30 }
32 }
31 Binding {
33 Binding {
32 target: surface
34 target: surface
33− property: "anchors.fill"; value: container
35+ property: "anchors.fill"; value: root
34 }
36 }
35
37
36− Connections {
38+ states: [
37− target: surface
39+ State {
38− onRemoved: {
40+ name: "zombie"
39− container.removing = true;
41+ when: surface && !surface.live
40−
41− var childSurfaces = surface.childSurfaces;
42− for (var i=0; i<childSurfaces.length; i++) {
43− childSurfaces[i].removed();
44− }
45−
46− animateOut();
47 }
42 }
48− }
43+ ]
49−
44+ transitions: [
50− Repeater {
45+ Transition {
51− model: surface ? surface.childSurfaces : null
46+ from: ""; to: "zombie"
52−
47+ SequentialAnimation {
53− delegate: Loader {
48+ UbuntuNumberAnimation { target: surface; property: "opacity"; to: 0.0
54− z: 2
49+ duration: UbuntuAnimation.BriskDuration }
55− anchors {
50+ PropertyAction { target: surface; property: "visible"; value: false }
56− fill: container
51+ ScriptAction { script: { if (root.surface) { root.surface.release(); } } }
57− topMargin: container.surface.anchors.topMargin
58− rightMargin: container.surface.anchors.rightMargin
59− bottomMargin: container.surface.anchors.bottomMargin
60− leftMargin: container.surface.anchors.leftMargin
61 }
52 }
62−
63− // Only way to do recursive qml items.
64− source: Qt.resolvedUrl("SurfaceContainer.qml")
65− onLoaded: {
66− item.surface = modelData;
67− item.animateIn();
68− }
69− }
70− }
71−
72− function animateIn() {
73− var animation = swipeFromBottom.createObject(container, { "surface": container.surface });
74− animation.start();
75−
76− var tmp = d.animations;
77− tmp.push(animation);
78− d.animations = tmp;
79− }
80−
81− function animateOut() {
82− if (d.animations.length > 0) {
83− var tmp = d.animations;
84− var popped = tmp.pop();
85− popped.end();
86− d.animations = tmp;
87 }
53 }
88− }
54+ ]
89−
90− QtObject {
91− id: d
92− property var animations: []
93− property var currentAnimation: animations.length > 0 ? animations[animations.length-1] : undefined
94− }
95−
96− Component {
97− id: swipeFromBottom
98− SwipeFromBottomAnimation {}
99− }
100}
55}
qml/Stages/TabletStage.qml+5
@@ -36,6 +36,9 @@ Rectangle {
36 property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.
36 property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.
37
37
38 onInverseProgressChanged: {
38 onInverseProgressChanged: {
39+ // This can't be a simple binding because that would be triggered after this handler
40+ // while we need it active before doing the anition left/right
41+ spreadView.animateX = (inverseProgress == 0)
39 if (inverseProgress == 0 && priv.oldInverseProgress > 0) {
42 if (inverseProgress == 0 && priv.oldInverseProgress > 0) {
40 // left edge drag released. Minimum distance is given by design.
43 // left edge drag released. Minimum distance is given by design.
41 if (priv.oldInverseProgress > units.gu(22)) {
44 if (priv.oldInverseProgress > units.gu(22)) {
@@ -193,6 +196,8 @@ Rectangle {
193 property int draggedDelegateCount: 0
196 property int draggedDelegateCount: 0
194 property int closingIndex: -1
197 property int closingIndex: -1
195
198
199+ property bool animateX: true
200+
196 property bool sideStageDragging: sideStageDragHandle.dragging
201 property bool sideStageDragging: sideStageDragHandle.dragging
197 property real sideStageDragProgress: sideStageDragHandle.progress
202 property real sideStageDragProgress: sideStageDragHandle.progress
198
203
qml/Stages/TransformedTabletSpreadDelegate.qml+2−1
@@ -138,7 +138,8 @@ SpreadDelegate {
138 enabled: !spreadView.active &&
138 enabled: !spreadView.active &&
139 !snapAnimation.running &&
139 !snapAnimation.running &&
140 model.appId !== "unity8-dash" &&
140 model.appId !== "unity8-dash" &&
141− !spreadView.sideStageDragging
141+ !spreadView.sideStageDragging &&
142+ spreadView.animateX
142 UbuntuNumberAnimation {
143 UbuntuNumberAnimation {
143 duration: UbuntuAnimation.FastDuration
144 duration: UbuntuAnimation.FastDuration
144 }
145 }
run_on_device.sh+43−41
@@ -4,8 +4,8 @@ USER=phablet
4USER_ID=32011
4USER_ID=32011
5PACKAGE=unity8
5PACKAGE=unity8
6BINARY=unity8
6BINARY=unity8
7−TARGET_IP=${TARGET_IP-127.0.0.1}
7+TARGET_IP=127.0.0.1
8−TARGET_SSH_PORT=${TARGET_SSH_PORT-2222}
8+TARGET_SSH_PORT=2222
9TARGET_DEBUG_PORT=3768
9TARGET_DEBUG_PORT=3768
10RUN_OPTIONS=-qmljsdebugger=port:$TARGET_DEBUG_PORT
10RUN_OPTIONS=-qmljsdebugger=port:$TARGET_DEBUG_PORT
11SETUP=false
11SETUP=false
@@ -14,18 +14,23 @@ PINLOCK=false
14KEYLOCK=false
14KEYLOCK=false
15NUM_JOBS='$(( `grep -c ^processor /proc/cpuinfo` + 1 ))'
15NUM_JOBS='$(( `grep -c ^processor /proc/cpuinfo` + 1 ))'
16FLIPPED=false
16FLIPPED=false
17−CHROOT_PREFIX="/data/ubuntu"
18SSH_WAS_STARTED=0
17SSH_WAS_STARTED=0
19SSH_STARTED=0
18SSH_STARTED=0
19+PASSWORD=""
20+PASSFILE=""
20
21
21usage() {
22usage() {
22− echo "usage: run_on_device [OPTIONS]\n"
23+ echo "usage: run_on_device -a SUDO_PASSWORD [OPTIONS]"
24+ echo
23− echo "Script to setup a build environment for the shell and sync build and run it on the device\n"
25+ echo "Script to setup a build environment for the shell and sync build and run it on the device"
26+ echo
24 echo "OPTIONS:"
27 echo "OPTIONS:"
28+ echo " -a, --password The sudo password to use"
25− echo " -s, --setup Setup the build environment"
29+ echo " -s, --setup Setup the build environment"
30+ echo " -g, --gdb Run with gdb"
26− echo " -p, --pinlock Enable a PIN lock screen when running"
31+ echo " -p, --pinlock Enable a PIN lock screen when running"
27− echo " -k, --keylock Enable a Keyboard lock screen when running"
32+ echo " -k, --keylock Enable a Keyboard lock screen when running"
28− echo ""
33+ echo
29 echo "IMPORTANT:"
34 echo "IMPORTANT:"
30 echo " * Make sure to have networking setup on the device beforehand."
35 echo " * Make sure to have networking setup on the device beforehand."
31 echo " * Execute that script from a directory containing unity8 code."
36 echo " * Execute that script from a directory containing unity8 code."
@@ -34,7 +39,7 @@ usage() {
34
39
35start_ssh() {
40start_ssh() {
36 if [ $SSH_STARTED -eq 0 ]; then
41 if [ $SSH_STARTED -eq 0 ]; then
37− exec_with_adb initctl start ssh
42+ adb_sudo initctl start ssh
38 SSH_STARTED=1
43 SSH_STARTED=1
39 fi
44 fi
40}
45}
@@ -44,25 +49,13 @@ exec_with_ssh() {
44 ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -t $USER@$TARGET_IP -p $TARGET_SSH_PORT sudo -u $USER -i bash -ic \"$@\"
49 ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -t $USER@$TARGET_IP -p $TARGET_SSH_PORT sudo -u $USER -i bash -ic \"$@\"
45}
50}
46
51
47−exec_with_adb() {
52+adb_sudo() {
48− if $FLIPPED; then
53+ adb shell "SUDO_ASKPASS=${PASSFILE} sudo --askpass $@"
49− adb shell $@
50− else
51− adb shell chroot /data/ubuntu /usr/bin/env -i PATH=/bin:/usr/bin:/sbin:/usr/sbin:/tools/bin "$@"
52− fi
53−}
54−
55−adb_root() {
56− adb root
57− adb wait-for-device
58}
54}
59
55
60install_ssh_key() {
56install_ssh_key() {
61− ssh-keygen -R $TARGET_IP
62− HOME_DIR="${CHROOT_PREFIX}/home/phablet"
57+ HOME_DIR="/home/phablet"
63 adb push ~/.ssh/id_rsa.pub $HOME_DIR/.ssh/authorized_keys
58 adb push ~/.ssh/id_rsa.pub $HOME_DIR/.ssh/authorized_keys
64− adb shell chown $USER_ID:$USER_ID $HOME_DIR/.ssh
65− adb shell chown $USER_ID:$USER_ID $HOME_DIR/.ssh/authorized_keys
66 adb shell chmod 700 $HOME_DIR/.ssh
59 adb shell chmod 700 $HOME_DIR/.ssh
67 adb shell chmod 600 $HOME_DIR/.ssh/authorized_keys
60 adb shell chmod 600 $HOME_DIR/.ssh/authorized_keys
68}
61}
@@ -73,8 +66,14 @@ setup_adb_forwarding() {
73}
66}
74
67
75install_dependencies() {
68install_dependencies() {
76− exec_with_adb apt-get update
69+ phablet-config writable-image --remotepassword ${PASSWORD} -p build-essential \
77− exec_with_adb apt-get -y --force-yes install build-essential rsync bzr ccache gdb ninja-build devscripts equivs unity-plugin-scopes
70+ -p rsync \
71+ -p bzr \
72+ -p ccache \
73+ -p gdb \
74+ -p ninja-build \
75+ -p devscripts \
76+ -p equivs
78}
77}
79
78
80sync_code() {
79sync_code() {
@@ -108,12 +107,13 @@ run() {
108 exec_with_ssh "start unity8"
107 exec_with_ssh "start unity8"
109}
108}
110
109
111−set -- `getopt -n$0 -u -a --longoptions="setup,gdb,pinlock,keylock,help" "sgpkh" "$@"`
110+set -- `getopt -n$0 -u -a --longoptions="password:,setup,gdb,pinlock,keylock,help" "a:sgpkh" "$@"`
112
111
113# FIXME: giving incorrect arguments does not call usage and exit
112# FIXME: giving incorrect arguments does not call usage and exit
114while [ $# -gt 0 ]
113while [ $# -gt 0 ]
115do
114do
116 case "$1" in
115 case "$1" in
116+ -a|--password) PASSWORD=$2;;
117 -s|--setup) SETUP=true;;
117 -s|--setup) SETUP=true;;
118 -g|--gdb) GDB=true;;
118 -g|--gdb) GDB=true;;
119 -p|--pinlock) PINLOCK=true;;
119 -p|--pinlock) PINLOCK=true;;
@@ -124,21 +124,21 @@ do
124 shift
124 shift
125done
125done
126
126
127+if [ -z "${PASSWORD}" ]; then
128+ echo "ERROR: You need to provide a sudo password..."
129+ echo
130+ usage
131+fi
127
132
128−adb_root
133+PASSFILE=$( adb shell "FILE=\`mktemp\`
129−[ "${TARGET_IP}" = "127.0.0.1" ] && setup_adb_forwarding
134+ echo \"#!/bin/sh\" > \$FILE
135+ echo \"echo \\\"${PASSWORD}\\\"\" >> \$FILE
136+ chmod +x \$FILE
137+ echo \$FILE" | tr -d '\r' )
130
138
131−if [ "`adb shell 'grep -q Ubuntu /etc/lsb-release 2> /dev/null && echo -n FLIPPED'`" = "FLIPPED" ]; then
139+setup_adb_forwarding
132− FLIPPED=true
133− CHROOT_PREFIX=""
134− if [ "${TARGET_IP}" != "127.0.0.1" ]; then
135− echo "ERROR: Flipped image detected, adb over TCP/IP isn't supported, yet :/"
136− echo "Unset TARGET_IP and try again."
137− exit 2
138− fi
139−fi
140
140
141−status_output=$(exec_with_adb initctl status ssh)
141+status_output=$(adb_sudo initctl status ssh)
142if [[ $status_output == "ssh start/running, process "* ]]; then
142if [[ $status_output == "ssh start/running, process "* ]]; then
143 SSH_WAS_STARTED=1
143 SSH_WAS_STARTED=1
144fi
144fi
@@ -158,6 +158,8 @@ else
158 run
158 run
159fi
159fi
160
160
161+adb shell "rm ${PASSFILE}"
162+
161if [ $SSH_WAS_STARTED -eq 0 ]; then
163if [ $SSH_WAS_STARTED -eq 0 ]; then
162− exec_with_adb initctl stop ssh
164+ adb_sudo initctl stop ssh
163fi
165fi
src/Dash/main.cpp+1
@@ -68,6 +68,7 @@ int main(int argc, const char *argv[])
68 }
68 }
69
69
70 bindtextdomain("unity8", translationDirectory().toUtf8().data());
70 bindtextdomain("unity8", translationDirectory().toUtf8().data());
71+ textdomain("unity8");
71
72
72 QQuickView* view = new QQuickView();
73 QQuickView* view = new QQuickView();
73 view->setResizeMode(QQuickView::SizeRootObjectToView);
74 view->setResizeMode(QQuickView::SizeRootObjectToView);
src/main.cpp+1
@@ -108,6 +108,7 @@ Load the testability driver");
108 }
108 }
109
109
110 bindtextdomain("unity8", translationDirectory().toUtf8().data());
110 bindtextdomain("unity8", translationDirectory().toUtf8().data());
111+ textdomain("unity8");
111
112
112 QQuickView* view = new QQuickView();
113 QQuickView* view = new QQuickView();
113 view->setResizeMode(QQuickView::SizeRootObjectToView);
114 view->setResizeMode(QQuickView::SizeRootObjectToView);
tests/autopilot/unity8/application_lifecycle/tests/test_application_lifecycle.py+4−2
@@ -97,7 +97,8 @@ class ApplicationLifecycleTests(tests.ApplicationLifeCycleTestCase):
97 self.assertThat(greeter.created, Eventually(Equals(True)))
97 self.assertThat(greeter.created, Eventually(Equals(True)))
98
98
99 application_name = self.launch_fake_app()
99 application_name = self.launch_fake_app()
100− self.assertThat(greeter.created, Eventually(Equals(False)))
100+ greeter.wait_swiped_away()
101+ process_helpers.unlock_unity()
101 self.assert_current_focused_application(application_name)
102 self.assert_current_focused_application(application_name)
102
103
103 def test_greeter_hides_on_app_focus(self):
104 def test_greeter_hides_on_app_focus(self):
@@ -113,7 +114,8 @@ class ApplicationLifecycleTests(tests.ApplicationLifeCycleTestCase):
113 self.assertThat(greeter.created, Eventually(Equals(True)))
114 self.assertThat(greeter.created, Eventually(Equals(True)))
114
115
115 self.launch_upstart_application(application_name)
116 self.launch_upstart_application(application_name)
116− self.assertThat(greeter.created, Eventually(Equals(False)))
117+ greeter.wait_swiped_away()
118+ process_helpers.unlock_unity()
117 self.assert_current_focused_application(application_name)
119 self.assert_current_focused_application(application_name)
118
120
119 def test_click_dash_icon_must_unfocus_application(self):
121 def test_click_dash_icon_must_unfocus_application(self):
tests/autopilot/unity8/process_helpers.py+12−17
@@ -20,6 +20,7 @@
20import logging
20import logging
21import subprocess
21import subprocess
22import sys
22import sys
23+import dbus
23
24
24# This has to work in both python 3 (ap 1.5) and py2 (ap legacy 1.4.1) so we
25# This has to work in both python 3 (ap 1.5) and py2 (ap legacy 1.4.1) so we
25# pick the correct location in each case. Remove the py2 branch once we no
26# pick the correct location in each case. Remove the py2 branch once we no
@@ -82,22 +83,16 @@ def unlock_unity(unity_proxy_obj=None):
82 if greeter.created is False:
83 if greeter.created is False:
83 raise RuntimeWarning("Greeter appears to be already unlocked.")
84 raise RuntimeWarning("Greeter appears to be already unlocked.")
84
85
85− # Because of potential input jerkiness under heavy load,
86+ bus = dbus.SessionBus()
86− # retry unlocking the greeter two times.
87+ dbus_proxy = bus.get_object("com.canonical.UnityGreeter", "/")
87− # https://bugs.launchpad.net/ubuntu/+bug/1260113
88−
89− retries = 3
90− while retries > 0:
91− try:
88+ try:
92− greeter.swipe()
89+ dbus_proxy.HideGreeter()
93− except AssertionError:
90+ except dbus.DBusException:
94− retries -= 1
95− if retries == 0:
96− raise
97− logger.info("Failed to unlock greeter, trying again...")
91+ logger.info("Failed to unlock greeter")
92+ raise
98− else:
93+ else:
94+ greeter.created.wait_for(False)
99− logger.info("Greeter unlocked, continuing.")
95+ logger.info("Greeter unlocked, continuing.")
100− break
101
96
102
97
103def lock_unity(unity_proxy_obj=None):
98def lock_unity(unity_proxy_obj=None):
@@ -198,7 +193,7 @@ def get_job_status(name):
198 ], universal_newlines=True)
193 ], universal_newlines=True)
199 except subprocess.CalledProcessError as error:
194 except subprocess.CalledProcessError as error:
200 raise JobError(
195 raise JobError(
201− "Unable to get {}'s status: {}".format(name, error)
196+ "Unable to get {}'s status: {}".format(name, error)
202 )
197 )
203
198
204
199
tests/autopilot/unity8/shell/emulators/greeter.py+4−1
@@ -25,6 +25,9 @@ from unity8.shell.emulators import UnityEmulatorBase
25class Greeter(UnityEmulatorBase):
25class Greeter(UnityEmulatorBase):
26 """An emulator that understands the greeter screen."""
26 """An emulator that understands the greeter screen."""
27
27
28+ def wait_swiped_away(self):
29+ self.showProgress.wait_for(0)
30+
28 def swipe(self):
31 def swipe(self):
29 """Swipe the greeter screen away."""
32 """Swipe the greeter screen away."""
30 self.created.wait_for(True)
33 self.created.wait_for(True)
@@ -37,7 +40,7 @@ class Greeter(UnityEmulatorBase):
37 stop_y = start_y
40 stop_y = start_y
38 self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
41 self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
39
42
40− self.showProgress.wait_for(0)
43+ self.wait_swiped_away()
41
44
42 def get_prompt(self):
45 def get_prompt(self):
43 return self.select_single(
46 return self.select_single(
tests/autopilot/unity8/shell/tests/test_lock_screen.py+8−9
@@ -20,7 +20,6 @@
20
20
21from __future__ import absolute_import
21from __future__ import absolute_import
22
22
23−from unity8.process_helpers import unlock_unity
24from unity8.shell import with_lightdm_mock
23from unity8.shell import with_lightdm_mock
25from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
24from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
26
25
@@ -45,11 +44,11 @@ class TestLockscreen(UnityTestCase):
45 @with_lightdm_mock("single-pin")
44 @with_lightdm_mock("single-pin")
46 def test_can_unlock_pin_screen(self):
45 def test_can_unlock_pin_screen(self):
47 """Must be able to unlock the PIN entry lock screen."""
46 """Must be able to unlock the PIN entry lock screen."""
48− unity_proxy = self.launch_unity()
47+ self.launch_unity()
49 greeter = self.main_window.get_greeter()
48 greeter = self.main_window.get_greeter()
50
49
51 if greeter.narrowMode:
50 if greeter.narrowMode:
52− unlock_unity(unity_proxy)
51+ greeter.swipe()
53 lockscreen = self._wait_for_lockscreen()
52 lockscreen = self._wait_for_lockscreen()
54 self.main_window.enter_pin_code("1234")
53 self.main_window.enter_pin_code("1234")
55 self.assertThat(lockscreen.shown, Eventually(Equals(False)))
54 self.assertThat(lockscreen.shown, Eventually(Equals(False)))
@@ -60,11 +59,11 @@ class TestLockscreen(UnityTestCase):
60 @with_lightdm_mock("single-passphrase")
59 @with_lightdm_mock("single-passphrase")
61 def test_can_unlock_passphrase_screen(self):
60 def test_can_unlock_passphrase_screen(self):
62 """Must be able to unlock the passphrase entry screen."""
61 """Must be able to unlock the passphrase entry screen."""
63− unity_proxy = self.launch_unity()
62+ self.launch_unity()
64 greeter = self.main_window.get_greeter()
63 greeter = self.main_window.get_greeter()
65
64
66 if greeter.narrowMode:
65 if greeter.narrowMode:
67− unlock_unity(unity_proxy)
66+ greeter.swipe()
68 lockscreen = self._wait_for_lockscreen()
67 lockscreen = self._wait_for_lockscreen()
69 self._enter_pin_passphrase("password")
68 self._enter_pin_passphrase("password")
70 self.assertThat(lockscreen.shown, Eventually(Equals(False)))
69 self.assertThat(lockscreen.shown, Eventually(Equals(False)))
@@ -75,11 +74,11 @@ class TestLockscreen(UnityTestCase):
75 @with_lightdm_mock("single-pin")
74 @with_lightdm_mock("single-pin")
76 def test_pin_screen_wrong_code(self):
75 def test_pin_screen_wrong_code(self):
77 """Entering the wrong pin code must not dismiss the lock screen."""
76 """Entering the wrong pin code must not dismiss the lock screen."""
78− unity_proxy = self.launch_unity()
77+ self.launch_unity()
79 greeter = self.main_window.get_greeter()
78 greeter = self.main_window.get_greeter()
80
79
81 if greeter.narrowMode:
80 if greeter.narrowMode:
82− unlock_unity(unity_proxy)
81+ greeter.swipe()
83 lockscreen = self._wait_for_lockscreen()
82 lockscreen = self._wait_for_lockscreen()
84 self.main_window.enter_pin_code("4321")
83 self.main_window.enter_pin_code("4321")
85 pinentryField = self.main_window.get_pinentryField()
84 pinentryField = self.main_window.get_pinentryField()
@@ -94,11 +93,11 @@ class TestLockscreen(UnityTestCase):
94 @with_lightdm_mock("single-passphrase")
93 @with_lightdm_mock("single-passphrase")
95 def test_passphrase_screen_wrong_password(self):
94 def test_passphrase_screen_wrong_password(self):
96 """Entering the wrong password must not dismiss the lock screen."""
95 """Entering the wrong password must not dismiss the lock screen."""
97− unity_proxy = self.launch_unity()
96+ self.launch_unity()
98 greeter = self.main_window.get_greeter()
97 greeter = self.main_window.get_greeter()
99
98
100 if greeter.narrowMode:
99 if greeter.narrowMode:
101− unlock_unity(unity_proxy)
100+ greeter.swipe()
102 lockscreen = self._wait_for_lockscreen()
101 lockscreen = self._wait_for_lockscreen()
103 self._enter_pin_passphrase("foobar")
102 self._enter_pin_passphrase("foobar")
104 pinentryField = self.main_window.get_pinentryField()
103 pinentryField = self.main_window.get_pinentryField()
tests/autopilot/unity8/shell/tests/test_notifications.py+61−97
@@ -135,10 +135,7 @@ class InteractiveNotificationBase(NotificationsBase):
135 actions = [("action_id", "dummy")]
135 actions = [("action_id", "dummy")]
136 hints = [
136 hints = [
137 ("x-canonical-switch-to-application", "true"),
137 ("x-canonical-switch-to-application", "true"),
138− (
139− "x-canonical-secondary-icon",
138+ ("x-canonical-secondary-icon","dialer")
140− self._get_icon_path('applicationIcons/dialer-app.png')
141− )
142 ]
139 ]
143
140
144 self._create_interactive_notification(
141 self._create_interactive_notification(
@@ -170,20 +167,19 @@ class InteractiveNotificationBase(NotificationsBase):
170 body = "Frank Zappa\n+44 (0)7736 027340"
167 body = "Frank Zappa\n+44 (0)7736 027340"
171 icon_path = self._get_icon_path('avatars/anna_olsson.png')
168 icon_path = self._get_icon_path('avatars/anna_olsson.png')
172 hints = [
169 hints = [
173− (
174− "x-canonical-secondary-icon",
170+ ("x-canonical-secondary-icon", "incoming-call"),
175− self._get_icon_path('applicationIcons/dialer-app.png')
176− ),
177 ("x-canonical-snap-decisions", "true"),
171 ("x-canonical-snap-decisions", "true"),
172+ ("x-canonical-private-affirmative-tint", "true"),
173+ ("x-canonical-private-rejection-tint", "true"),
178 ]
174 ]
179
175
180 actions = [
176 actions = [
181 ('action_accept', 'Hold + Answer'),
177 ('action_accept', 'Hold + Answer'),
182 ('action_decline_1', 'End + Answer'),
178 ('action_decline_1', 'End + Answer'),
183 ('action_decline_2', 'Decline'),
179 ('action_decline_2', 'Decline'),
184− ('action_decline_3', 'messages:I missed your call - can you call me now?'),
180+ ('action_decline_3', 'message:I missed your call - can you call me now?'),
185− ('action_decline_4', 'messages:I\'m running late. I\'m on my way.'),
181+ ('action_decline_4', 'message:I\'m running late. I\'m on my way.'),
186− ('action_decline_5', 'messages:I\'m busy at the moment. I\'ll call later.'),
182+ ('action_decline_5', 'message:I\'m busy at the moment. I\'ll call later.'),
187 ('action_decline_6', 'edit:Custom'),
183 ('action_decline_6', 'edit:Custom'),
188 ]
184 ]
189
185
@@ -204,13 +200,53 @@ class InteractiveNotificationBase(NotificationsBase):
204 notification.pointing_device.click_object(
200 notification.pointing_device.click_object(
205 notification.select_single(objectName="combobutton_dropdown"))
201 notification.select_single(objectName="combobutton_dropdown"))
206 self.assertThat(
202 self.assertThat(
207− notification.select_single(objectName="button2").expanded,
203+ notification.select_single(objectName="notify_button2").expanded,
208 Eventually(Equals(True)))
204 Eventually(Equals(True)))
209 time.sleep(2)
205 time.sleep(2)
210 notification.pointing_device.click_object(
206 notification.pointing_device.click_object(
211− notification.select_single(objectName="button4"))
207+ notification.select_single(objectName="notify_button4"))
212 self.assert_notification_action_id_was_called("action_decline_4")
208 self.assert_notification_action_id_was_called("action_decline_4")
213
209
210+
211+ def test_sd_one_over_two_layout(self):
212+ """Snap-decision with three actions should use one-over two button layout."""
213+ unity_proxy = self.launch_unity()
214+ unlock_unity(unity_proxy)
215+
216+ summary = "Theatre at Ferria Stadium"
217+ body = "at Ferria Stadium in Bilbao, Spain\n07578545317"
218+ hints = [
219+ ("x-canonical-snap-decisions", "true"),
220+ ("x-canonical-non-shaped-icon", "true"),
221+ ("x-canonical-private-affirmative-tint", "true")
222+ ]
223+
224+ actions = [
225+ ('action_accept', 'Ok'),
226+ ('action_decline_1', 'Snooze'),
227+ ('action_decline_2', 'View'),
228+ ]
229+
230+ self._create_interactive_notification(
231+ summary,
232+ body,
233+ None,
234+ "NORMAL",
235+ actions,
236+ hints
237+ )
238+
239+ # verify and interact with the triggered snap-decision notification
240+ notify_list = self._get_notifications_list()
241+ get_notification = lambda: notify_list.wait_select_single(
242+ 'Notification', objectName='notification1')
243+ notification = get_notification()
244+ self._assert_notification(
245+ notification, summary, body, False, False, 1.0)
246+ notification.pointing_device.click_object(
247+ notification.select_single(objectName="notify_oot_button0"))
248+ self.assert_notification_action_id_was_called("action_accept")
249+
214 def test_modal_sd_without_greeter(self):
250 def test_modal_sd_without_greeter(self):
215 """Snap-decision should block input to shell without greeter."""
251 """Snap-decision should block input to shell without greeter."""
216 unity_proxy = self.launch_unity()
252 unity_proxy = self.launch_unity()
@@ -222,6 +258,8 @@ class InteractiveNotificationBase(NotificationsBase):
222 hints = [
258 hints = [
223 ("x-canonical-snap-decisions", "true"),
259 ("x-canonical-snap-decisions", "true"),
224 ("x-canonical-non-shaped-icon", "true"),
260 ("x-canonical-non-shaped-icon", "true"),
261+ ("x-canonical-private-affirmative-tint", "true"),
262+ ("x-canonical-private-rejection-tint", "true"),
225 ]
263 ]
226
264
227 actions = [
265 actions = [
@@ -253,7 +291,7 @@ class InteractiveNotificationBase(NotificationsBase):
253 self._assert_notification(
291 self._assert_notification(
254 notification, summary, body, True, False, 1.0)
292 notification, summary, body, True, False, 1.0)
255 notification.pointing_device.click_object(
293 notification.pointing_device.click_object(
256− notification.select_single(objectName="button0"))
294+ notification.select_single(objectName="notify_button0"))
257 self.assert_notification_action_id_was_called("action_accept")
295 self.assert_notification_action_id_was_called("action_accept")
258
296
259 def test_modal_sd_with_greeter(self):
297 def test_modal_sd_with_greeter(self):
@@ -266,6 +304,8 @@ class InteractiveNotificationBase(NotificationsBase):
266 hints = [
304 hints = [
267 ("x-canonical-snap-decisions", "true"),
305 ("x-canonical-snap-decisions", "true"),
268 ("x-canonical-non-shaped-icon", "true"),
306 ("x-canonical-non-shaped-icon", "true"),
307+ ("x-canonical-private-affirmative-tint", "true"),
308+ ("x-canonical-private-rejection-tint", "true"),
269 ]
309 ]
270
310
271 actions = [
311 actions = [
@@ -296,7 +336,7 @@ class InteractiveNotificationBase(NotificationsBase):
296 self._assert_notification(
336 self._assert_notification(
297 notification, summary, body, True, False, 1.0)
337 notification, summary, body, True, False, 1.0)
298 notification.pointing_device.click_object(
338 notification.pointing_device.click_object(
299− notification.select_single(objectName="button0"))
339+ notification.select_single(objectName="notify_button0"))
300 self.assert_notification_action_id_was_called("action_accept")
340 self.assert_notification_action_id_was_called("action_accept")
301
341
302 def _create_interactive_notification(
342 def _create_interactive_notification(
@@ -438,10 +478,7 @@ class EphemeralNotificationsTests(NotificationsBase):
438 "join me and Anna?"
478 "join me and Anna?"
439 icon_path = self._get_icon_path('avatars/anna_olsson.png')
479 icon_path = self._get_icon_path('avatars/anna_olsson.png')
440 hints = [
480 hints = [
441− (
442− "x-canonical-secondary-icon",
481+ ("x-canonical-secondary-icon", "message")
443− self._get_icon_path('applicationIcons/dialer-app.png')
444− )
445 ]
482 ]
446
483
447 notification = shell.create_ephemeral_notification(
484 notification = shell.create_ephemeral_notification(
@@ -474,17 +511,13 @@ class EphemeralNotificationsTests(NotificationsBase):
474 notify_list = self._get_notifications_list()
511 notify_list = self._get_notifications_list()
475
512
476 summary = "Upload of image completed"
513 summary = "Upload of image completed"
477− hints = [
478− (
479− "x-canonical-secondary-icon",
480− self._get_icon_path('applicationIcons/facebook.png')
514+ icon_path = self._get_icon_path('applicationIcons/facebook.png')
481− )
515+ hints=[]
482− ]
483
516
484 notification = shell.create_ephemeral_notification(
517 notification = shell.create_ephemeral_notification(
485 summary,
518 summary,
486 None,
519 None,
487− None,
520+ icon_path,
488 hints,
521 hints,
489 "NORMAL",
522 "NORMAL",
490 )
523 )
@@ -497,8 +530,8 @@ class EphemeralNotificationsTests(NotificationsBase):
497 notification(),
530 notification(),
498 summary,
531 summary,
499 None,
532 None,
500− False,
501 True,
533 True,
534+ False,
502 1.0
535 1.0
503 )
536 )
504
537
@@ -683,7 +716,7 @@ class EphemeralNotificationsTests(NotificationsBase):
683 body = 'This bubble uses the icon-title-body layout with a ' \
716 body = 'This bubble uses the icon-title-body layout with a ' \
684 'secondary icon.'
717 'secondary icon.'
685 icon_path = self._get_icon_path('avatars/anna_olsson.png')
718 icon_path = self._get_icon_path('avatars/anna_olsson.png')
686− hint_icon = self._get_icon_path('applicationIcons/dialer-app.png')
719+ hint_icon = 'dialer'
687
720
688 notification = shell.create_ephemeral_notification(
721 notification = shell.create_ephemeral_notification(
689 summary,
722 summary,
@@ -718,72 +751,3 @@ class EphemeralNotificationsTests(NotificationsBase):
718 self.assertThat(get_notification, Eventually(NotEquals(None)))
751 self.assertThat(get_notification, Eventually(NotEquals(None)))
719 self._assert_notification(
752 self._assert_notification(
720 get_notification(), summary, body, False, False, 1.0)
753 get_notification(), summary, body, False, False, 1.0)
721−
722− def test_append_hint(self):
723− """Notification has to accumulate body-text using append-hint."""
724− unity_proxy = self.launch_unity()
725− unlock_unity(unity_proxy)
726−
727− notify_list = self._get_notifications_list()
728−
729− summary = 'Cole Raby'
730− body = 'Hey Bro Coly!'
731− icon_path = self._get_icon_path('avatars/amanda.png')
732− body_sum = body
733− notification = shell.create_ephemeral_notification(
734− summary,
735− body,
736− icon_path,
737− hints=[('x-canonical-append', 'true')]
738− )
739−
740− notification.show()
741−
742− get_notification = lambda: notify_list.wait_select_single(
743− 'Notification', objectName='notification1')
744−
745− notification = get_notification()
746− self._assert_notification(
747− notification,
748− summary,
749− body_sum,
750− True,
751− False,
752− 1.0
753− )
754−
755− bodies = [
756− 'What\'s up dude?',
757− 'Did you watch the air-race in Oshkosh last week?',
758− 'Phil owned the place like no one before him!',
759− 'Did really everything in the race work according to regulations?',
760− 'Somehow I think to remember Burt Williams did cut corners and '
761− 'was not punished for this.',
762− 'Hopefully the referees will watch the videos of the race.',
763− 'Burt could get fined with US$ 50000 for that rule-violation :)'
764− ]
765−
766− for new_body in bodies:
767− body = new_body
768− body_sum += '\n' + body
769− notification = shell.create_ephemeral_notification(
770− summary,
771− body,
772− icon_path,
773− hints=[('x-canonical-append', 'true')]
774− )
775− notification.show()
776−
777− get_notification = lambda: notify_list.wait_select_single(
778− 'Notification',
779− objectName='notification1'
780− )
781− notification = get_notification()
782− self._assert_notification(
783− notification,
784− summary,
785− body_sum,
786− True,
787− False,
788− 1.0
789− )
tests/mocks/AccountsService/AccountsService.qmltypes+1
@@ -26,5 +26,6 @@ Module {
26 Property { name: "backgroundFile"; type: "string" }
26 Property { name: "backgroundFile"; type: "string" }
27 Property { name: "statsWelcomeScreen"; type: "bool" }
27 Property { name: "statsWelcomeScreen"; type: "bool" }
28 Property { name: "passwordDisplayHint"; type: "PasswordDisplayHint"; isReadonly: true }
28 Property { name: "passwordDisplayHint"; type: "PasswordDisplayHint"; isReadonly: true }
29+ Property { name: "failedLogins"; type: "uint" }
29 }
30 }
30}
31}
tests/mocks/LightDM/LightDM.qmltypes+2
@@ -27,6 +27,7 @@ Module {
27 name: "showPrompt"
27 name: "showPrompt"
28 Parameter { name: "text"; type: "string" }
28 Parameter { name: "text"; type: "string" }
29 Parameter { name: "isSecret"; type: "bool" }
29 Parameter { name: "isSecret"; type: "bool" }
30+ Parameter { name: "isDefaultPrompt"; type: "bool" }
30 }
31 }
31 Signal { name: "authenticationComplete" }
32 Signal { name: "authenticationComplete" }
32 Signal {
33 Signal {
@@ -34,6 +35,7 @@ Module {
34 Parameter { name: "user"; type: "string" }
35 Parameter { name: "user"; type: "string" }
35 }
36 }
36 Signal { name: "isActiveChanged" }
37 Signal { name: "isActiveChanged" }
38+ Signal { name: "isAuthenticatedChanged" }
37 Signal { name: "showGreeter" }
39 Signal { name: "showGreeter" }
38 Signal {
40 Signal {
39 name: "requestAuthenticationUser"
41 name: "requestAuthenticationUser"
tests/mocks/Powerd/Powerd.cpp+15−1
@@ -19,6 +19,20 @@
19#include "Powerd.h"
19#include "Powerd.h"
20
20
21Powerd::Powerd(QObject* parent)
21Powerd::Powerd(QObject* parent)
22− : QObject(parent)
22+ : QObject(parent),
23+ m_status(Powerd::Status::On)
23{
24{
24}
25}
26+
27+void Powerd::setStatus(Powerd::Status status)
28+{
29+ if (m_status != status) {
30+ m_status = status;
31+ Q_EMIT statusChanged(DisplayStateChangeReason::Unknown);
32+ }
33+}
34+
35+Powerd::Status Powerd::status() const
36+{
37+ return m_status;
38+}
tests/mocks/Powerd/Powerd.h+8−1
@@ -26,6 +26,7 @@ class Powerd: public QObject
26 Q_OBJECT
26 Q_OBJECT
27 Q_ENUMS(Status)
27 Q_ENUMS(Status)
28 Q_ENUMS(DisplayStateChangeReason)
28 Q_ENUMS(DisplayStateChangeReason)
29+ Q_PROPERTY(Status status READ status WRITE setStatus NOTIFY statusChanged) // write only exists for tests
29
30
30public:
31public:
31 enum DisplayStateChangeReason {
32 enum DisplayStateChangeReason {
@@ -42,8 +43,14 @@ public:
42
43
43 explicit Powerd(QObject *parent = 0);
44 explicit Powerd(QObject *parent = 0);
44
45
46+ Status status() const;
47+ void setStatus(Status status);
48+
45Q_SIGNALS:
49Q_SIGNALS:
46− void displayPowerStateChange(int status, int reason);
50+ void statusChanged(DisplayStateChangeReason reason);
51+
52+private:
53+ Status m_status;
47};
54};
48
55
49#endif
56#endif
tests/mocks/Powerd/Powerd.qmltypes+3−3
@@ -30,10 +30,10 @@ Module {
30 "On": 1
30 "On": 1
31 }
31 }
32 }
32 }
33+ Property { name: "status"; type: "Status" }
33 Signal {
34 Signal {
34− name: "displayPowerStateChange"
35+ name: "statusChanged"
35− Parameter { name: "status"; type: "int" }
36− Parameter { name: "reason"; type: "int" }
36+ Parameter { name: "reason"; type: "DisplayStateChangeReason" }
37 }
37 }
38 }
38 }
39}
39}
tests/mocks/Ubuntu/Payments/MockPayments.cpp+10−7
@@ -77,13 +77,16 @@ void MockPayments::setStoreItemId(const QString &store_item_id)
77
77
78void MockPayments::start()
78void MockPayments::start()
79{
79{
80− if (!m_store_item_id.isEmpty()) {
80+ if (m_store_item_id.isEmpty()) {
81− if (m_store_item_id == "com.example.invalid") {
82− Q_EMIT purchaseError("Purchase failed.");
83− } else {
84− Q_EMIT purchaseCompleted();
85− }
86− } else {
87 Q_EMIT purchaseError("No item ID supplied.");
81 Q_EMIT purchaseError("No item ID supplied.");
88 }
82 }
89}
83}
84+
85+void MockPayments::process()
86+{
87+ if (m_store_item_id == "com.example.invalid") {
88+ Q_EMIT purchaseError("Purchase failed.");
89+ } else {
90+ Q_EMIT purchaseCompleted();
91+ }
92+}
tests/mocks/Ubuntu/Payments/MockPayments.h+1
@@ -41,6 +41,7 @@ public:
41 void setPrice(const double price);
41 void setPrice(const double price);
42 void setStoreItemId(const QString& store_item_id);
42 void setStoreItemId(const QString& store_item_id);
43 Q_INVOKABLE void start();
43 Q_INVOKABLE void start();
44+ Q_INVOKABLE void process(); // only available for testing
44
45
45Q_SIGNALS:
46Q_SIGNALS:
46 void currencyChanged(const QString& currency);
47 void currencyChanged(const QString& currency);
tests/mocks/Ubuntu/SystemImage/SystemImage.qmltypes+3−1
@@ -4,13 +4,15 @@ import QtQuick.tooling 1.1
4// It is used for QML tooling purposes only.
4// It is used for QML tooling purposes only.
5//
5//
6// This file was auto-generated by:
6// This file was auto-generated by:
7−// 'qmlplugindump -notrelocatable Ubuntu.SystemImage 0.1 plugins'
7+// 'qmlplugindump -notrelocatable Ubuntu.SystemImage 0.1 tests/mocks'
8
8
9Module {
9Module {
10 Component {
10 Component {
11 name: "MockSystemImage"
11 name: "MockSystemImage"
12 prototype: "QObject"
12 prototype: "QObject"
13 exports: ["Ubuntu.SystemImage/SystemImage 0.1"]
13 exports: ["Ubuntu.SystemImage/SystemImage 0.1"]
14+ isCreatable: false
15+ isSingleton: true
14 exportMetaObjectRevisions: [0]
16 exportMetaObjectRevisions: [0]
15 Signal { name: "resettingDevice" }
17 Signal { name: "resettingDevice" }
16 Method { name: "factoryReset" }
18 Method { name: "factoryReset" }
tests/mocks/Unity/Application/Application.qmltypes+115−70
@@ -13,58 +13,24 @@ Module {
13 exports: ["Unity.Application/ApplicationInfo 0.1"]
13 exports: ["Unity.Application/ApplicationInfo 0.1"]
14 exportMetaObjectRevisions: [0]
14 exportMetaObjectRevisions: [0]
15 Property { name: "fullscreen"; type: "bool" }
15 Property { name: "fullscreen"; type: "bool" }
16− Property { name: "stage"; type: "Stage" }
17− Property { name: "surface"; type: "MirSurfaceItem"; isReadonly: true; isPointer: true }
16+ Property { name: "session"; type: "Session"; isReadonly: true; isPointer: true }
18− Property { name: "promptSurfaces"; type: "MirSurfaceItem"; isList: true; isReadonly: true }
17+ Property { name: "manualSurfaceCreation"; type: "bool" }
19− Property { name: "imageQml"; type: "string" }
20− Property { name: "windowQml"; type: "string" }
21− Signal {
22− name: "appIdChanged"
23− Parameter { type: "string" }
24− }
25− Signal {
26− name: "nameChanged"
27− Parameter { type: "string" }
28− }
29− Signal {
30− name: "commentChanged"
31− Parameter { type: "string" }
32− }
33− Signal {
34− name: "iconChanged"
35− Parameter { type: "QUrl" }
36− }
37 Signal {
18 Signal {
38− name: "stageChanged"
19+ name: "sessionChanged"
39− Parameter { type: "Stage" }
20+ Parameter { type: "Session"; isPointer: true }
40− }
41− Signal {
42− name: "stateChanged"
43− Parameter { type: "State" }
44− }
45− Signal {
46− name: "focusedChanged"
47− Parameter { type: "bool" }
48 }
21 }
49 Signal {
22 Signal {
50 name: "fullscreenChanged"
23 name: "fullscreenChanged"
51− Parameter { type: "bool" }
24+ Parameter { name: "value"; type: "bool" }
52− }
53− Signal {
54− name: "imageQmlChanged"
55− Parameter { type: "string" }
56− }
57− Signal {
58− name: "windowQmlChanged"
59− Parameter { type: "string" }
60 }
25 }
61 Signal {
26 Signal {
62− name: "screenshotChanged"
27+ name: "manualSurfaceCreationChanged"
63− Parameter { type: "QUrl" }
28+ Parameter { name: "value"; type: "bool" }
64 }
29 }
65− Signal {
30+ Method { name: "createSession" }
66− name: "surfaceChanged"
31+ Method {
67− Parameter { type: "MirSurfaceItem"; isPointer: true }
32+ name: "setState"
33+ Parameter { name: "value"; type: "State" }
68 }
34 }
69 }
35 }
70 Component {
36 Component {
@@ -198,17 +164,50 @@ Module {
198 type: "bool"
164 type: "bool"
199 Parameter { name: "appId"; type: "string" }
165 Parameter { name: "appId"; type: "string" }
200 }
166 }
167+ Method { name: "availableApplications"; type: "QStringList" }
201 Method {
168 Method {
202− name: "updateScreenshot"
169+ name: "add"
203− type: "bool"
170+ type: "ApplicationInfo*"
204 Parameter { name: "appId"; type: "string" }
171 Parameter { name: "appId"; type: "string" }
205 }
172 }
206− Method { name: "availableApplications"; type: "QStringList" }
173+ }
174+ Component {
175+ name: "ApplicationTestInterface"
176+ prototype: "QDBusAbstractAdaptor"
177+ exports: ["Unity.Application/ApplicationTest 0.1"]
178+ isCreatable: false
179+ isSingleton: true
180+ exportMetaObjectRevisions: [0]
181+ Method {
182+ name: "addChildSession"
183+ type: "uint"
184+ Parameter { name: "appId"; type: "string" }
185+ Parameter { name: "existingSessionId"; type: "uint" }
186+ Parameter { name: "surfaceImage"; type: "string" }
187+ }
188+ Method {
189+ name: "removeSession"
190+ Parameter { name: "sessionId"; type: "uint" }
191+ }
192+ Method {
193+ name: "addChildSession"
194+ type: "Session*"
195+ Parameter { name: "existingSession"; type: "Session"; isPointer: true }
196+ Parameter { name: "surfaceImage"; type: "string" }
197+ }
198+ Method {
199+ name: "removeSession"
200+ Parameter { name: "existingSession"; type: "Session"; isPointer: true }
201+ }
202+ Method {
203+ name: "removeSurface"
204+ Parameter { name: "existingSurface"; type: "MirSurfaceItem"; isPointer: true }
205+ }
207 }
206 }
208 Component {
207 Component {
209 name: "MirSurfaceItem"
208 name: "MirSurfaceItem"
210 defaultProperty: "data"
209 defaultProperty: "data"
211− prototype: "QQuickPaintedItem"
210+ prototype: "QQuickItem"
212 exports: ["Unity.Application/MirSurfaceItem 0.1"]
211 exports: ["Unity.Application/MirSurfaceItem 0.1"]
213 isCreatable: false
212 isCreatable: false
214 exportMetaObjectRevisions: [0]
213 exportMetaObjectRevisions: [0]
@@ -238,8 +237,7 @@ Module {
238 Property { name: "type"; type: "Type"; isReadonly: true }
237 Property { name: "type"; type: "Type"; isReadonly: true }
239 Property { name: "state"; type: "State"; isReadonly: true }
238 Property { name: "state"; type: "State"; isReadonly: true }
240 Property { name: "name"; type: "string"; isReadonly: true }
239 Property { name: "name"; type: "string"; isReadonly: true }
241− Property { name: "parentSurface"; type: "MirSurfaceItem"; isReadonly: true; isPointer: true }
240+ Property { name: "live"; type: "bool"; isReadonly: true }
242− Property { name: "childSurfaces"; type: "MirSurfaceItem"; isList: true; isReadonly: true }
243 Signal {
241 Signal {
244 name: "typeChanged"
242 name: "typeChanged"
245 Parameter { type: "Type" }
243 Parameter { type: "Type" }
@@ -249,22 +247,72 @@ Module {
249 Parameter { type: "State" }
247 Parameter { type: "State" }
250 }
248 }
251 Signal {
249 Signal {
252− name: "nameChanged"
250+ name: "liveChanged"
253− Parameter { type: "string" }
251+ Parameter { name: "live"; type: "bool" }
254− }
255− Signal {
256− name: "parentSurfaceChanged"
257− Parameter { type: "MirSurfaceItem"; isPointer: true }
258 }
252 }
259− Signal { name: "removed" }
260 Signal { name: "inputMethodRequested" }
253 Signal { name: "inputMethodRequested" }
261 Signal { name: "inputMethodDismissed" }
254 Signal { name: "inputMethodDismissed" }
255+ Signal { name: "deregister" }
262 Method {
256 Method {
263 name: "setState"
257 name: "setState"
264 Parameter { name: "newState"; type: "State" }
258 Parameter { name: "newState"; type: "State" }
265 }
259 }
266 Method { name: "release" }
260 Method { name: "release" }
267 }
261 }
262+ Component { name: "QDBusAbstractAdaptor"; prototype: "QObject" }
263+ Component {
264+ name: "Session"
265+ prototype: "QObject"
266+ exports: ["Unity.Application/Session 0.1"]
267+ isCreatable: false
268+ exportMetaObjectRevisions: [0]
269+ Property { name: "name"; type: "string"; isReadonly: true }
270+ Property { name: "surface"; type: "MirSurfaceItem"; isReadonly: true; isPointer: true }
271+ Property { name: "parentSession"; type: "Session"; isReadonly: true; isPointer: true }
272+ Property { name: "childSessions"; type: "SessionModel"; isReadonly: true; isPointer: true }
273+ Property { name: "live"; type: "bool"; isReadonly: true }
274+ Signal {
275+ name: "surfaceChanged"
276+ Parameter { type: "MirSurfaceItem"; isPointer: true }
277+ }
278+ Signal {
279+ name: "parentSessionChanged"
280+ Parameter { type: "Session"; isPointer: true }
281+ }
282+ Signal {
283+ name: "liveChanged"
284+ Parameter { name: "live"; type: "bool" }
285+ }
286+ Signal { name: "deregister" }
287+ Method { name: "createSurface" }
288+ Method { name: "release" }
289+ Method {
290+ name: "addChildSession"
291+ Parameter { name: "session"; type: "Session"; isPointer: true }
292+ }
293+ }
294+ Component {
295+ name: "SessionManager"
296+ prototype: "QObject"
297+ exports: ["Unity.Application/SessionManager 0.1"]
298+ isCreatable: false
299+ isSingleton: true
300+ exportMetaObjectRevisions: [0]
301+ Signal {
302+ name: "sessionStarting"
303+ Parameter { name: "session"; type: "Session"; isPointer: true }
304+ }
305+ Signal {
306+ name: "sessionStopping"
307+ Parameter { name: "session"; type: "Session"; isPointer: true }
308+ }
309+ Method {
310+ name: "createSession"
311+ type: "Session*"
312+ Parameter { name: "name"; type: "string" }
313+ Parameter { name: "screenshot"; type: "QUrl" }
314+ }
315+ }
268 Component {
316 Component {
269 name: "SurfaceManager"
317 name: "SurfaceManager"
270 prototype: "QObject"
318 prototype: "QObject"
@@ -281,6 +329,14 @@ Module {
281 name: "surfaceDestroyed"
329 name: "surfaceDestroyed"
282 Parameter { name: "surface"; type: "MirSurfaceItem"; isPointer: true }
330 Parameter { name: "surface"; type: "MirSurfaceItem"; isPointer: true }
283 }
331 }
332+ Method {
333+ name: "createSurface"
334+ type: "MirSurfaceItem*"
335+ Parameter { name: "name"; type: "string" }
336+ Parameter { name: "type"; type: "MirSurfaceItem::Type" }
337+ Parameter { name: "state"; type: "MirSurfaceItem::State" }
338+ Parameter { name: "screenshot"; type: "QUrl" }
339+ }
284 Method { name: "inputMethodSurface"; type: "MirSurfaceItem*" }
340 Method { name: "inputMethodSurface"; type: "MirSurfaceItem*" }
285 }
341 }
286 Component {
342 Component {
@@ -312,7 +368,6 @@ Module {
312 Property { name: "stage"; type: "Stage"; isReadonly: true }
368 Property { name: "stage"; type: "Stage"; isReadonly: true }
313 Property { name: "state"; type: "State"; isReadonly: true }
369 Property { name: "state"; type: "State"; isReadonly: true }
314 Property { name: "focused"; type: "bool"; isReadonly: true }
370 Property { name: "focused"; type: "bool"; isReadonly: true }
315− Property { name: "screenshot"; type: "QUrl"; isReadonly: true }
316 Signal {
371 Signal {
317 name: "nameChanged"
372 name: "nameChanged"
318 Parameter { name: "name"; type: "string" }
373 Parameter { name: "name"; type: "string" }
@@ -337,10 +392,6 @@ Module {
337 name: "focusedChanged"
392 name: "focusedChanged"
338 Parameter { name: "focused"; type: "bool" }
393 Parameter { name: "focused"; type: "bool" }
339 }
394 }
340− Signal {
341− name: "screenshotChanged"
342− Parameter { name: "screenshot"; type: "QUrl" }
343− }
344 }
395 }
345 Component {
396 Component {
346 name: "unity::shell::application::ApplicationManagerInterface"
397 name: "unity::shell::application::ApplicationManagerInterface"
@@ -357,8 +408,7 @@ Module {
357 "RoleIcon": 259,
408 "RoleIcon": 259,
358 "RoleStage": 260,
409 "RoleStage": 260,
359 "RoleState": 261,
410 "RoleState": 261,
360− "RoleFocused": 262,
411+ "RoleFocused": 262
361− "RoleScreenshot": 263
362 }
412 }
363 }
413 }
364 Property { name: "count"; type: "int"; isReadonly: true }
414 Property { name: "count"; type: "int"; isReadonly: true }
@@ -408,10 +458,5 @@ Module {
408 type: "bool"
458 type: "bool"
409 Parameter { name: "appId"; type: "string" }
459 Parameter { name: "appId"; type: "string" }
410 }
460 }
411− Method {
412− name: "updateScreenshot"
413− type: "bool"
414− Parameter { name: "appId"; type: "string" }
415− }
416 }
461 }
417}
462}
tests/mocks/Unity/Application/ApplicationDBusAdaptor.cppdeleted−81
@@ -1,81 +0,0 @@
1−/*
2− * Copyright (C) 2014 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#include "ApplicationInfo.h"
18−#include "ApplicationDBusAdaptor.h"
19−#include "ApplicationManager.h"
20−#include "SurfaceManager.h"
21−#include "MirSurfaceItem.h"
22−
23−quint32 nextId = 0;
24−
25−ApplicationDBusAdaptor::ApplicationDBusAdaptor(ApplicationManager* applicationManager)
26− : QDBusAbstractAdaptor(applicationManager)
27− , m_applicationManager(applicationManager)
28−{
29−}
30−
31−MirSurfaceItem* topSurface(MirSurfaceItem* surface)
32−{
33− if (!surface)
34− return nullptr;
35−
36− MirSurfaceItem* child = nullptr;
37− Q_FOREACH (MirSurfaceItem *childSurface, surface->childSurfaceList()) {
38− child = topSurface(childSurface);
39− if (child) {
40− break;
41− }
42− }
43− return child ? child : surface;
44−}
45−
46−quint32 ApplicationDBusAdaptor::addPromptSurface(const QString &appId, const QString &surfaceImage)
47−{
48− qDebug() << "ApplicationDBusAdaptor::addPromptSurface to " << appId;
49−
50− ApplicationInfo* application = m_applicationManager->findApplication(appId);
51− if (!application) {
52− qDebug() << "ApplicationDBusAdaptor::addChildSurface - No application found for " << appId;
53− return 0;
54− }
55− quint32 surfaceId = ++nextId;
56− MirSurfaceItem* surface = new MirSurfaceItem(QString("%1-ChildSurface%2").arg(appId).arg(surfaceId),
57− MirSurfaceItem::Normal,
58− MirSurfaceItem::Maximized,
59− QUrl(surfaceImage));
60− m_childItems[surfaceId] = surface;
61−
62− if (application->promptSurfaceList().count() > 0) {
63− surface->setParentSurface(topSurface(application->promptSurfaceList()[0]));
64− } else {
65− application->addPromptSurface(surface);
66− }
67−
68− return surfaceId;
69−}
70−
71−void ApplicationDBusAdaptor::removeChildSurface(int surfaceId)
72−{
73− qDebug() << "ApplicationDBusAdaptor::removeChildSurface - " << surfaceId;
74−
75− if (!m_childItems.contains(surfaceId)) {
76− qDebug() << "ApplicationDBusAdaptor::removeChildSurface - No added surface for " << surfaceId;
77− return;
78− }
79− MirSurfaceItem* surface = m_childItems.take(surfaceId);
80− Q_EMIT surface->removed();
81−}
tests/mocks/Unity/Application/ApplicationInfo.cpp+36−85
@@ -15,8 +15,8 @@
15 */
15 */
16
16
17#include "ApplicationInfo.h"
17#include "ApplicationInfo.h"
18−#include "MirSurfaceItem.h"
18+#include "Session.h"
19−#include "SurfaceManager.h"
19+#include "SessionManager.h"
20
20
21#include <paths.h>
21#include <paths.h>
22
22
@@ -33,9 +33,8 @@ ApplicationInfo::ApplicationInfo(const QString &appId, QObject *parent)
33 , m_state(Starting)
33 , m_state(Starting)
34 , m_focused(false)
34 , m_focused(false)
35 , m_fullscreen(false)
35 , m_fullscreen(false)
36− , m_surface(0)
36+ , m_session(0)
37 , m_manualSurfaceCreation(false)
37 , m_manualSurfaceCreation(false)
38− , m_parentItem(0)
39{
38{
40}
39}
41
40
@@ -45,107 +44,50 @@ ApplicationInfo::ApplicationInfo(QObject *parent)
45 , m_state(Starting)
44 , m_state(Starting)
46 , m_focused(false)
45 , m_focused(false)
47 , m_fullscreen(false)
46 , m_fullscreen(false)
48− , m_surface(0)
47+ , m_session(0)
49 , m_manualSurfaceCreation(false)
48 , m_manualSurfaceCreation(false)
50− , m_parentItem(0)
51{
49{
52}
50}
53
51
54ApplicationInfo::~ApplicationInfo()
52ApplicationInfo::~ApplicationInfo()
55{
53{
56− if (m_surface) {
54+ delete m_session;
57− Q_EMIT SurfaceManager::singleton()->surfaceDestroyed(m_surface);
58− m_surface->deleteLater();
59− setSurface(nullptr);
60− }
61}
55}
62
56
63−void ApplicationInfo::createSurface()
57+void ApplicationInfo::createSession()
64{
58{
65− if (m_surface || state() == ApplicationInfo::Stopped) return;
59+ if (m_session || state() == ApplicationInfo::Stopped) { return; }
66
60
67 QUrl screenshotUrl = QString("file://%1").arg(m_screenshotFileName);
61 QUrl screenshotUrl = QString("file://%1").arg(m_screenshotFileName);
68−
62+ setSession(SessionManager::singleton()->createSession(appId(), screenshotUrl));
69− setSurface(new MirSurfaceItem(name(),
70− MirSurfaceItem::Normal,
71− fullscreen() ? MirSurfaceItem::Fullscreen : MirSurfaceItem::Maximized,
72− screenshotUrl));
73}
63}
74
64
75−void ApplicationInfo::setSurface(MirSurfaceItem* surface)
65+void ApplicationInfo::setSession(Session* session)
76{
66{
77− qDebug() << "Application::setSurface - appId=" << appId() << "surface=" << surface;
67+ qDebug() << "Application::setSession - appId=" << appId() << "session=" << session;
78− if (m_surface == surface)
68+ if (m_session == session)
79 return;
69 return;
80
70
81− if (m_surface) {
71+ if (m_session) {
82− m_surface->setApplication(nullptr);
72+ disconnect(this, 0, m_session, 0);
83− m_surface->setParent(nullptr);
84− SurfaceManager::singleton()->unregisterSurface(m_surface);
85− }
86−
87− m_surface = surface;
88−
89− if (m_surface) {
90− m_surface->setApplication(this);
73+ m_session->setApplication(nullptr);
91− m_surface->setParent(this);
74+ m_session->setParent(nullptr);
92− SurfaceManager::singleton()->registerSurface(m_surface);
75+ Q_EMIT m_session->deregister();
93 }
76 }
94
77
95− Q_EMIT surfaceChanged(m_surface);
78+ m_session = session;
96− SurfaceManager::singleton()->registerSurface(m_surface);
97−}
98
79
99−void ApplicationInfo::addPromptSurface(MirSurfaceItem* surface)
80+ if (m_session) {
100−{
81+ m_session->setApplication(this);
101− qDebug() << "ApplicationInfo::addPromptSurface " << surface->name() << " to " << name();
82+ m_session->setParent(this);
102− if (surface == m_surface || m_promptSurfaces.contains(surface)) return;
83+ SessionManager::singleton()->registerSession(m_session);
103
84
104− surface->setApplication(this);
85+ if (!m_manualSurfaceCreation) {
105− m_promptSurfaces.append(surface);
86+ QTimer::singleShot(500, m_session, SLOT(createSurface()));
106− Q_EMIT promptSurfacesChanged();
87+ }
107−}
108−
109−void ApplicationInfo::removeSurface(MirSurfaceItem* surface)
110−{
111− if (m_surface == surface) {
112− setSurface(nullptr);
113− } else if (m_promptSurfaces.contains(surface)) {
114− qDebug() << "Application::removeSurface " << surface->name() << " from " << name();
115−
116− m_promptSurfaces.removeAll(surface);
117− surface->setApplication(nullptr);
118−
119− Q_EMIT promptSurfacesChanged();
120 }
88 }
121−}
122
89
123−QList<MirSurfaceItem*> ApplicationInfo::promptSurfaceList() const
90+ Q_EMIT sessionChanged(m_session);
124−{
125− return m_promptSurfaces;
126−}
127−
128−QQmlListProperty<MirSurfaceItem> ApplicationInfo::promptSurfaces()
129−{
130− return QQmlListProperty<MirSurfaceItem>(this,
131− 0,
132− ApplicationInfo::promptSurfaceCount,
133− ApplicationInfo::promptSurfaceAt);
134−}
135−
136−int ApplicationInfo::promptSurfaceCount(QQmlListProperty<MirSurfaceItem> *prop)
137−{
138− ApplicationInfo *p = qobject_cast<ApplicationInfo*>(prop->object);
139− return p->m_promptSurfaces.count();
140−}
141−
142−MirSurfaceItem* ApplicationInfo::promptSurfaceAt(QQmlListProperty<MirSurfaceItem> *prop, int index)
143−{
144− ApplicationInfo *p = qobject_cast<ApplicationInfo*>(prop->object);
145−
146− if (index < 0 || index >= p->m_promptSurfaces.count())
147− return nullptr;
148− return p->m_promptSurfaces[index];
149}
91}
150
92
151void ApplicationInfo::setIconId(const QString &iconId)
93void ApplicationInfo::setIconId(const QString &iconId)
@@ -157,9 +99,18 @@ void ApplicationInfo::setIconId(const QString &iconId)
157
99
158void ApplicationInfo::setScreenshotId(const QString &screenshotId)
100void ApplicationInfo::setScreenshotId(const QString &screenshotId)
159{
101{
160− m_screenshotFileName = QString("%1/Dash/graphics/phone/screenshots/%2@12.png")
102+ QString screenshotFileName = QString("%1/Dash/graphics/phone/screenshots/%2@12.png")
161 .arg(qmlDirectory())
103 .arg(qmlDirectory())
162 .arg(screenshotId);
104 .arg(screenshotId);
105+
106+ if (screenshotFileName != m_screenshotFileName) {
107+ m_screenshotFileName = screenshotFileName;
108+
109+ QUrl screenshotUrl = QString("file://%1").arg(m_screenshotFileName);
110+ if (m_session) {
111+ m_session->setScreenshot(screenshotUrl);
112+ }
113+ }
163}
114}
164
115
165void ApplicationInfo::setName(const QString &value)
116void ApplicationInfo::setName(const QString &value)
@@ -193,7 +144,7 @@ void ApplicationInfo::setState(State value)
193 Q_EMIT stateChanged(value);
144 Q_EMIT stateChanged(value);
194
145
195 if (!m_manualSurfaceCreation && m_state == ApplicationInfo::Running) {
146 if (!m_manualSurfaceCreation && m_state == ApplicationInfo::Running) {
196− QTimer::singleShot(1000, this, SLOT(createSurface()));
147+ QTimer::singleShot(500, this, SLOT(createSession()));
197 }
148 }
198 }
149 }
199}
150}
tests/mocks/Unity/Application/ApplicationInfo.h+11−23
@@ -17,8 +17,10 @@
17#ifndef APPLICATION_H
17#ifndef APPLICATION_H
18#define APPLICATION_H
18#define APPLICATION_H
19
19
20+#include "SurfaceManager.h"
21+#include "MirSurfaceItemModel.h"
22+
20#include <QObject>
23#include <QObject>
21−#include <QQmlComponent>
22
24
23class QQuickItem;
25class QQuickItem;
24class MirSurfaceItem;
26class MirSurfaceItem;
@@ -32,8 +34,7 @@ class ApplicationInfo : public ApplicationInfoInterface {
32 Q_OBJECT
34 Q_OBJECT
33
35
34 Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged)
36 Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged)
35− Q_PROPERTY(MirSurfaceItem* surface READ surface NOTIFY surfaceChanged)
37+ Q_PROPERTY(Session* session READ session NOTIFY sessionChanged)
36− Q_PROPERTY(QQmlListProperty<MirSurfaceItem> promptSurfaces READ promptSurfaces NOTIFY promptSurfacesChanged DESIGNABLE false)
37
38
38 // Only exists in this fake implementation
39 // Only exists in this fake implementation
39
40
@@ -72,32 +73,23 @@ public:
72 void setFullscreen(bool value);
73 void setFullscreen(bool value);
73 bool fullscreen() const { return m_fullscreen; }
74 bool fullscreen() const { return m_fullscreen; }
74
75
75− void setSurface(MirSurfaceItem* surface);
76− MirSurfaceItem* surface() const { return m_surface; }
77−
78− void removeSurface(MirSurfaceItem* surface);
79−
80− void addPromptSurface(MirSurfaceItem* surface);
81− QList<MirSurfaceItem*> promptSurfaceList() const;
82− QQmlListProperty<MirSurfaceItem> promptSurfaces();
83−
84 bool manualSurfaceCreation() const { return m_manualSurfaceCreation; }
76 bool manualSurfaceCreation() const { return m_manualSurfaceCreation; }
85 void setManualSurfaceCreation(bool value);
77 void setManualSurfaceCreation(bool value);
86
78
79+public:
80+ void setSession(Session* session);
81+ Session* session() const { return m_session; }
82+
87Q_SIGNALS:
83Q_SIGNALS:
88− void surfaceChanged(MirSurfaceItem*);
84+ void sessionChanged(Session*);
89− void promptSurfacesChanged();
90 void fullscreenChanged(bool value);
85 void fullscreenChanged(bool value);
91 void manualSurfaceCreationChanged(bool value);
86 void manualSurfaceCreationChanged(bool value);
92
87
93public Q_SLOTS:
88public Q_SLOTS:
94− Q_INVOKABLE void createSurface();
89+ Q_INVOKABLE void createSession();
95
90
96private:
91private:
97− static int promptSurfaceCount(QQmlListProperty<MirSurfaceItem> *prop);
98− static MirSurfaceItem* promptSurfaceAt(QQmlListProperty<MirSurfaceItem> *prop, int index);
99 void setIcon(const QUrl &value);
92 void setIcon(const QUrl &value);
100− void setScreenshot(const QUrl &value);
101
93
102 QString m_screenshotFileName;
94 QString m_screenshotFileName;
103
95
@@ -108,15 +100,11 @@ private:
108 State m_state;
100 State m_state;
109 bool m_focused;
101 bool m_focused;
110 bool m_fullscreen;
102 bool m_fullscreen;
111− MirSurfaceItem* m_surface;
103+ Session* m_session;
112
104
113 bool m_manualSurfaceCreation;
105 bool m_manualSurfaceCreation;
114−
115− QQuickItem *m_parentItem;
116− QList<MirSurfaceItem*> m_promptSurfaces;
117};
106};
118
107
119Q_DECLARE_METATYPE(ApplicationInfo*)
108Q_DECLARE_METATYPE(ApplicationInfo*)
120−Q_DECLARE_METATYPE(QQmlListProperty<MirSurfaceItem>)
121
109
122#endif // APPLICATION_H
110#endif // APPLICATION_H
tests/mocks/Unity/Application/ApplicationManager.cpp+9−16
@@ -15,9 +15,9 @@
15 */
15 */
16
16
17#include "ApplicationManager.h"
17#include "ApplicationManager.h"
18−#include "ApplicationDBusAdaptor.h"
19#include "ApplicationInfo.h"
18#include "ApplicationInfo.h"
20−#include "MirSurfaceItem.h"
19+#include "Session.h"
20+#include "ApplicationTestInterface.h"
21
21
22#include <paths.h>
22#include <paths.h>
23
23
@@ -36,11 +36,6 @@ ApplicationManager *ApplicationManager::singleton()
36{
36{
37 if (!the_application_manager) {
37 if (!the_application_manager) {
38 the_application_manager = new ApplicationManager();
38 the_application_manager = new ApplicationManager();
39− new ApplicationDBusAdaptor(the_application_manager);
40−
41− QDBusConnection connection = QDBusConnection::sessionBus();
42− connection.registerService("com.canonical.Unity8");
43− connection.registerObject("/com/canonical/Unity8/Mocks", the_application_manager);
44 }
39 }
45 return the_application_manager;
40 return the_application_manager;
46}
41}
@@ -49,9 +44,8 @@ ApplicationManager::ApplicationManager(QObject *parent)
49 : ApplicationManagerInterface(parent)
44 : ApplicationManagerInterface(parent)
50 , m_suspended(false)
45 , m_suspended(false)
51{
46{
52− m_roleNames.insert(RoleSurface, "surface");
47+ m_roleNames.insert(RoleSession, "session");
53 m_roleNames.insert(RoleFullscreen, "fullscreen");
48 m_roleNames.insert(RoleFullscreen, "fullscreen");
54− m_roleNames.insert(RoleApplication, "application");
55
49
56 buildListOfAvailableApplications();
50 buildListOfAvailableApplications();
57
51
@@ -105,12 +99,10 @@ QVariant ApplicationManager::data(const QModelIndex& index, int role) const {
105 return app->state();
99 return app->state();
106 case RoleFocused:
100 case RoleFocused:
107 return app->focused();
101 return app->focused();
108− case RoleSurface:
102+ case RoleSession:
109− return QVariant::fromValue(app->surface());
103+ return QVariant::fromValue(app->session());
110 case RoleFullscreen:
104 case RoleFullscreen:
111 return app->fullscreen();
105 return app->fullscreen();
112− case RoleApplication:
113− return QVariant::fromValue(app);
114 default:
106 default:
115 return QVariant();
107 return QVariant();
116 }
108 }
@@ -154,10 +146,10 @@ void ApplicationManager::add(ApplicationInfo *application) {
154 Q_EMIT countChanged();
146 Q_EMIT countChanged();
155 if (count() == 1) Q_EMIT emptyChanged(isEmpty()); // was empty but not anymore
147 if (count() == 1) Q_EMIT emptyChanged(isEmpty()); // was empty but not anymore
156
148
157− connect(application, &ApplicationInfo::surfaceChanged, this, [application, this]() {
149+ connect(application, &ApplicationInfo::sessionChanged, this, [application, this]() {
158 QModelIndex appIndex = findIndex(application);
150 QModelIndex appIndex = findIndex(application);
159 if (!appIndex.isValid()) return;
151 if (!appIndex.isValid()) return;
160− Q_EMIT dataChanged(appIndex, appIndex, QVector<int>() << ApplicationManager::RoleSurface);
152+ Q_EMIT dataChanged(appIndex, appIndex, QVector<int>() << ApplicationManager::RoleSession);
161 });
153 });
162 connect(application, &ApplicationInfo::focusedChanged, this, [application, this]() {
154 connect(application, &ApplicationInfo::focusedChanged, this, [application, this]() {
163 QModelIndex appIndex = findIndex(application);
155 QModelIndex appIndex = findIndex(application);
@@ -181,7 +173,7 @@ void ApplicationManager::remove(ApplicationInfo *application) {
181 Q_EMIT countChanged();
173 Q_EMIT countChanged();
182 if (isEmpty()) Q_EMIT emptyChanged(isEmpty());
174 if (isEmpty()) Q_EMIT emptyChanged(isEmpty());
183 }
175 }
184− disconnect(application, 0, this, 0);
176+ application->disconnect(this);
185}
177}
186
178
187void ApplicationManager::move(int from, int to) {
179void ApplicationManager::move(int from, int to) {
@@ -464,6 +456,7 @@ void ApplicationManager::buildListOfAvailableApplications()
464 m_availableApplications.append(application);
456 m_availableApplications.append(application);
465}
457}
466
458
459+
467QStringList ApplicationManager::availableApplications()
460QStringList ApplicationManager::availableApplications()
468{
461{
469 QStringList appIds;
462 QStringList appIds;
tests/mocks/Unity/Application/ApplicationManager.h+1−2
@@ -52,9 +52,8 @@ class ApplicationManager : public ApplicationManagerInterface {
52 static ApplicationManager *singleton();
52 static ApplicationManager *singleton();
53
53
54 enum MoreRoles {
54 enum MoreRoles {
55− RoleSurface = RoleFocused+1,
55+ RoleSession = RoleFocused+1,
56 RoleFullscreen,
56 RoleFullscreen,
57− RoleApplication,
58 };
57 };
59 enum Role {
58 enum Role {
60 Dash, Default, Indicators, Notifications, Greeter, Launcher, OnScreenKeyboard,
59 Dash, Default, Indicators, Notifications, Greeter, Launcher, OnScreenKeyboard,
tests/mocks/Unity/Application/ApplicationTestInterface.cppnew file+117
@@ -0,0 +1,117 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "ApplicationInfo.h"
18+#include "ApplicationTestInterface.h"
19+#include "ApplicationManager.h"
20+#include "SessionManager.h"
21+#include "SurfaceManager.h"
22+#include "Session.h"
23+#include "MirSurfaceItem.h"
24+
25+#include <paths.h>
26+
27+#include <QtDBus/QtDBus>
28+
29+quint32 nextId = 0;
30+
31+ApplicationTestInterface::ApplicationTestInterface(QObject* parent)
32+ : QDBusAbstractAdaptor(parent)
33+{
34+ QDBusConnection connection = QDBusConnection::sessionBus();
35+ connection.registerService("com.canonical.Unity8");
36+ connection.registerObject("/com/canonical/Unity8/Mocks", parent);
37+}
38+
39+Session* ApplicationTestInterface::addChildSession(Session* existingSession, const QString& surfaceImage)
40+{
41+ if (!existingSession) return nullptr;
42+
43+ QUrl screenshotUrl = QString("file://%1/Dash/graphics/phone/screenshots/%2@12.png")
44+ .arg(qmlDirectory())
45+ .arg(surfaceImage);
46+
47+ Session* session = SessionManager::singleton()->createSession(
48+ QString("%1-Child%2").arg(existingSession->name())
49+ .arg(existingSession->childSessions()->count()),
50+ screenshotUrl);
51+ existingSession->addChildSession(session);
52+ session->createSurface();
53+
54+ return session;
55+}
56+
57+void ApplicationTestInterface::removeSession(Session* existingSession)
58+{
59+ qDebug() << "ApplicationTestInterface::removeSession - " << existingSession;
60+
61+ if (existingSession)
62+ existingSession->setLive(false);
63+}
64+
65+void ApplicationTestInterface::removeSurface(MirSurfaceItem* existingSurface)
66+{
67+ qDebug() << "ApplicationTestInterface::removeSurface - " << existingSurface;
68+
69+ if (existingSurface)
70+ existingSurface->setLive(false);
71+}
72+
73+quint32 ApplicationTestInterface::addChildSession(const QString& appId, quint32 existingSessionId, const QString& surfaceImage)
74+{
75+ qDebug() << "ApplicationTestInterface::addChildSession to " << appId;
76+
77+ ApplicationInfo* application = ApplicationManager::singleton()->findApplication(appId);
78+ if (!application) {
79+ qDebug() << "ApplicationTestInterface::addChildSession - No application found for " << appId;
80+ return 0;
81+ }
82+
83+ Session* parentSession = nullptr;
84+ if (m_childSessions.contains(existingSessionId)) {
85+ parentSession = m_childSessions[existingSessionId];
86+ } else if (application->session()) {
87+ parentSession = application->session();
88+ } else {
89+ qDebug() << "ApplicationTestInterface::addChildSession - No session for " << appId << ":" << existingSessionId;
90+ return 0;
91+ }
92+
93+ QUrl screenshotUrl = QString("file://%1/Dash/graphics/phone/screenshots/%2@12.png")
94+ .arg(qmlDirectory())
95+ .arg(surfaceImage);
96+
97+ quint32 sessionId = ++nextId;
98+ Session* session = SessionManager::singleton()->createSession(
99+ QString("%1-Child%2").arg(parentSession->name())
100+ .arg(parentSession->childSessions()->count()),
101+ screenshotUrl);
102+ parentSession->addChildSession(session);
103+ session->createSurface();
104+ m_childSessions[sessionId] = session;
105+
106+ return sessionId;
107+}
108+
109+void ApplicationTestInterface::removeSession(quint32 sessionId)
110+{
111+ if (!m_childSessions.contains(sessionId)) {
112+ qDebug() << "ApplicationTestInterface::removeSession - No added session for " << sessionId;
113+ return;
114+ }
115+ Session* session = m_childSessions.take(sessionId);
116+ removeSession(session);
117+}
tests/mocks/Unity/Application/ApplicationDBusAdaptor.h → tests/mocks/Unity/Application/ApplicationTestInterface.hrenamed+13−11
@@ -14,30 +14,32 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
15 */
16
16
17−#ifndef APPLICATIONDBUSADAPTOR_H
17+#ifndef APPLICATIONTESTINTERFACE_H
18−#define APPLICATIONDBUSADAPTOR_H
18+#define APPLICATIONTESTINTERFACE_H
19
19
20#include <QtDBus/QtDBus>
20#include <QtDBus/QtDBus>
21
21
22class ApplicationManager;
22class ApplicationManager;
23−class SurfaceManager;
23+class Session;
24class MirSurfaceItem;
24class MirSurfaceItem;
25
25
26−class ApplicationDBusAdaptor : public QDBusAbstractAdaptor
26+class ApplicationTestInterface : public QDBusAbstractAdaptor
27{
27{
28 Q_OBJECT
28 Q_OBJECT
29 Q_CLASSINFO("D-Bus Interface", "com.canonical.Unity8.Mocks.Application")
29 Q_CLASSINFO("D-Bus Interface", "com.canonical.Unity8.Mocks.Application")
30public:
30public:
31− ApplicationDBusAdaptor(ApplicationManager* applicationManager);
31+ ApplicationTestInterface(QObject* parent = 0);
32+
33+ Q_INVOKABLE Session* addChildSession(Session* existingSession, const QString& surfaceImage);
34+ Q_INVOKABLE void removeSession(Session* existingSession);
35+ Q_INVOKABLE void removeSurface(MirSurfaceItem* existingSurface);
32
36
33public Q_SLOTS:
37public Q_SLOTS:
34− quint32 addPromptSurface(const QString& appId, const QString& surfaceImage);
38+ quint32 addChildSession(const QString& appId, quint32 existingSessionId, const QString& surfaceImage);
35− void removeChildSurface(int surfaceId);
39+ void removeSession(quint32 sessionId);
36
40
37private:
41private:
38− ApplicationManager* m_applicationManager;
42+ QHash<quint32, Session*> m_childSessions;
39−
40− QHash<quint32, MirSurfaceItem*> m_childItems;
41};
43};
42
44
43−#endif // APPLICATIONDBUSADAPTOR_H
45+#endif // APPLICATIONTESTINTERFACE_H
tests/mocks/Unity/Application/CMakeLists.txt+6−1
@@ -2,12 +2,17 @@ pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=3)
2
2
3set(FakeUnityApplicationQml_SOURCES
3set(FakeUnityApplicationQml_SOURCES
4 plugin.cpp
4 plugin.cpp
5− ApplicationDBusAdaptor.cpp
6 ApplicationInfo.cpp
5 ApplicationInfo.cpp
7 ApplicationManager.cpp
6 ApplicationManager.cpp
8 ApplicationScreenshotProvider.cpp
7 ApplicationScreenshotProvider.cpp
8+ ApplicationTestInterface.cpp
9 MirSurfaceItem.cpp
9 MirSurfaceItem.cpp
10+ MirSurfaceItemModel.h
11+ ObjectListModel.h
12+ Session.cpp
13+ SessionManager.cpp
10 SurfaceManager.cpp
14 SurfaceManager.cpp
15+ SessionModel.h
11 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
16 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
12 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
17 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
13)
18)
tests/mocks/Unity/Application/MirSurfaceItem.cpp+19−79
@@ -15,7 +15,7 @@
15 */
15 */
16
16
17#include "MirSurfaceItem.h"
17#include "MirSurfaceItem.h"
18−#include "ApplicationInfo.h"
18+#include "Session.h"
19
19
20#include <paths.h>
20#include <paths.h>
21
21
@@ -34,11 +34,11 @@ MirSurfaceItem::MirSurfaceItem(const QString& name,
34 const QString &qmlFilePath,
34 const QString &qmlFilePath,
35 QQuickItem *parent)
35 QQuickItem *parent)
36 : QQuickItem(parent)
36 : QQuickItem(parent)
37− , m_application(nullptr)
37+ , m_session(nullptr)
38 , m_name(name)
38 , m_name(name)
39 , m_type(type)
39 , m_type(type)
40 , m_state(state)
40 , m_state(state)
41− , m_parentSurface(nullptr)
41+ , m_live(true)
42 , m_qmlItem(nullptr)
42 , m_qmlItem(nullptr)
43 , m_screenshotUrl(screenshot)
43 , m_screenshotUrl(screenshot)
44{
44{
@@ -83,16 +83,9 @@ MirSurfaceItem::MirSurfaceItem(const QString& name,
83MirSurfaceItem::~MirSurfaceItem()
83MirSurfaceItem::~MirSurfaceItem()
84{
84{
85 qDebug() << "MirSurfaceItem::~MirSurfaceItem() " << name();
85 qDebug() << "MirSurfaceItem::~MirSurfaceItem() " << name();
86−
86+ if (m_session) {
87− QList<MirSurfaceItem*> children(m_children);
87+ m_session->setSurface(nullptr);
88− for (MirSurfaceItem* child : children) {
89− child->setParentSurface(nullptr);
90 }
88 }
91− if (m_parentSurface)
92− m_parentSurface->removeChildSurface(this);
93−
94− if (m_application)
95− m_application->removeSurface(this);
96}
89}
97
90
98void MirSurfaceItem::printComponentErrors()
91void MirSurfaceItem::printComponentErrors()
@@ -105,91 +98,38 @@ void MirSurfaceItem::printComponentErrors()
105
98
106void MirSurfaceItem::release()
99void MirSurfaceItem::release()
107{
100{
108− QList<MirSurfaceItem*> children(m_children);
101+ qDebug() << "MirSurfaceItem::release " << name();
109− for (MirSurfaceItem* child : children) {
110− child->release();
111− }
112− if (m_parentSurface) {
113− m_parentSurface->removeChildSurface(this);
114− }
115
102
116− if (m_application) {
103+ if (m_session) {
117− m_application->removeSurface(this);
104+ m_session->setSurface(nullptr);
118 }
105 }
119 if (!parent()) {
106 if (!parent()) {
120 deleteLater();
107 deleteLater();
121 }
108 }
122}
109}
123
110
124−void MirSurfaceItem::setApplication(ApplicationInfo* application)
111+void MirSurfaceItem::setSession(Session* session)
125{
112{
126− m_application = application;
113+ m_session = session;
127}
114}
128
115
129−void MirSurfaceItem::setParentSurface(MirSurfaceItem* surface)
116+void MirSurfaceItem::setScreenshot(const QUrl& screenshot)
130{
117{
131− if (m_parentSurface == surface || surface == this)
118+ m_screenshotUrl = screenshot;
132− return;
119+ if (m_qmlItem) {
133−
120+ QQmlProperty screenshotSource(m_qmlItem, "screenshotSource");
134− if (m_parentSurface) {
121+ screenshotSource.write(QVariant::fromValue(m_screenshotUrl));
135− m_parentSurface->removeChildSurface(this);
136− }
137−
138− m_parentSurface = surface;
139−
140− if (m_parentSurface) {
141− m_parentSurface->addChildSurface(this);
142 }
122 }
143− Q_EMIT parentSurfaceChanged(surface);
144}
123}
145
124
146−void MirSurfaceItem::addChildSurface(MirSurfaceItem* surface)
125+void MirSurfaceItem::setLive(bool live)
147{
126{
148− qDebug() << "MirSurfaceItem::addChildSurface " << surface->name() << " to " << name();
127+ if (m_live != live) {
149−
128+ m_live = live;
150− m_children.append(surface);
129+ Q_EMIT liveChanged(m_live);
151− Q_EMIT childSurfacesChanged();
152−}
153−
154−void MirSurfaceItem::removeChildSurface(MirSurfaceItem* surface)
155−{
156− qDebug() << "MirSurfaceItem::removeChildSurface " << surface->name() << " from " << name();
157−
158− if (m_children.contains(surface)) {
159− m_children.removeOne(surface);
160− Q_EMIT childSurfacesChanged();
161 }
130 }
162}
131}
163
132
164−QList<MirSurfaceItem*> MirSurfaceItem::childSurfaceList()
165−{
166− return m_children;
167−}
168−
169−QQmlListProperty<MirSurfaceItem> MirSurfaceItem::childSurfaces()
170−{
171− return QQmlListProperty<MirSurfaceItem>(this,
172− 0,
173− MirSurfaceItem::childSurfaceCount,
174− MirSurfaceItem::childSurfaceAt);
175−}
176−
177−int MirSurfaceItem::childSurfaceCount(QQmlListProperty<MirSurfaceItem> *prop)
178−{
179− MirSurfaceItem *p = qobject_cast<MirSurfaceItem*>(prop->object);
180− return p->m_children.count();
181−}
182−
183−MirSurfaceItem* MirSurfaceItem::childSurfaceAt(QQmlListProperty<MirSurfaceItem> *prop, int index)
184−{
185− MirSurfaceItem *p = qobject_cast<MirSurfaceItem*>(prop->object);
186−
187− if (index < 0 || index >= p->m_children.count())
188− return nullptr;
189− return p->m_children[index];
190−}
191−
192−
193void MirSurfaceItem::onQmlWantInputMethodChanged()
133void MirSurfaceItem::onQmlWantInputMethodChanged()
194{
134{
195 QQmlProperty prop(m_qmlItem, "wantInputMethod");
135 QQmlProperty prop(m_qmlItem, "wantInputMethod");
tests/mocks/Unity/Application/MirSurfaceItem.h+24−31
@@ -17,11 +17,12 @@
17#ifndef MIRSURFACEITEM_H
17#ifndef MIRSURFACEITEM_H
18#define MIRSURFACEITEM_H
18#define MIRSURFACEITEM_H
19
19
20+#include "MirSurfaceItemModel.h"
21+
20#include <QQuickItem>
22#include <QQuickItem>
21−#include <QQmlComponent>
22#include <QUrl>
23#include <QUrl>
23
24
24−class ApplicationInfo;
25+class Session;
25
26
26class MirSurfaceItem : public QQuickItem
27class MirSurfaceItem : public QQuickItem
27{
28{
@@ -31,9 +32,8 @@ class MirSurfaceItem : public QQuickItem
31
32
32 Q_PROPERTY(Type type READ type NOTIFY typeChanged)
33 Q_PROPERTY(Type type READ type NOTIFY typeChanged)
33 Q_PROPERTY(State state READ state NOTIFY stateChanged)
34 Q_PROPERTY(State state READ state NOTIFY stateChanged)
34− Q_PROPERTY(QString name READ name NOTIFY nameChanged)
35+ Q_PROPERTY(QString name READ name CONSTANT)
35− Q_PROPERTY(MirSurfaceItem* parentSurface READ parentSurface NOTIFY parentSurfaceChanged)
36+ Q_PROPERTY(bool live READ live NOTIFY liveChanged)
36− Q_PROPERTY(QQmlListProperty<MirSurfaceItem> childSurfaces READ childSurfaces NOTIFY childSurfacesChanged DESIGNABLE false)
37
37
38public:
38public:
39 enum Type {
39 enum Type {
@@ -56,24 +56,18 @@ public:
56 Fullscreen,
56 Fullscreen,
57 };
57 };
58
58
59− explicit MirSurfaceItem(const QString& name,
60− Type type,
61− State state,
62− const QUrl& screenshot,
63− const QString &qmlFilePath = QString(),
64− QQuickItem *parent = 0);
65 ~MirSurfaceItem();
59 ~MirSurfaceItem();
66
60
67 //getters
61 //getters
68− ApplicationInfo* application() const { return m_application; }
62+ Session* session() const { return m_session; }
69 Type type() const { return m_type; }
63 Type type() const { return m_type; }
70 State state() const { return m_state; }
64 State state() const { return m_state; }
71 QString name() const { return m_name; }
65 QString name() const { return m_name; }
72− MirSurfaceItem* parentSurface() const { return m_parentSurface; }
66+ bool live() const { return m_live; }
73− QList<MirSurfaceItem*> childSurfaceList();
74
67
75− void setApplication(ApplicationInfo* item);
68+ void setSession(Session* item);
76− void setParentSurface(MirSurfaceItem* item);
69+ void setScreenshot(const QUrl& screenshot);
70+ void setLive(bool live);
77
71
78 Q_INVOKABLE void setState(State newState);
72 Q_INVOKABLE void setState(State newState);
79 Q_INVOKABLE void release();
73 Q_INVOKABLE void release();
@@ -81,42 +75,41 @@ public:
81Q_SIGNALS:
75Q_SIGNALS:
82 void typeChanged(Type);
76 void typeChanged(Type);
83 void stateChanged(State);
77 void stateChanged(State);
84− void nameChanged(QString);
78+ void liveChanged(bool live);
85− void parentSurfaceChanged(MirSurfaceItem*);
86− void childSurfacesChanged();
87−
88− void removed();
89
79
90 void inputMethodRequested();
80 void inputMethodRequested();
91 void inputMethodDismissed();
81 void inputMethodDismissed();
92
82
83+ // internal mock use
84+ void deregister();
85+
93private Q_SLOTS:
86private Q_SLOTS:
94 void onFocusChanged();
87 void onFocusChanged();
95 void onComponentStatusChanged(QQmlComponent::Status status);
88 void onComponentStatusChanged(QQmlComponent::Status status);
96 void onQmlWantInputMethodChanged();
89 void onQmlWantInputMethodChanged();
97
90
98private:
91private:
99− void addChildSurface(MirSurfaceItem* surface);
92+ explicit MirSurfaceItem(const QString& name,
100− void removeChildSurface(MirSurfaceItem* surface);
93+ Type type,
101−
94+ State state,
102− QQmlListProperty<MirSurfaceItem> childSurfaces();
95+ const QUrl& screenshot,
103− static int childSurfaceCount(QQmlListProperty<MirSurfaceItem> *prop);
96+ const QString &qmlFilePath = QString(),
104− static MirSurfaceItem* childSurfaceAt(QQmlListProperty<MirSurfaceItem> *prop, int index);
97+ QQuickItem *parent = 0);
105
98
106 void createQmlContentItem();
99 void createQmlContentItem();
107 void printComponentErrors();
100 void printComponentErrors();
108
101
109− ApplicationInfo* m_application;
102+ Session* m_session;
110 const QString m_name;
103 const QString m_name;
111 const Type m_type;
104 const Type m_type;
112 State m_state;
105 State m_state;
113−
106+ bool m_live;
114− MirSurfaceItem* m_parentSurface;
115− QList<MirSurfaceItem*> m_children;
116
107
117 QQmlComponent *m_qmlContentComponent;
108 QQmlComponent *m_qmlContentComponent;
118 QQuickItem *m_qmlItem;
109 QQuickItem *m_qmlItem;
119 QUrl m_screenshotUrl;
110 QUrl m_screenshotUrl;
111+
112+ friend class SurfaceManager;
120};
113};
121
114
122Q_DECLARE_METATYPE(MirSurfaceItem*)
115Q_DECLARE_METATYPE(MirSurfaceItem*)
tests/mocks/Unity/Application/MirSurfaceItemModel.hnew file+35
@@ -0,0 +1,35 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef MIRSURFACEITEMMODEL_H
18+#define MIRSURFACEITEMMODEL_H
19+
20+// Local
21+#include "ObjectListModel.h"
22+
23+class MirSurfaceItem;
24+class MirSurfaceItemModel: public ObjectListModel<MirSurfaceItem>
25+{
26+ Q_OBJECT
27+public:
28+ MirSurfaceItemModel(QObject *parent = 0): ObjectListModel(parent) {}
29+
30+ Q_INVOKABLE int count() const { return rowCount(); }
31+};
32+
33+Q_DECLARE_METATYPE(MirSurfaceItemModel*)
34+
35+#endif // MIRSURFACEITEMMODEL_H
tests/mocks/Unity/Application/ObjectListModel.hnew file+106
@@ -0,0 +1,106 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef OBJECTLISTMODEL_H
18+#define OBJECTLISTMODEL_H
19+
20+// Qt
21+#include <QAbstractListModel>
22+
23+template<class TYPE>
24+class ObjectListModel : public QAbstractListModel
25+{
26+public:
27+ ObjectListModel(QObject *parent = 0)
28+ : QAbstractListModel(parent)
29+ {}
30+
31+ enum Roles {
32+ RoleModelData = Qt::UserRole,
33+ };
34+
35+ const QList<TYPE*>& list() const { return m_items; }
36+ bool contains(TYPE* item) const { return m_items.contains(item); }
37+
38+ void insert(uint index, TYPE* item)
39+ {
40+ index = qMin(index, (uint)m_items.count());
41+
42+ int existingIndex = m_items.indexOf(item);
43+ if (existingIndex != -1) {
44+ move(existingIndex, qMin(index, (uint)(m_items.count()-1)));
45+ } else {
46+ beginInsertRows(QModelIndex(), index, index);
47+ m_items.insert(index, item);
48+ endInsertRows();
49+ }
50+ }
51+
52+ void remove(TYPE* item)
53+ {
54+ int existingIndex = m_items.indexOf(item);
55+ if (existingIndex != -1) {
56+ beginRemoveRows(QModelIndex(), existingIndex, existingIndex);
57+ m_items.removeAt(existingIndex);
58+ endRemoveRows();
59+ }
60+ }
61+
62+ // from QAbstractItemModel
63+ int rowCount(const QModelIndex& = QModelIndex()) const override
64+ {
65+ return m_items.count();
66+ }
67+
68+ QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override
69+ {
70+ if (index.row() >= 0 && index.row() < m_items.count()) {
71+ if (role == RoleModelData) {
72+ TYPE *item = m_items.at(index.row());
73+ return QVariant::fromValue(item);
74+ }
75+ }
76+ return QVariant();
77+ }
78+
79+ QHash<int, QByteArray> roleNames() const
80+ {
81+ QHash<int, QByteArray> roleNames;
82+ roleNames.insert(RoleModelData, "modelData");
83+ return roleNames;
84+ }
85+
86+protected:
87+ void move(int from, int to)
88+ {
89+ if (from == to) return;
90+
91+ if (from >= 0 && from < m_items.size() && to >= 0 && to < m_items.size()) {
92+ QModelIndex parent;
93+ /* When moving an item down, the destination index needs to be incremented
94+ by one, as explained in the documentation:
95+ http://qt-project.org/doc/qt-5.0/qtcore/qabstractitemmodel.html#beginMoveRows */
96+
97+ beginMoveRows(parent, from, from, parent, to + (to > from ? 1 : 0));
98+ m_items.move(from, to);
99+ endMoveRows();
100+ }
101+ }
102+
103+ QList<TYPE*> m_items;
104+};
105+
106+#endif // OBJECTLISTMODEL_H
tests/mocks/Unity/Application/Session.cppnew file+174
@@ -0,0 +1,174 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "Session.h"
18+#include "ApplicationInfo.h"
19+#include "SessionManager.h"
20+#include "SurfaceManager.h"
21+
22+#include <QPainter>
23+#include <QQmlEngine>
24+#include <QTimer>
25+
26+Session::Session(const QString &name,
27+ const QUrl& screenshot,
28+ QObject *parent)
29+ : QObject(parent)
30+ , m_name(name)
31+ , m_live(true)
32+ , m_screenshot(screenshot)
33+ , m_application(nullptr)
34+ , m_surface(nullptr)
35+ , m_parentSession(nullptr)
36+ , m_children(new SessionModel(this))
37+{
38+ qDebug() << "Session::Session() " << this->name();
39+
40+ QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
41+}
42+
43+Session::~Session()
44+{
45+ qDebug() << "Session::~Session() " << name();
46+
47+ QList<Session*> children(m_children->list());
48+ for (Session* child : children) {
49+ delete child;
50+ }
51+ if (m_parentSession) {
52+ m_parentSession->removeChildSession(this);
53+ }
54+ if (m_application) {
55+ m_application->setSession(nullptr);
56+ }
57+ delete m_surface;
58+ delete m_children;
59+}
60+
61+void Session::release()
62+{
63+ qDebug() << "Session::release " << name();
64+
65+ if (m_parentSession) {
66+ m_parentSession->removeChildSession(this);
67+ }
68+ if (m_application) {
69+ m_application->setSession(nullptr);
70+ }
71+ if (!parent()) {
72+ deleteLater();
73+ }
74+}
75+
76+void Session::setApplication(ApplicationInfo* application)
77+{
78+ if (m_application == application)
79+ return;
80+
81+ m_application = application;
82+ Q_EMIT applicationChanged(application);
83+}
84+
85+void Session::setSurface(MirSurfaceItem* surface)
86+{
87+ qDebug() << "Session::setSurface - session=" << name() << "surface=" << surface;
88+ if (m_surface == surface)
89+ return;
90+
91+ if (m_surface) {
92+ m_surface->setSession(nullptr);
93+ m_surface->setParent(nullptr);
94+ Q_EMIT m_surface->deregister();
95+ }
96+
97+ m_surface = surface;
98+
99+ if (m_surface) {
100+ m_surface->setSession(this);
101+ m_surface->setParent(this);
102+ SurfaceManager::singleton()->registerSurface(m_surface);
103+ }
104+
105+ Q_EMIT surfaceChanged(m_surface);
106+}
107+
108+void Session::setScreenshot(const QUrl& screenshot)
109+{
110+ if (screenshot != m_screenshot) {
111+ m_screenshot = screenshot;
112+ if (m_surface) {
113+ m_surface->setScreenshot(m_screenshot);
114+ }
115+ }
116+}
117+
118+void Session::setLive(bool live)
119+{
120+ if (m_live != live) {
121+ m_live = live;
122+ Q_EMIT liveChanged(m_live);
123+ }
124+}
125+
126+void Session::setParentSession(Session* session)
127+{
128+ if (m_parentSession == session || session == this)
129+ return;
130+
131+ m_parentSession = session;
132+ Q_EMIT parentSessionChanged(session);
133+}
134+
135+void Session::createSurface()
136+{
137+ if (m_surface) return;
138+
139+ setSurface(SurfaceManager::singleton()->createSurface(name(),
140+ MirSurfaceItem::Normal,
141+ m_application && m_application->fullscreen() ? MirSurfaceItem::Fullscreen :
142+ MirSurfaceItem::Maximized,
143+ m_screenshot));
144+}
145+
146+void Session::addChildSession(Session* session)
147+{
148+ insertChildSession(m_children->rowCount(), session);
149+}
150+
151+void Session::insertChildSession(uint index, Session* session)
152+{
153+ qDebug() << "Session::insertChildSession - " << session->name() << " to " << name() << " @ " << index;
154+
155+ session->setParentSession(this);
156+ m_children->insert(index, session);
157+ SessionManager::singleton()->registerSession(session);
158+}
159+
160+void Session::removeChildSession(Session* session)
161+{
162+ qDebug() << "Session::removeChildSession - " << session->name() << " from " << name();
163+
164+ if (m_children->contains(session)) {
165+ m_children->remove(session);
166+ session->setParentSession(nullptr);
167+ Q_EMIT session->deregister();
168+ }
169+}
170+
171+SessionModel* Session::childSessions() const
172+{
173+ return m_children;
174+}
tests/mocks/Unity/Application/Session.hnew file+90
@@ -0,0 +1,90 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef SESSION_H
18+#define SESSION_H
19+
20+#include "SessionModel.h"
21+
22+#include <QQuickItem>
23+
24+class ApplicationInfo;
25+class MirSurfaceItem;
26+
27+class Session : public QObject
28+{
29+ Q_OBJECT
30+ Q_PROPERTY(QString name READ name CONSTANT)
31+ Q_PROPERTY(MirSurfaceItem* surface READ surface NOTIFY surfaceChanged)
32+ Q_PROPERTY(ApplicationInfo* application READ application NOTIFY applicationChanged)
33+ Q_PROPERTY(Session* parentSession READ parentSession NOTIFY parentSessionChanged DESIGNABLE false)
34+ Q_PROPERTY(SessionModel* childSessions READ childSessions DESIGNABLE false CONSTANT)
35+ Q_PROPERTY(bool live READ live NOTIFY liveChanged)
36+
37+public:
38+ explicit Session(const QString &name,
39+ const QUrl& screenshot,
40+ QObject *parent = 0);
41+ ~Session();
42+
43+ Q_INVOKABLE void release();
44+
45+ //getters
46+ QString name() const { return m_name; }
47+ bool live() const { return m_live; }
48+ ApplicationInfo* application() const { return m_application; }
49+ MirSurfaceItem* surface() const { return m_surface; }
50+ Session* parentSession() const { return m_parentSession; }
51+
52+ void setApplication(ApplicationInfo* item);
53+ void setSurface(MirSurfaceItem* surface);
54+ void setScreenshot(const QUrl& m_screenshot);
55+ void setLive(bool live);
56+
57+ Q_INVOKABLE void addChildSession(Session* session);
58+ void insertChildSession(uint index, Session* session);
59+ void removeChildSession(Session* session);
60+
61+Q_SIGNALS:
62+ void applicationChanged(ApplicationInfo*);
63+ void surfaceChanged(MirSurfaceItem*);
64+ void parentSessionChanged(Session*);
65+ void liveChanged(bool live);
66+
67+ // internal mock use
68+ void deregister();
69+
70+public Q_SLOTS:
71+ Q_INVOKABLE void createSurface();
72+
73+private:
74+ SessionModel* childSessions() const;
75+ void setParentSession(Session* session);
76+
77+ QString m_name;
78+ bool m_live;
79+ QUrl m_screenshot;
80+ ApplicationInfo* m_application;
81+ MirSurfaceItem* m_surface;
82+ Session* m_parentSession;
83+ SessionModel* m_children;
84+
85+ friend class ApplicationTestInterface;
86+};
87+
88+Q_DECLARE_METATYPE(Session*)
89+
90+#endif // SESSION_H
tests/mocks/Unity/Application/SessionManager.cppnew file+55
@@ -0,0 +1,55 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "SessionManager.h"
18+
19+#include "Session.h"
20+
21+SessionManager *SessionManager::the_session_manager = nullptr;
22+
23+SessionManager *SessionManager::singleton()
24+{
25+ if (!the_session_manager) {
26+ the_session_manager = new SessionManager();
27+ }
28+ return the_session_manager;
29+}
30+
31+SessionManager::SessionManager(QObject *parent) :
32+ QObject(parent)
33+{
34+}
35+
36+
37+Session *SessionManager::createSession(const QString& name,
38+ const QUrl& screenshot)
39+{
40+ Session* session = new Session(name, screenshot);
41+ Q_EMIT sessionStarting(session);
42+ return session;
43+}
44+
45+void SessionManager::registerSession(Session *session)
46+{
47+ connect(session, &Session::deregister, this, [this] {
48+ Session* session = qobject_cast<Session*>(sender());
49+
50+ disconnect(session, 0, this, 0);
51+
52+ session->setLive(false);
53+ Q_EMIT sessionStopping(session);
54+ });
55+}
tests/mocks/Unity/Application/SessionManager.hnew file+44
@@ -0,0 +1,44 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef SESSIONMANAGER_H
18+#define SESSIONMANAGER_H
19+
20+#include <QObject>
21+
22+class Session;
23+
24+class SessionManager : public QObject
25+{
26+ Q_OBJECT
27+public:
28+ explicit SessionManager(QObject *parent = 0);
29+
30+ static SessionManager *singleton();
31+
32+ Q_INVOKABLE Session* createSession(const QString& name, const QUrl& screenshot);
33+
34+ void registerSession(Session *session);
35+
36+Q_SIGNALS:
37+ void sessionStarting(Session *session);
38+ void sessionStopping(Session *session);
39+
40+private:
41+ static SessionManager *the_session_manager;
42+};
43+
44+#endif // SESSIONMANAGER_H
tests/mocks/Unity/Application/SessionModel.hnew file+35
@@ -0,0 +1,35 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef SESSIONMODEL_H
18+#define SESSIONMODEL_H
19+
20+// Local
21+#include "ObjectListModel.h"
22+
23+class Session;
24+class SessionModel: public ObjectListModel<Session>
25+{
26+ Q_OBJECT
27+public:
28+ SessionModel(QObject *parent = 0): ObjectListModel(parent) {}
29+
30+ Q_INVOKABLE int count() const { return rowCount(); }
31+};
32+
33+Q_DECLARE_METATYPE(SessionModel*)
34+
35+#endif // SESSIONMODEL_H
tests/mocks/Unity/Application/SurfaceManager.cpp+20−7
@@ -35,19 +35,32 @@ SurfaceManager::SurfaceManager(QObject *parent) :
35{
35{
36}
36}
37
37
38+MirSurfaceItem *SurfaceManager::createSurface(const QString& name,
39+ MirSurfaceItem::Type type,
40+ MirSurfaceItem::State state,
41+ const QUrl& screenshot)
42+{
43+ MirSurfaceItem* surface = new MirSurfaceItem(name,
44+ type,
45+ state,
46+ screenshot);
47+ Q_EMIT surfaceCreated(surface);
48+ return surface;
49+}
50+
38void SurfaceManager::registerSurface(MirSurfaceItem *surface)
51void SurfaceManager::registerSurface(MirSurfaceItem *surface)
39{
52{
53+ connect(surface, &MirSurfaceItem::deregister, this, [this] {
54+ MirSurfaceItem* surface = qobject_cast<MirSurfaceItem*>(sender());
55+ disconnect(surface, 0, this, 0);
56+
57+ surface->setLive(false);
58+ Q_EMIT surfaceDestroyed(surface);
59+ });
40 connect(surface, &MirSurfaceItem::inputMethodRequested,
60 connect(surface, &MirSurfaceItem::inputMethodRequested,
41 this, &SurfaceManager::showInputMethod);
61 this, &SurfaceManager::showInputMethod);
42 connect(surface, &MirSurfaceItem::inputMethodDismissed,
62 connect(surface, &MirSurfaceItem::inputMethodDismissed,
43 this, &SurfaceManager::hideInputMethod);
63 this, &SurfaceManager::hideInputMethod);
44− Q_EMIT surfaceCreated(surface);
45−}
46−
47−void SurfaceManager::unregisterSurface(MirSurfaceItem *surface)
48−{
49− disconnect(surface, 0, this, 0);
50− Q_EMIT surfaceDestroyed(surface);
51}
64}
52
65
53void SurfaceManager::showInputMethod()
66void SurfaceManager::showInputMethod()
tests/mocks/Unity/Application/SurfaceManager.h+6−2
@@ -19,7 +19,7 @@
19
19
20#include <QObject>
20#include <QObject>
21
21
22−class MirSurfaceItem;
22+#include "MirSurfaceItem.h"
23
23
24class SurfaceManager : public QObject
24class SurfaceManager : public QObject
25{
25{
@@ -29,9 +29,13 @@ public:
29
29
30 static SurfaceManager *singleton();
30 static SurfaceManager *singleton();
31
31
32+ Q_INVOKABLE MirSurfaceItem *createSurface(const QString& name,
33+ MirSurfaceItem::Type type,
34+ MirSurfaceItem::State state,
35+ const QUrl& screenshot);
36+
32 // Internal mock use
37 // Internal mock use
33 void registerSurface(MirSurfaceItem *surface);
38 void registerSurface(MirSurfaceItem *surface);
34− void unregisterSurface(MirSurfaceItem *surface);
35
39
36 // To be used in the tests
40 // To be used in the tests
37 Q_INVOKABLE MirSurfaceItem *inputMethodSurface();
41 Q_INVOKABLE MirSurfaceItem *inputMethodSurface();
tests/mocks/Unity/Application/plugin.cpp+37−4
@@ -18,8 +18,12 @@
18#include "ApplicationInfo.h"
18#include "ApplicationInfo.h"
19#include "ApplicationManager.h"
19#include "ApplicationManager.h"
20#include "ApplicationScreenshotProvider.h"
20#include "ApplicationScreenshotProvider.h"
21+#include "Session.h"
21#include "MirSurfaceItem.h"
22#include "MirSurfaceItem.h"
23+#include "MirSurfaceItemModel.h"
22#include "SurfaceManager.h"
24#include "SurfaceManager.h"
25+#include "SessionManager.h"
26+#include "ApplicationTestInterface.h"
23
27
24#include <qqml.h>
28#include <qqml.h>
25#include <QQmlEngine>
29#include <QQmlEngine>
@@ -36,18 +40,45 @@ static QObject* surfaceManagerSingleton(QQmlEngine* engine, QJSEngine* scriptEng
36 return SurfaceManager::singleton();
40 return SurfaceManager::singleton();
37}
41}
38
42
43+static QObject* sessionManagerSingleton(QQmlEngine* engine, QJSEngine* scriptEngine) {
44+ Q_UNUSED(engine);
45+ Q_UNUSED(scriptEngine);
46+ return SessionManager::singleton();
47+}
48+
49+ApplicationTestInterface* s_appTestInterface = nullptr;
50+
51+static QObject* applicationTestInterface(QQmlEngine* engine, QJSEngine* scriptEngine) {
52+ Q_UNUSED(engine);
53+ Q_UNUSED(scriptEngine);
54+ if (!s_appTestInterface) {
55+ s_appTestInterface = new ApplicationTestInterface(engine);
56+ }
57+ return s_appTestInterface;
58+}
59+
39void FakeUnityApplicationQmlPlugin::registerTypes(const char *uri)
60void FakeUnityApplicationQmlPlugin::registerTypes(const char *uri)
40{
61{
62+ qRegisterMetaType<Session*>("Session*");
63+ qRegisterMetaType<ApplicationInfo*>("ApplicationInfo*");
64+ qRegisterMetaType<MirSurfaceItemModel*>("SessionModel*");
41 qRegisterMetaType<MirSurfaceItem*>("MirSurfaceItem*");
65 qRegisterMetaType<MirSurfaceItem*>("MirSurfaceItem*");
66+ qRegisterMetaType<MirSurfaceItemModel*>("MirSurfaceItemModel*");
42
67
43 qmlRegisterUncreatableType<unity::shell::application::ApplicationManagerInterface>(uri, 0, 1, "ApplicationManagerInterface", "Abstract interface. Cannot be created in QML");
68 qmlRegisterUncreatableType<unity::shell::application::ApplicationManagerInterface>(uri, 0, 1, "ApplicationManagerInterface", "Abstract interface. Cannot be created in QML");
44− qmlRegisterSingletonType<ApplicationManager>(uri, 0, 1, "ApplicationManager", applicationManagerSingleton);
45− qmlRegisterSingletonType<SurfaceManager>(uri, 0, 1, "SurfaceManager", surfaceManagerSingleton);
46−
47 qmlRegisterUncreatableType<unity::shell::application::ApplicationInfoInterface>(uri, 0, 1, "ApplicationInfoInterface", "Abstract interface. Cannot be created in QML");
69 qmlRegisterUncreatableType<unity::shell::application::ApplicationInfoInterface>(uri, 0, 1, "ApplicationInfoInterface", "Abstract interface. Cannot be created in QML");
70+ qmlRegisterUncreatableType<Session>(uri, 0, 1, "Session", "Session can't be instantiated from QML");
71+ qmlRegisterUncreatableType<MirSurfaceItem>(uri, 0, 1, "MirSurfaceItem", "MirSurfaceItem can't be instantiated from QML");
72+
48 qmlRegisterType<ApplicationInfo>(uri, 0, 1, "ApplicationInfo");
73 qmlRegisterType<ApplicationInfo>(uri, 0, 1, "ApplicationInfo");
49
74
50− qmlRegisterUncreatableType<MirSurfaceItem>(uri, 0, 1, "MirSurfaceItem", "MirSurfaceItem can't be instantiated from QML");
75+ qmlRegisterSingletonType<ApplicationManager>(uri, 0, 1, "ApplicationManager", applicationManagerSingleton);
76+ qmlRegisterSingletonType<SurfaceManager>(uri, 0, 1, "SurfaceManager", surfaceManagerSingleton);
77+ qmlRegisterSingletonType<SessionManager>(uri, 0, 1, "SessionManager", sessionManagerSingleton);
78+ qmlRegisterSingletonType<ApplicationTestInterface>(uri, 0, 1, "ApplicationTest", applicationTestInterface);
79+
80+ qRegisterMetaType<MirSurfaceItem::Type>("MirSurfaceItem::Type");
81+ qRegisterMetaType<MirSurfaceItem::State>("MirSurfaceItem::State");
51}
82}
52
83
53void FakeUnityApplicationQmlPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
84void FakeUnityApplicationQmlPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
@@ -55,4 +86,6 @@ void FakeUnityApplicationQmlPlugin::initializeEngine(QQmlEngine *engine, const c
55 QQmlExtensionPlugin::initializeEngine(engine, uri);
86 QQmlExtensionPlugin::initializeEngine(engine, uri);
56
87
57 engine->addImageProvider(QLatin1String("application"), new ApplicationScreenshotProvider(ApplicationManager::singleton()));
88 engine->addImageProvider(QLatin1String("application"), new ApplicationScreenshotProvider(ApplicationManager::singleton()));
89+ // make sure we initialise our test interface.
90+ applicationTestInterface(engine, nullptr);
58}
91}
tests/mocks/Unity/DashCommunicator/dashcommunicatorservice.cpp+2−2
@@ -27,7 +27,7 @@ DashCommunicatorService::~DashCommunicatorService()
27
27
28}
28}
29
29
30−void DashCommunicatorService::mockSetCurrentScope(const QString &scopeId, bool animate, bool reset)
30+void DashCommunicatorService::mockSetCurrentScope(const QString &scopeId, bool animate, bool isSwipe)
31{
31{
32− Q_EMIT setCurrentScopeRequested(scopeId, animate, reset);
32+ Q_EMIT setCurrentScopeRequested(scopeId, animate, isSwipe);
33}
33}
tests/mocks/Unity/DashCommunicator/dashcommunicatorservice.h+2−2
@@ -27,10 +27,10 @@ public:
27 ~DashCommunicatorService();
27 ~DashCommunicatorService();
28
28
29Q_SIGNALS:
29Q_SIGNALS:
30− void setCurrentScopeRequested(const QString &scopeId, bool animate, bool reset);
30+ void setCurrentScopeRequested(const QString &scopeId, bool animate, bool isSwipe);
31
31
32public Q_SLOTS:
32public Q_SLOTS:
33− void mockSetCurrentScope(const QString &scopeId, bool animate, bool reset);
33+ void mockSetCurrentScope(const QString &scopeId, bool animate, bool isSwipe);
34};
34};
35
35
36#endif // DBUSUNITYSESSIONSERVICE_H
36#endif // DBUSUNITYSESSIONSERVICE_H
tests/mocks/Unity/Indicators/Indicators.qmltypes+20
@@ -159,6 +159,26 @@ Module {
159 Property { name: "sourceModel"; type: "QAbstractItemModel"; isPointer: true }
159 Property { name: "sourceModel"; type: "QAbstractItemModel"; isPointer: true }
160 }
160 }
161 Component { name: "QIdentityProxyModel"; prototype: "QAbstractProxyModel" }
161 Component { name: "QIdentityProxyModel"; prototype: "QAbstractProxyModel" }
162+ Component {
163+ name: "UnityMenuModelCache"
164+ prototype: "QObject"
165+ exports: ["Unity.Indicators/UnityMenuModelCache 0.1"]
166+ isCreatable: false
167+ isSingleton: true
168+ exportMetaObjectRevisions: [0]
169+ Method {
170+ name: "model"
171+ type: "UnityMenuModel*"
172+ Parameter { name: "bus"; type: "QByteArray" }
173+ Parameter { name: "path"; type: "QByteArray" }
174+ Parameter { name: "actions"; type: "QVariantMap" }
175+ }
176+ Method {
177+ name: "contains"
178+ type: "bool"
179+ Parameter { name: "path"; type: "QByteArray" }
180+ }
181+ }
162 Component {
182 Component {
163 name: "UnityMenuModelStack"
183 name: "UnityMenuModelStack"
164 prototype: "QObject"
184 prototype: "QObject"
tests/mocks/Unity/Unity.qmltypes+30−2
@@ -36,6 +36,10 @@ Module {
36 prototype: "unity::shell::scopes::PreviewModelInterface"
36 prototype: "unity::shell::scopes::PreviewModelInterface"
37 exports: ["Unity/FakePreviewModel 0.2"]
37 exports: ["Unity/FakePreviewModel 0.2"]
38 exportMetaObjectRevisions: [0]
38 exportMetaObjectRevisions: [0]
39+ Method {
40+ name: "setLoaded"
41+ Parameter { type: "bool" }
42+ }
39 }
43 }
40 Component {
44 Component {
41 name: "PreviewStack"
45 name: "PreviewStack"
@@ -59,9 +63,9 @@ Module {
59 Component {
63 Component {
60 name: "ResultsModel"
64 name: "ResultsModel"
61 prototype: "unity::shell::scopes::ResultsModelInterface"
65 prototype: "unity::shell::scopes::ResultsModelInterface"
62− exports: ["Unity/ResultsModel 0.2"]
66+ exports: ["Unity/FakeResultsModel 0.2", "Unity/ResultsModel 0.2"]
63 isCreatable: false
67 isCreatable: false
64− exportMetaObjectRevisions: [0]
68+ exportMetaObjectRevisions: [0, 0]
65 }
69 }
66 Component {
70 Component {
67 name: "Scope"
71 name: "Scope"
@@ -134,7 +138,13 @@ Module {
134 }
138 }
135 Method { name: "clear" }
139 Method { name: "clear" }
136 Method { name: "load" }
140 Method { name: "load" }
141+ Method {
142+ name: "getScopeFromAll"
143+ type: "Scope*"
144+ Parameter { name: "scope_id"; type: "string" }
145+ }
137 }
146 }
147+ Component { name: "SettingsModel"; prototype: "unity::shell::scopes::SettingsModelInterface" }
138 Component {
148 Component {
139 name: "unity::shell::scopes::CategoriesInterface"
149 name: "unity::shell::scopes::CategoriesInterface"
140 prototype: "QAbstractListModel"
150 prototype: "QAbstractListModel"
@@ -402,4 +412,22 @@ Module {
402 Parameter { name: "scopeId"; type: "string" }
412 Parameter { name: "scopeId"; type: "string" }
403 }
413 }
404 }
414 }
415+ Component {
416+ name: "unity::shell::scopes::SettingsModelInterface"
417+ prototype: "QAbstractListModel"
418+ exports: ["Unity/SettingsModel 0.2"]
419+ isCreatable: false
420+ exportMetaObjectRevisions: [0]
421+ Enum {
422+ name: "Roles"
423+ values: {
424+ "RoleSettingId": 0,
425+ "RoleDisplayName": 1,
426+ "RoleType": 2,
427+ "RoleProperties": 3,
428+ "RoleValue": 4
429+ }
430+ }
431+ Property { name: "count"; type: "int"; isReadonly: true }
432+ }
405}
433}
tests/mocks/Unity/fake_scope.cpp+1−1
@@ -24,7 +24,7 @@
24#include "fake_scopes.h"
24#include "fake_scopes.h"
25#include "fake_settingsmodel.h"
25#include "fake_settingsmodel.h"
26
26
27−Scope::Scope(Scopes* parent) : Scope(QString(), QString(), false, parent)
27+Scope::Scope(Scopes* parent) : Scope("MockScope5", "Mock Scope", false, parent)
28{
28{
29}
29}
30
30
tests/plugins/Dash/cardcreator/2.res+2−2
@@ -94,7 +94,7 @@ Image {
94 wrapMode: Text.Wrap;
94 wrapMode: Text.Wrap;
95 maximumLineCount: 2;
95 maximumLineCount: 2;
96 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
96 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
97− color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
97+ color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
98 visible: showHeader ;
98 visible: showHeader ;
99 text: root.title;
99 text: root.title;
100 font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
100 font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
@@ -112,7 +112,7 @@ Image {
112 elide: Text.ElideRight;
112 elide: Text.ElideRight;
113 fontSize: "small";
113 fontSize: "small";
114 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
114 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
115− color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
115+ color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
116 visible: titleLabel.visible && titleLabel.text;
116 visible: titleLabel.visible && titleLabel.text;
117 text: cardData && cardData["subtitle"] || "";
117 text: cardData && cardData["subtitle"] || "";
118 font.weight: Font.Light;
118 font.weight: Font.Light;
tests/plugins/Dash/cardcreator/5.res+2−2
@@ -114,7 +114,7 @@ Label {
114 wrapMode: Text.Wrap;
114 wrapMode: Text.Wrap;
115 maximumLineCount: 2;
115 maximumLineCount: 2;
116 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
116 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
117− color: root.scopeStyle ? root.scopeStyle.getTextColor(overlayLoader.item.luminance) : (overlayLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
117+ color: root.scopeStyle && overlayLoader.item ? root.scopeStyle.getTextColor(overlayLoader.item.luminance) : (overlayLoader.item && overlayLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
118 visible: showHeader && overlayLoader.active;
118 visible: showHeader && overlayLoader.active;
119 text: root.title;
119 text: root.title;
120 font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
120 font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
@@ -133,7 +133,7 @@ Label {
133 elide: Text.ElideRight;
133 elide: Text.ElideRight;
134 fontSize: "small";
134 fontSize: "small";
135 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
135 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
136− color: root.scopeStyle ? root.scopeStyle.getTextColor(overlayLoader.item.luminance) : (overlayLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
136+ color: root.scopeStyle && overlayLoader.item ? root.scopeStyle.getTextColor(overlayLoader.item.luminance) : (overlayLoader.item && overlayLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
137 visible: titleLabel.visible && titleLabel.text;
137 visible: titleLabel.visible && titleLabel.text;
138 text: cardData && cardData["subtitle"] || "";
138 text: cardData && cardData["subtitle"] || "";
139 font.weight: Font.Light;
139 font.weight: Font.Light;
tests/plugins/Dash/cardcreator/6.res+3−3
@@ -70,7 +70,7 @@ Item {
70 wrapMode: Text.Wrap;
70 wrapMode: Text.Wrap;
71 maximumLineCount: 2;
71 maximumLineCount: 2;
72 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
72 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
73− color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
73+ color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
74 visible: showHeader ;
74 visible: showHeader ;
75 text: root.title;
75 text: root.title;
76 font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
76 font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
@@ -88,7 +88,7 @@ Item {
88 elide: Text.ElideRight;
88 elide: Text.ElideRight;
89 fontSize: "small";
89 fontSize: "small";
90 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
90 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
91− color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
91+ color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
92 visible: titleLabel.visible && titleLabel.text;
92 visible: titleLabel.visible && titleLabel.text;
93 text: cardData && cardData["subtitle"] || "";
93 text: cardData && cardData["subtitle"] || "";
94 font.weight: Font.Light;
94 font.weight: Font.Light;
@@ -103,7 +103,7 @@ Item {
103 rightMargin: units.gu(1);
103 rightMargin: units.gu(1);
104 }
104 }
105 source: cardData && cardData["emblem"] || "";
105 source: cardData && cardData["emblem"] || "";
106− color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
106+ color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
107 width: height;
107 width: height;
108 height: source != "" ? titleLabel.font.pixelSize : 0;
108 height: source != "" ? titleLabel.font.pixelSize : 0;
109 }
109 }
tests/plugins/Dash/cardcreator/7.res+3−3
@@ -95,7 +95,7 @@ Image {
95 wrapMode: Text.Wrap;
95 wrapMode: Text.Wrap;
96 maximumLineCount: 2;
96 maximumLineCount: 2;
97 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
97 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
98− color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
98+ color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
99 visible: showHeader ;
99 visible: showHeader ;
100 text: root.title;
100 text: root.title;
101 font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
101 font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
@@ -113,7 +113,7 @@ Image {
113 elide: Text.ElideRight;
113 elide: Text.ElideRight;
114 fontSize: "small";
114 fontSize: "small";
115 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
115 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
116− color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
116+ color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
117 visible: titleLabel.visible && titleLabel.text;
117 visible: titleLabel.visible && titleLabel.text;
118 text: cardData && cardData["subtitle"] || "";
118 text: cardData && cardData["subtitle"] || "";
119 font.weight: Font.Light;
119 font.weight: Font.Light;
@@ -127,7 +127,7 @@ Image {
127 rightMargin: units.gu(1);
127 rightMargin: units.gu(1);
128 top: subtitleLabel.bottom;
128 top: subtitleLabel.bottom;
129 }
129 }
130− color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
130+ color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
131 fontScale: root.fontScale;
131 fontScale: root.fontScale;
132 model: cardData && cardData["attributes"];
132 model: cardData && cardData["attributes"];
133 }
133 }
tests/plugins/Unity/Launcher/CMakeLists.txt+1−1
@@ -50,7 +50,7 @@ add_executable(launchermodeltestExec
50 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
50 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
51 )
51 )
52target_link_libraries(launchermodeltestExec ${GSETTINGS_QT_LDFLAGS})
52target_link_libraries(launchermodeltestExec ${GSETTINGS_QT_LDFLAGS})
53−qt5_use_modules(launchermodeltestExec Test Core DBus)
53+qt5_use_modules(launchermodeltestExec Test Core DBus Gui)
54
54
55# copy .desktop files into build directory for shadow builds
55# copy .desktop files into build directory for shadow builds
56file(GLOB DESKTOP_FILES *.desktop)
56file(GLOB DESKTOP_FILES *.desktop)
tests/qmltests/CMakeLists.txt+1
@@ -86,3 +86,4 @@ add_qml_test(Stages ApplicationWindow ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINAR
86add_qml_test(Stages PhoneStage ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
86add_qml_test(Stages PhoneStage ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
87add_qml_test(Stages SpreadDelegate ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
87add_qml_test(Stages SpreadDelegate ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
88add_qml_test(Stages SurfaceContainer ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
88add_qml_test(Stages SurfaceContainer ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
89+add_qml_test(Stages SessionContainer ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
tests/qmltests/Dash/Previews/tst_PreviewPayments.qml+49−9
@@ -48,19 +48,28 @@ Rectangle {
48 UT.UnityTestCase {
48 UT.UnityTestCase {
49 name: "PreviewPaymentsTest"
49 name: "PreviewPaymentsTest"
50 when: windowShown
50 when: windowShown
51+ property var paymentClient
52+
53+ function init()
54+ {
55+ paymentClient = findInvisibleChild(previewPayments, "paymentClient");
56+ verify(paymentClient, "Could not find the payment client object.");
57+ }
51
58
52 function cleanup()
59 function cleanup()
53 {
60 {
61+ paymentClient = null;
62+ previewPayments.widgetData = null;
54 spy.clear();
63 spy.clear();
55− var button = findChild(root, "paymentButton");
64+ var button = findChild(previewPayments, "paymentButton");
56 button.opacity = 1;
65 button.opacity = 1;
57 }
66 }
58
67
59 function test_purchase_text_display() {
68 function test_purchase_text_display() {
60 previewPayments.widgetData = jsonPurchase;
69 previewPayments.widgetData = jsonPurchase;
61
70
62− var button = findChild(root, "paymentButton");
71+ var button = findChild(previewPayments, "paymentButton");
63− verify(button != null, "Button not found.");
72+ verify(button, "Button not found.");
64 compare(button.text, "0.99USD");
73 compare(button.text, "0.99USD");
65 }
74 }
66
75
@@ -68,11 +77,12 @@ Rectangle {
68 // Exercise the purchaseCompleted signal here.
77 // Exercise the purchaseCompleted signal here.
69 previewPayments.widgetData = jsonPurchase;
78 previewPayments.widgetData = jsonPurchase;
70
79
71− var button = findChild(root, "paymentButton");
80+ var button = findChild(previewPayments, "paymentButton");
72− verify(button != null, "Button not found.");
81+ verify(button, "Button not found.");
73
82
74 mouseClick(button, button.width / 2, button.height / 2);
83 mouseClick(button, button.width / 2, button.height / 2);
75
84
85+ paymentClient.process();
76 spy.wait();
86 spy.wait();
77
87
78 var args = spy.signalArguments[0];
88 var args = spy.signalArguments[0];
@@ -85,8 +95,8 @@ Rectangle {
85 // Make sure the progress bar is shown.
95 // Make sure the progress bar is shown.
86 previewPayments.widgetData = jsonPurchase;
96 previewPayments.widgetData = jsonPurchase;
87
97
88− var button = findChild(root, "paymentButton");
98+ var button = findChild(previewPayments, "paymentButton");
89− var progress = findChild(root, "loadingBar");
99+ var progress = findChild(previewPayments, "loadingBar");
90
100
91 tryCompare(progress, "visible", false);
101 tryCompare(progress, "visible", false);
92 tryCompare(progress, "opacity", 0);
102 tryCompare(progress, "opacity", 0);
@@ -95,6 +105,7 @@ Rectangle {
95
105
96 mouseClick(button, button.width / 2, button.height / 2);
106 mouseClick(button, button.width / 2, button.height / 2);
97
107
108+ paymentClient.process();
98 spy.wait();
109 spy.wait();
99
110
100 tryCompare(progress, "visible", true);
111 tryCompare(progress, "visible", true);
@@ -103,16 +114,45 @@ Rectangle {
103 tryCompare(button, "opacity", 0);
114 tryCompare(button, "opacity", 0);
104 }
115 }
105
116
117+ function test_progress_show_cancel() {
118+ // Make sure the progress bar is shown.
119+ previewPayments.widgetData = jsonPurchaseError;
120+
121+ var button = findChild(previewPayments, "paymentButton");
122+ var progress = findChild(previewPayments, "loadingBar");
123+
124+ tryCompare(progress, "visible", false);
125+ tryCompare(progress, "opacity", 0);
126+ tryCompare(button, "visible", true);
127+ tryCompare(button, "opacity", 1);
128+
129+ mouseClick(button, button.width / 2, button.height / 2);
130+
131+ tryCompare(progress, "visible", true);
132+ tryCompare(progress, "opacity", 1);
133+ tryCompare(button, "visible", false);
134+ tryCompare(button, "opacity", 0);
135+
136+ paymentClient.process();
137+ spy.wait();
138+
139+ tryCompare(progress, "visible", false);
140+ tryCompare(progress, "opacity", 0);
141+ tryCompare(button, "visible", true);
142+ tryCompare(button, "opacity", 1);
143+ }
144+
106 function test_purchase_error() {
145 function test_purchase_error() {
107 // The mock Payments triggers an error when com.example.invalid is
146 // The mock Payments triggers an error when com.example.invalid is
108 // passed to it as store_item_id. Exercise it here
147 // passed to it as store_item_id. Exercise it here
109 previewPayments.widgetData = jsonPurchaseError;
148 previewPayments.widgetData = jsonPurchaseError;
110
149
111− var button = findChild(root, "paymentButton");
150+ var button = findChild(previewPayments, "paymentButton");
112− verify(button != null, "Button not found.");
151+ verify(button, "Button not found.");
113
152
114 mouseClick(button, button.width / 2, button.height / 2);
153 mouseClick(button, button.width / 2, button.height / 2);
115
154
155+ paymentClient.process();
116 spy.wait();
156 spy.wait();
117
157
118 var args = spy.signalArguments[0];
158 var args = spy.signalArguments[0];
tests/qmltests/Dash/tst_Dash.qml+9−2
@@ -189,6 +189,14 @@ Item {
189 var scopesOverviewAllView = findChild(dash, "scopesOverviewRepeaterChild1");
189 var scopesOverviewAllView = findChild(dash, "scopesOverviewRepeaterChild1");
190 tryCompare(scopesOverviewAllView, "enabled", true);
190 tryCompare(scopesOverviewAllView, "enabled", true);
191
191
192+ // Click in the middle of the black bar (nothing happens)
193+ var bottomBar = findChild(scopesOverview, "bottomBar");
194+ mouseClick(bottomBar, bottomBar.width / 2, bottomBar.height / 2);
195+ // Check temp scope is not there
196+ var scopesOverviewTempScopeItem = findChild(dash, "scopesOverviewTempScopeItem");
197+ expectFailContinue("", "Clicking in the middle of bottom bar should not open a temp scope");
198+ tryCompareFunction( function() { return scopesOverviewTempScopeItem.scope != null; }, true);
199+
192 // Click on a temp scope
200 // Click on a temp scope
193 var tempScopeCard = findChild(scopesOverviewAllView, "delegate1");
201 var tempScopeCard = findChild(scopesOverviewAllView, "delegate1");
194 mouseClick(tempScopeCard, 0, 0);
202 mouseClick(tempScopeCard, 0, 0);
@@ -198,7 +206,6 @@ Item {
198 compare(overviewDragHandle.enabled, false);
206 compare(overviewDragHandle.enabled, false);
199
207
200 // Check temp scope is there
208 // Check temp scope is there
201− var scopesOverviewTempScopeItem = findChild(dash, "scopesOverviewTempScopeItem");
202 tryCompareFunction( function() { return scopesOverviewTempScopeItem.scope != null; }, true);
209 tryCompareFunction( function() { return scopesOverviewTempScopeItem.scope != null; }, true);
203 tryCompare(scopesOverviewTempScopeItem, "enabled", true);
210 tryCompare(scopesOverviewTempScopeItem, "enabled", true);
204
211
@@ -328,7 +335,7 @@ Item {
328 mouseFlick(dash, startX, startY, stopX, stopY);
335 mouseFlick(dash, startX, startY, stopX, stopY);
329 compare(dashContentList.currentIndex, 2, "Could not flick to scope id 2");
336 compare(dashContentList.currentIndex, 2, "Could not flick to scope id 2");
330 var dashCommunicatorService = findInvisibleChild(dash, "dashCommunicatorService");
337 var dashCommunicatorService = findInvisibleChild(dash, "dashCommunicatorService");
331− dashCommunicatorService.mockSetCurrentScope("clickscope", true, true);
338+ dashCommunicatorService.mockSetCurrentScope("clickscope", true, false);
332 tryCompare(dashContentList, "currentIndex", 1)
339 tryCompare(dashContentList, "currentIndex", 1)
333 }
340 }
334
341
tests/qmltests/Dash/tst_PreviewListView.qml+29−1
@@ -16,6 +16,7 @@
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18import QtTest 1.0
18import QtTest 1.0
19+import Ubuntu.Components 1.1
19import "../../../qml/Dash"
20import "../../../qml/Dash"
20import Unity.Test 0.1 as UT
21import Unity.Test 0.1 as UT
21import Unity 0.2 as Unity
22import Unity 0.2 as Unity
@@ -39,7 +40,9 @@ Rectangle {
39 id: listView
40 id: listView
40 anchors.fill: parent
41 anchors.fill: parent
41 scope: mockScope
42 scope: mockScope
42− scopeStyle: ScopeStyle { }
43+ scopeStyle: ScopeStyle {
44+ style: mockScope.customizations
45+ }
43 }
46 }
44
47
45 UT.UnityTestCase {
48 UT.UnityTestCase {
@@ -83,5 +86,30 @@ Rectangle {
83 mouseClick(listView, listView.width / 2, listView.height / 2);
86 mouseClick(listView, listView.width / 2, listView.height / 2);
84 clickedSpy.wait();
87 clickedSpy.wait();
85 }
88 }
89+
90+ function test_title() {
91+ var header = findChild(listView, "innerPageHeader");
92+ verify(header, "Could not find the preview header");
93+
94+ compare(header.title, "Mock Scope");
95+ }
96+
97+ function test_header_style() {
98+ var header = findChild(listView, "pageHeader");
99+ verify(header, "Could not find the header");
100+
101+ var innerHeader = findChild(header, "innerPageHeader");
102+ verify(innerHeader, "Could not find the inner header");
103+ verify(Qt.colorEqual(innerHeader.textColor, UbuntuColors.darkGrey),
104+ "Foreground color not equal: %1 != %2".arg(innerHeader.textColor).arg(UbuntuColors.darkGrey));
105+
106+ var background = findChild(header, "headerBackground");
107+ verify(background, "Could not find the background");
108+ compare(background.style, "gradient:///lightgrey/grey");
109+
110+ var image = findChild(header, "titleImage");
111+ 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");
113+ }
86 }
114 }
87}
115}
tests/qmltests/Notifications/tst_Notifications.qml+59−17
@@ -64,7 +64,7 @@ Row {
64 function addSnapDecisionNotification() {
64 function addSnapDecisionNotification() {
65 var n = {
65 var n = {
66 type: Notification.SnapDecision,
66 type: Notification.SnapDecision,
67− hints: {"x-canonical-private-button-tint": "true"},
67+ hints: {"x-canonical-private-affirmative-tint": "true"},
68 summary: "Tom Ato",
68 summary: "Tom Ato",
69 body: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.",
69 body: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.",
70 icon: "../graphics/avatars/funky.png",
70 icon: "../graphics/avatars/funky.png",
@@ -79,6 +79,22 @@ Row {
79 mockModel.append(n)
79 mockModel.append(n)
80 }
80 }
81
81
82+ function add2over1SnapDecisionNotification() {
83+ var n = {
84+ type: Notification.SnapDecision,
85+ hints: {"x-canonical-private-affirmative-tint": "true",},
86+ summary: "Theatre at Ferria Stadium",
87+ body: "at Ferria Stadium in Bilbao, Spain\n07578545317",
88+ icon: "",
89+ secondaryIcon: "",
90+ actions: [{ id: "ok_id", label: "Ok"},
91+ { id: "snooze_id", label: "Snooze"},
92+ { id: "view_id", label: "View"}]
93+ }
94+
95+ mockModel.append(n)
96+ }
97+
82 function addEphemeralNotification() {
98 function addEphemeralNotification() {
83 var n = {
99 var n = {
84 type: Notification.Ephemeral,
100 type: Notification.Ephemeral,
@@ -181,6 +197,12 @@ Row {
181 onClicked: addSnapDecisionNotification()
197 onClicked: addSnapDecisionNotification()
182 }
198 }
183
199
200+ Button {
201+ width: parent.width
202+ text: "add a 2over1 snap-decision"
203+ onClicked: add2over1SnapDecisionNotification()
204+ }
205+
184 Button {
206 Button {
185 width: parent.width
207 width: parent.width
186 text: "add an ephemeral"
208 text: "add an ephemeral"
@@ -229,7 +251,7 @@ Row {
229 {
251 {
230 tag: "Snap Decision with secondary icon and button-tint",
252 tag: "Snap Decision with secondary icon and button-tint",
231 type: Notification.SnapDecision,
253 type: Notification.SnapDecision,
232− hints: {"x-canonical-private-button-tint": "true"},
254+ hints: {"x-canonical-private-affirmative-tint": "true"},
233 summary: "Tom Ato",
255 summary: "Tom Ato",
234 body: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.",
256 body: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.",
235 icon: "../graphics/avatars/funky.png",
257 icon: "../graphics/avatars/funky.png",
@@ -249,10 +271,31 @@ Row {
249 buttonTinted: true,
271 buttonTinted: true,
250 hasSound: false
272 hasSound: false
251 },
273 },
274+ {
275+ tag: "2-over-1 Snap Decision with button-tint",
276+ type: Notification.SnapDecision,
277+ hints: {"x-canonical-private-affirmative-tint": "true"},
278+ summary: "Theatre at Ferria Stadium",
279+ body: "at Ferria Stadium in Bilbao, Spain\n07578545317",
280+ icon: "",
281+ secondaryIcon: "",
282+ actions: [{ id: "ok_id", label: "Ok"},
283+ { id: "snooze_id", label: "Snooze"},
284+ { id: "view_id", label: "View"}],
285+ summaryVisible: true,
286+ bodyVisible: true,
287+ iconVisible: false,
288+ shapedIcon: false,
289+ nonShapedIcon: false,
290+ secondaryIconVisible: false,
291+ buttonRowVisible: false,
292+ buttonTinted: true,
293+ hasSound: false
294+ },
252 {
295 {
253 tag: "Ephemeral notification - icon-summary layout",
296 tag: "Ephemeral notification - icon-summary layout",
254 type: Notification.Ephemeral,
297 type: Notification.Ephemeral,
255− hints: {"x-canonical-private-button-tint": "false"},
298+ hints: {"x-canonical-private-affirmative-tint": "false"},
256 summary: "Photo upload completed",
299 summary: "Photo upload completed",
257 body: "",
300 body: "",
258 icon: "",
301 icon: "",
@@ -271,7 +314,7 @@ Row {
271 {
314 {
272 tag: "Ephemeral notification - check suppression of secondary icon for icon-summary layout",
315 tag: "Ephemeral notification - check suppression of secondary icon for icon-summary layout",
273 type: Notification.Ephemeral,
316 type: Notification.Ephemeral,
274− hints: {"x-canonical-private-button-tint": "false",
317+ hints: {"x-canonical-private-affirmative-tint": "false",
275 "sound-file": "dummy.ogg",
318 "sound-file": "dummy.ogg",
276 "suppress-sound": "true"},
319 "suppress-sound": "true"},
277 summary: "New comment successfully published",
320 summary: "New comment successfully published",
@@ -293,7 +336,7 @@ Row {
293 {
336 {
294 tag: "Interactive notification",
337 tag: "Interactive notification",
295 type: Notification.Interactive,
338 type: Notification.Interactive,
296− hints: {"x-canonical-private-button-tint": "false",
339+ hints: {"x-canonical-private-affirmative-tint": "false",
297 "sound-file": "dummy.ogg"},
340 "sound-file": "dummy.ogg"},
298 summary: "Interactive notification",
341 summary: "Interactive notification",
299 body: "This is a notification that can be clicked",
342 body: "This is a notification that can be clicked",
@@ -313,7 +356,7 @@ Row {
313 {
356 {
314 tag: "Snap Decision without secondary icon and no button-tint",
357 tag: "Snap Decision without secondary icon and no button-tint",
315 type: Notification.SnapDecision,
358 type: Notification.SnapDecision,
316− hints: {"x-canonical-private-button-tint": "false",
359+ hints: {"x-canonical-private-affirmative-tint": "false",
317 "sound-file": "dummy.ogg"},
360 "sound-file": "dummy.ogg"},
318 summary: "Bro Coly",
361 summary: "Bro Coly",
319 body: "At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.",
362 body: "At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.",
@@ -334,7 +377,7 @@ Row {
334 {
377 {
335 tag: "Ephemeral notification",
378 tag: "Ephemeral notification",
336 type: Notification.Ephemeral,
379 type: Notification.Ephemeral,
337− hints: {"x-canonical-private-button-tint": "false",
380+ hints: {"x-canonical-private-affirmative-tint": "false",
338 "sound-file": "dummy.ogg"},
381 "sound-file": "dummy.ogg"},
339 summary: "Cole Raby",
382 summary: "Cole Raby",
340 body: "I did not expect it to be that late.",
383 body: "I did not expect it to be that late.",
@@ -354,9 +397,8 @@ Row {
354 {
397 {
355 tag: "Ephemeral notification with non-shaped icon",
398 tag: "Ephemeral notification with non-shaped icon",
356 type: Notification.Ephemeral,
399 type: Notification.Ephemeral,
357− hints: {"x-canonical-private-button-tint": "false",
400+ hints: {"x-canonical-private-affirmative-tint": "false",
358− "x-canonical-non-shaped-icon": "true",
401+ "x-canonical-non-shaped-icon": "true"},
359− "sound-file": "dummy.ogg"},
360 summary: "Contacts",
402 summary: "Contacts",
361 body: "Synchronised contacts-database with cloud-storage.",
403 body: "Synchronised contacts-database with cloud-storage.",
362 icon: "../graphics/applicationIcons/contacts-app.png",
404 icon: "../graphics/applicationIcons/contacts-app.png",
@@ -370,7 +412,7 @@ Row {
370 secondaryIconVisible: false,
412 secondaryIconVisible: false,
371 buttonRowVisible: false,
413 buttonRowVisible: false,
372 buttonTinted: false,
414 buttonTinted: false,
373− hasSound: true
415+ hasSound: false
374 }
416 }
375 ]
417 ]
376 }
418 }
@@ -437,8 +479,8 @@ Row {
437 tryCompare(audioItem, "playbackState", data.hasSound ? Audio.PlayingState : Audio.StoppedState)
479 tryCompare(audioItem, "playbackState", data.hasSound ? Audio.PlayingState : Audio.StoppedState)
438
480
439 if(data.buttonRowVisible) {
481 if(data.buttonRowVisible) {
440− var buttonCancel = findChild(buttonRow, "button1")
482+ var buttonCancel = findChild(buttonRow, "notify_button1")
441− var buttonAccept = findChild(buttonRow, "button0")
483+ var buttonAccept = findChild(buttonRow, "notify_button0")
442
484
443 // only test the left/cancel-button if two actions have been passed in
485 // only test the left/cancel-button if two actions have been passed in
444 if (data.actions.length == 2) {
486 if (data.actions.length == 2) {
@@ -448,7 +490,7 @@ Row {
448 }
490 }
449
491
450 // check the tinting of the positive/right button
492 // check the tinting of the positive/right button
451− verify(buttonAccept.gradient === data.buttonTinted ? UbuntuColors.orangeGradient : UbuntuColors.greyGradient, "button has the wrong color-tint")
493+ verify(buttonAccept.color === data.buttonTinted ? "#3fb24f" : "#dddddd", "button has the wrong color-tint")
452
494
453 // click the positive/right button
495 // click the positive/right button
454 tryCompareFunction(function() { mouseClick(buttonAccept, buttonAccept.width / 2, buttonAccept.height / 2); return actionSpy.signalArguments.length > 0; }, true);
496 tryCompareFunction(function() { mouseClick(buttonAccept, buttonAccept.width / 2, buttonAccept.height / 2); return actionSpy.signalArguments.length > 0; }, true);
@@ -458,19 +500,19 @@ Row {
458
500
459 // check if there's a ComboButton created due to more actions being passed
501 // check if there's a ComboButton created due to more actions being passed
460 if (data.actions.length > 2) {
502 if (data.actions.length > 2) {
461− var comboButton = findChild(notification, "button2")
503+ var comboButton = findChild(notification, "notify_button2")
462 tryCompareFunction(function() { return comboButton.expanded == false; }, true);
504 tryCompareFunction(function() { return comboButton.expanded == false; }, true);
463
505
464 // click to expand
506 // click to expand
465 tryCompareFunction(function() { mouseClick(comboButton, comboButton.width - comboButton.__styleInstance.dropDownWidth / 2, comboButton.height / 2); return comboButton.expanded == true; }, true);
507 tryCompareFunction(function() { mouseClick(comboButton, comboButton.width - comboButton.__styleInstance.dropDownWidth / 2, comboButton.height / 2); return comboButton.expanded == true; }, true);
466
508
467 // try clicking on choices in expanded comboList
509 // try clicking on choices in expanded comboList
468− var choiceButton1 = findChild(notification, "button3")
510+ var choiceButton1 = findChild(notification, "notify_button3")
469 tryCompareFunction(function() { mouseClick(choiceButton1, choiceButton1.width / 2, choiceButton1.height / 2); return actionSpy.signalArguments.length > 0; }, true);
511 tryCompareFunction(function() { mouseClick(choiceButton1, choiceButton1.width / 2, choiceButton1.height / 2); return actionSpy.signalArguments.length > 0; }, true);
470 compare(actionSpy.signalArguments[0][0], data.actions[3]["id"], "got wrong id choice action 1")
512 compare(actionSpy.signalArguments[0][0], data.actions[3]["id"], "got wrong id choice action 1")
471 actionSpy.clear()
513 actionSpy.clear()
472
514
473− var choiceButton2 = findChild(notification, "button4")
515+ var choiceButton2 = findChild(notification, "notify_button4")
474 tryCompareFunction(function() { mouseClick(choiceButton2, choiceButton2.width / 2, choiceButton2.height / 2); return actionSpy.signalArguments.length > 0; }, true);
516 tryCompareFunction(function() { mouseClick(choiceButton2, choiceButton2.width / 2, choiceButton2.height / 2); return actionSpy.signalArguments.length > 0; }, true);
475 compare(actionSpy.signalArguments[0][0], data.actions[4]["id"], "got wrong id choice action 2")
517 compare(actionSpy.signalArguments[0][0], data.actions[4]["id"], "got wrong id choice action 2")
476 actionSpy.clear()
518 actionSpy.clear()
tests/qmltests/Panel/tst_ActiveCallHint.qml+1−1
@@ -97,7 +97,7 @@ Item {
97 var application = ApplicationManager.startApplication("dialer-app");
97 var application = ApplicationManager.startApplication("dialer-app");
98 ApplicationManager.focusApplication("dialer-app");
98 ApplicationManager.focusApplication("dialer-app");
99 tryCompare(ApplicationManager, "focusedApplicationId", "dialer-app");
99 tryCompare(ApplicationManager, "focusedApplicationId", "dialer-app");
100− tryCompare(application, "state", ApplicationInfo.Running);
100+ tryCompare(application, "state", ApplicationInfoInterface.Running);
101
101
102 if (!data.focused) { ApplicationManager.unfocusCurrentApplication(); }
102 if (!data.focused) { ApplicationManager.unfocusCurrentApplication(); }
103 }
103 }
tests/qmltests/Stages/RecursingChildSessionControl.qmlnew file+142
@@ -0,0 +1,142 @@
1+/*
2+ * Copyright 2014 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.1
18+import QtQuick.Layouts 1.1
19+import Ubuntu.Components 0.1
20+import Unity.Application 0.1
21+
22+ColumnLayout {
23+ id: root
24+
25+ property var session
26+ property var childSessions: session ? session.childSessions : 0
27+ property bool removable: false
28+ property alias surfaceCheckbox: _surfaceCheckbox
29+
30+ property var screenshotIds: [ "gallery", "map", "facebook", "camera", "browser", "music", "twitter"]
31+
32+ onSessionChanged: {
33+ if (!session) surfaceCheckbox.checked = false;
34+ }
35+
36+ Column {
37+ id: column
38+ Layout.fillWidth: true
39+ visible: repeater.count
40+ spacing: units.gu(1)
41+
42+ Repeater {
43+ id: repeater
44+ model: root.childSessions
45+ delegate: Rectangle {
46+ border {
47+ color: "black"
48+ width: 1
49+ }
50+ anchors {
51+ left: column.left
52+ right: column.right
53+ leftMargin: units.gu(1)
54+ rightMargin: units.gu(1)
55+ }
56+ height: loader.height
57+
58+ Rectangle {
59+ anchors.fill: parent
60+ color: Qt.rgba(Math.random(), Math.random(), Math.random(), 0.4 )
61+ }
62+
63+ Loader {
64+ id: loader
65+ visible: status == Loader.Ready
66+ source: Qt.resolvedUrl("RecursingChildSessionControl.qml")
67+
68+ anchors {
69+ left: parent.left
70+ right: parent.right
71+ }
72+
73+ onLoaded: {
74+ item.session = modelData;
75+ item.removable = true;
76+ }
77+ }
78+ }
79+ }
80+ }
81+
82+ ColumnLayout {
83+ Layout.fillWidth: true
84+ spacing: units.gu(1)
85+
86+ RowLayout {
87+ Layout.fillWidth: true
88+
89+ CheckBox {
90+ id: _surfaceCheckbox;
91+ checked: false;
92+ enabled: root.session
93+ onCheckedChanged: {
94+ if (checked) {
95+ root.session.createSurface();
96+ } else if (root.session.surface) {
97+ ApplicationTest.removeSurface(root.session.surface);
98+ }
99+ }
100+
101+ Connections {
102+ target: root.session ? root.session : null
103+ onSurfaceChanged: {
104+ surfaceCheckbox.checked = root.session.surface !== null
105+ }
106+ }
107+ }
108+
109+ Label {
110+ text: "Surface"
111+ anchors.verticalCenter: parent.verticalCenter
112+ }
113+ }
114+
115+ RowLayout {
116+ id: buttonLayout
117+
118+ Button {
119+ enabled: root.session
120+ text: removable ? "Remove" : "Release"
121+ onClicked: {
122+ if (removable) {
123+ // release the surface first. simulates mir app closing
124+ if (root.session.surface) ApplicationTest.removeSurface(root.session.surface);
125+ ApplicationTest.removeSession(root.session);
126+ } else {
127+ root.session.release();
128+ }
129+ }
130+ }
131+
132+ Button {
133+ enabled: root.session !== null
134+ text: "Add Child"
135+ onClicked: {
136+ var screenshot = Math.round(Math.random()*100 % (screenshotIds.length-1));
137+ var session = ApplicationTest.addChildSession(root.session, root.screenshotIds[screenshot]);
138+ }
139+ }
140+ }
141+ }
142+}
tests/qmltests/Stages/tst_ApplicationWindow.qml+99−47
@@ -14,7 +14,8 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
15 */
16
16
17−import QtQuick 2.0
17+import QtQuick 2.1
18+import QtQuick.Layouts 1.1
18import QtTest 1.0
19import QtTest 1.0
19import Unity.Test 0.1 as UT
20import Unity.Test 0.1 as UT
20import ".."
21import ".."
@@ -32,14 +33,15 @@ Rectangle {
32 Component.onCompleted: {
33 Component.onCompleted: {
33 root.fakeApplication = ApplicationManager.add("gallery-app");
34 root.fakeApplication = ApplicationManager.add("gallery-app");
34 root.fakeApplication.manualSurfaceCreation = true;
35 root.fakeApplication.manualSurfaceCreation = true;
35− root.fakeApplication.setState(ApplicationInfo.Starting);
36+ root.fakeApplication.setState(ApplicationInfoInterface.Starting);
36 }
37 }
37 property QtObject fakeApplication: null
38 property QtObject fakeApplication: null
39+ readonly property var fakeSession: fakeApplication ? fakeApplication.session : null
38
40
39 Connections {
41 Connections {
40 target: fakeApplication
42 target: fakeApplication
41− onSurfaceChanged: {
43+ onSessionChanged: {
42− surfaceCheckbox.checked = fakeApplication.surface !== null;
44+ sessionCheckbox.checked = fakeApplication.session !== null
43 }
45 }
44 }
46 }
45
47
@@ -50,15 +52,20 @@ Rectangle {
50 application: fakeApplication
52 application: fakeApplication
51 }
53 }
52 }
54 }
53− Loader {
55+ FocusScope {
54− id: applicationWindowLoader
56+ id: appFocus
55 anchors {
57 anchors {
56 top: parent.top
58 top: parent.top
57 bottom: parent.bottom
59 bottom: parent.bottom
58 left: parent.left
60 left: parent.left
59 }
61 }
60 width: units.gu(40)
62 width: units.gu(40)
63+
64+ Loader {
65+ id: applicationWindowLoader
66+ anchors.fill: parent
61− sourceComponent: applicationWindowComponent
67+ sourceComponent: applicationWindowComponent
68+ }
62 }
69 }
63
70
64 Rectangle {
71 Rectangle {
@@ -66,30 +73,55 @@ Rectangle {
66 anchors {
73 anchors {
67 top: parent.top
74 top: parent.top
68 bottom: parent.bottom
75 bottom: parent.bottom
69− left: applicationWindowLoader.right
76+ left: appFocus.right
70 right: parent.right
77 right: parent.right
71 }
78 }
72
79
73− Column {
80+ ColumnLayout {
74 anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
81 anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
75 spacing: units.gu(1)
82 spacing: units.gu(1)
76− Row {
83+
77− anchors { left: parent.left; right: parent.right }
84+ RowLayout {
85+ Layout.fillWidth: true
86+
78 CheckBox {
87 CheckBox {
79− id: surfaceCheckbox; checked: false
88+ id: sessionCheckbox; checked: false
80 onCheckedChanged: {
89 onCheckedChanged: {
81 if (applicationWindowLoader.status !== Loader.Ready)
90 if (applicationWindowLoader.status !== Loader.Ready)
82 return;
91 return;
83
92
84− if (checked && !fakeApplication.surface) {
93+ if (checked && !fakeApplication.session) {
85− fakeApplication.createSurface();
94+ fakeApplication.createSession();
86− } else if (!checked && fakeApplication.surface) {
95+ } else if (!checked && fakeApplication.session) {
87− fakeApplication.surface.release();
96+ fakeApplication.session.release();
88 }
97 }
89 }
98 }
90 }
99 }
91− Label { text: "Surface" }
100+ Label {
101+ text: "Session"
102+ anchors.verticalCenter: parent.verticalCenter
103+ }
92 }
104 }
105+
106+ Rectangle {
107+ border {
108+ color: "black"
109+ width: 1
110+ }
111+ anchors {
112+ left: parent.left
113+ right: parent.right
114+ }
115+ Layout.preferredHeight: sessionControl.height
116+
117+ RecursingChildSessionControl {
118+ id: sessionControl
119+ anchors { left: parent.left; right: parent.right; }
120+
121+ session: fakeSession
122+ }
123+ }
124+
93 ListItem.ItemSelector {
125 ListItem.ItemSelector {
94 id: appStateSelector
126 id: appStateSelector
95 anchors { left: parent.left; right: parent.right }
127 anchors { left: parent.left; right: parent.right }
@@ -100,13 +132,13 @@ Rectangle {
100 "Stopped"]
132 "Stopped"]
101 property int selectedApplicationState: {
133 property int selectedApplicationState: {
102 if (model[selectedIndex] === "Starting") {
134 if (model[selectedIndex] === "Starting") {
103− return ApplicationInfo.Starting;
135+ return ApplicationInfoInterface.Starting;
104 } else if (model[selectedIndex] === "Running") {
136 } else if (model[selectedIndex] === "Running") {
105− return ApplicationInfo.Running;
137+ return ApplicationInfoInterface.Running;
106 } else if (model[selectedIndex] === "Suspended") {
138 } else if (model[selectedIndex] === "Suspended") {
107− return ApplicationInfo.Suspended;
139+ return ApplicationInfoInterface.Suspended;
108 } else {
140 } else {
109− return ApplicationInfo.Stopped;
141+ return ApplicationInfoInterface.Stopped;
110 }
142 }
111 }
143 }
112 onSelectedApplicationStateChanged: {
144 onSelectedApplicationStateChanged: {
@@ -114,6 +146,7 @@ Rectangle {
114 fakeApplication.setState(selectedApplicationState);
146 fakeApplication.setState(selectedApplicationState);
115 }
147 }
116 }
148 }
149+
117 }
150 }
118 }
151 }
119
152
@@ -123,10 +156,10 @@ Rectangle {
123 when: windowShown
156 when: windowShown
124
157
125 // just to make them shorter
158 // just to make them shorter
126− property int appStarting: ApplicationInfo.Starting
159+ property int appStarting: ApplicationInfoInterface.Starting
127− property int appRunning: ApplicationInfo.Running
160+ property int appRunning: ApplicationInfoInterface.Running
128− property int appSuspended: ApplicationInfo.Suspended
161+ property int appSuspended: ApplicationInfoInterface.Suspended
129− property int appStopped: ApplicationInfo.Stopped
162+ property int appStopped: ApplicationInfoInterface.Stopped
130
163
131 function setApplicationState(appState) {
164 function setApplicationState(appState) {
132 switch (appState) {
165 switch (appState) {
@@ -170,6 +203,14 @@ Rectangle {
170 findInterestingApplicationWindowChildren();
203 findInterestingApplicationWindowChildren();
171 }
204 }
172
205
206+ function initSession() {
207+ sessionCheckbox.checked = true;
208+ sessionControl.surfaceCheckbox.checked = true;
209+ }
210+ function cleanupSession() {
211+ sessionCheckbox.checked = false;
212+ }
213+
173 function cleanup() {
214 function cleanup() {
174 forgetApplicationWindowChildren();
215 forgetApplicationWindowChildren();
175
216
@@ -177,10 +218,10 @@ Rectangle {
177 applicationWindowLoader.active = false;
218 applicationWindowLoader.active = false;
178
219
179 appStateSelector.selectedIndex = 0;
220 appStateSelector.selectedIndex = 0;
180− surfaceCheckbox.checked = false;
221+ cleanupSession();
181
222
182− if (fakeApplication.surface)
223+ if (fakeApplication.session)
183− fakeApplication.surface.release();
224+ fakeApplication.session.release();
184
225
185 applicationWindowLoader.active = true;
226 applicationWindowLoader.active = true;
186 }
227 }
@@ -197,7 +238,7 @@ Rectangle {
197 verify(stateGroup.state === "splashScreen");
238 verify(stateGroup.state === "splashScreen");
198
239
199 if (data.swapInitOrder) {
240 if (data.swapInitOrder) {
200− surfaceCheckbox.checked = true;
241+ initSession();
201 } else {
242 } else {
202 setApplicationState(appRunning);
243 setApplicationState(appRunning);
203 }
244 }
@@ -207,14 +248,14 @@ Rectangle {
207 if (data.swapInitOrder) {
248 if (data.swapInitOrder) {
208 setApplicationState(appRunning);
249 setApplicationState(appRunning);
209 } else {
250 } else {
210− surfaceCheckbox.checked = true;
251+ initSession();
211 }
252 }
212
253
213 tryCompare(stateGroup, "state", "surface");
254 tryCompare(stateGroup, "state", "surface");
214 }
255 }
215
256
216 function test_suspendedAppShowsSurface() {
257 function test_suspendedAppShowsSurface() {
217− surfaceCheckbox.checked = true;
258+ initSession();
218 setApplicationState(appRunning);
259 setApplicationState(appRunning);
219
260
220 tryCompare(stateGroup, "state", "surface");
261 tryCompare(stateGroup, "state", "surface");
@@ -228,7 +269,7 @@ Rectangle {
228 }
269 }
229
270
230 function test_killedAppShowsScreenshot() {
271 function test_killedAppShowsScreenshot() {
231− surfaceCheckbox.checked = true;
272+ initSession();
232 setApplicationState(appRunning);
273 setApplicationState(appRunning);
233 tryCompare(stateGroup, "state", "surface");
274 tryCompare(stateGroup, "state", "surface");
234
275
@@ -241,13 +282,13 @@ Rectangle {
241 setApplicationState(appStopped);
282 setApplicationState(appStopped);
242
283
243 tryCompare(stateGroup, "state", "screenshot");
284 tryCompare(stateGroup, "state", "screenshot");
244− tryCompare(fakeApplication, "surface", null);
285+ tryCompare(fakeApplication, "session", null);
245 }
286 }
246
287
247 function test_restartApp() {
288 function test_restartApp() {
248 var screenshotImage = findChild(applicationWindowLoader.item, "screenshotImage");
289 var screenshotImage = findChild(applicationWindowLoader.item, "screenshotImage");
249
290
250− surfaceCheckbox.checked = true;
291+ initSession();
251 setApplicationState(appRunning);
292 setApplicationState(appRunning);
252 tryCompare(stateGroup, "state", "surface");
293 tryCompare(stateGroup, "state", "surface");
253 waitUntilTransitionsEnd();
294 waitUntilTransitionsEnd();
@@ -259,28 +300,28 @@ Rectangle {
259
300
260 tryCompare(stateGroup, "state", "screenshot");
301 tryCompare(stateGroup, "state", "screenshot");
261 waitUntilTransitionsEnd();
302 waitUntilTransitionsEnd();
262− tryCompare(fakeApplication, "surface", null);
303+ tryCompare(fakeApplication, "session", null);
263
304
264 // and restart it
305 // and restart it
265 setApplicationState(appStarting);
306 setApplicationState(appStarting);
266
307
267 waitUntilTransitionsEnd();
308 waitUntilTransitionsEnd();
268 verify(stateGroup.state === "screenshot");
309 verify(stateGroup.state === "screenshot");
269− verify(fakeApplication.surface === null);
310+ verify(fakeSession === null);
270
311
271 setApplicationState(appRunning);
312 setApplicationState(appRunning);
272
313
273 waitUntilTransitionsEnd();
314 waitUntilTransitionsEnd();
274 verify(stateGroup.state === "screenshot");
315 verify(stateGroup.state === "screenshot");
275
316
276− surfaceCheckbox.checked = true;
317+ initSession();
277
318
278 tryCompare(stateGroup, "state", "surface");
319 tryCompare(stateGroup, "state", "surface");
279 tryCompare(screenshotImage, "status", Image.Null);
320 tryCompare(screenshotImage, "status", Image.Null);
280 }
321 }
281
322
282 function test_appCrashed() {
323 function test_appCrashed() {
283− surfaceCheckbox.checked = true;
324+ initSession();
284 setApplicationState(appRunning);
325 setApplicationState(appRunning);
285 tryCompare(stateGroup, "state", "surface");
326 tryCompare(stateGroup, "state", "surface");
286 waitUntilTransitionsEnd();
327 waitUntilTransitionsEnd();
@@ -289,39 +330,39 @@ Rectangle {
289 setApplicationState(appStopped);
330 setApplicationState(appStopped);
290
331
291 tryCompare(stateGroup, "state", "screenshot");
332 tryCompare(stateGroup, "state", "screenshot");
292− tryCompare(fakeApplication, "surface", null);
333+ tryCompare(fakeApplication, "session", null);
293 }
334 }
294
335
295 function test_keepSurfaceWhileInvisible() {
336 function test_keepSurfaceWhileInvisible() {
296− surfaceCheckbox.checked = true;
337+ initSession();
297 setApplicationState(appRunning);
338 setApplicationState(appRunning);
298 tryCompare(stateGroup, "state", "surface");
339 tryCompare(stateGroup, "state", "surface");
299 waitUntilTransitionsEnd();
340 waitUntilTransitionsEnd();
300− verify(fakeApplication.surface !== null);
341+ verify(fakeSession.surface !== null);
301
342
302 applicationWindowLoader.item.visible = false;
343 applicationWindowLoader.item.visible = false;
303
344
304 waitUntilTransitionsEnd();
345 waitUntilTransitionsEnd();
305 verify(stateGroup.state === "surface");
346 verify(stateGroup.state === "surface");
306− verify(fakeApplication.surface !== null);
347+ verify(fakeSession.surface !== null);
307
348
308 applicationWindowLoader.item.visible = true;
349 applicationWindowLoader.item.visible = true;
309
350
310 waitUntilTransitionsEnd();
351 waitUntilTransitionsEnd();
311 verify(stateGroup.state === "surface");
352 verify(stateGroup.state === "surface");
312− verify(fakeApplication.surface !== null);
353+ verify(fakeSession.surface !== null);
313 }
354 }
314
355
315 function test_touchesReachSurfaceWhenItsShown() {
356 function test_touchesReachSurfaceWhenItsShown() {
316 setApplicationState(appRunning);
357 setApplicationState(appRunning);
317− surfaceCheckbox.checked = true;
358+ initSession();
318
359
319 tryCompare(stateGroup, "state", "surface");
360 tryCompare(stateGroup, "state", "surface");
320
361
321 waitUntilTransitionsEnd();
362 waitUntilTransitionsEnd();
322
363
323 // Because doing stuff in C++ is a PITA we keep the counter in the interal qml impl.
364 // Because doing stuff in C++ is a PITA we keep the counter in the interal qml impl.
324− var fakeSurface = findChild(fakeApplication.surface, "fakeSurfaceQML");
365+ var fakeSurface = findChild(fakeSession.surface, "fakeSurfaceQML");
325 fakeSurface.touchPressCount = 0;
366 fakeSurface.touchPressCount = 0;
326 fakeSurface.touchReleaseCount = 0;
367 fakeSurface.touchReleaseCount = 0;
327
368
@@ -333,14 +374,25 @@ Rectangle {
333 }
374 }
334
375
335 function test_showNothingOnSuddenSurfaceLoss() {
376 function test_showNothingOnSuddenSurfaceLoss() {
336− surfaceCheckbox.checked = true;
377+ initSession();
337 setApplicationState(appRunning);
378 setApplicationState(appRunning);
338 tryCompare(stateGroup, "state", "surface");
379 tryCompare(stateGroup, "state", "surface");
339 waitUntilTransitionsEnd();
380 waitUntilTransitionsEnd();
340
381
341− surfaceCheckbox.checked = false;
382+ cleanupSession();
342
383
343 verify(stateGroup.state === "void");
384 verify(stateGroup.state === "void");
344 }
385 }
386+
387+ // should be forcing active focus when interactive changes,
388+ // which will cause a FocusScope higher in the object hierarchy tp be given the focus
389+ function test_forceActiveFocusFollowsInterative() {
390+ fakeApplication.createSession();
391+ applicationWindowLoader.item.interactive = false;
392+ applicationWindowLoader.item.interactive = true;
393+ fakeSession.createSurface();
394+
395+ compare(appFocus.focus, true);
396+ }
345 }
397 }
346}
398}
tests/qmltests/Stages/tst_PhoneStage.qml+1−1
@@ -64,7 +64,7 @@ Item {
64 anchors { left: parent.left; right: parent.right }
64 anchors { left: parent.left; right: parent.right }
65 text: "Stop Selected"
65 text: "Stop Selected"
66 onClicked: {
66 onClicked: {
67− ApplicationManager.get(appList.selectedAppIndex).setState(ApplicationInfo.Stopped);
67+ ApplicationManager.get(appList.selectedAppIndex).setState(ApplicationInfoInterface.Stopped);
68 }
68 }
69 }
69 }
70 }
70 }
tests/qmltests/Stages/tst_SessionContainer.qmlnew file+267
@@ -0,0 +1,267 @@
1+/*
2+ * Copyright 2014 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.1
18+import QtQuick.Layouts 1.1
19+import QtTest 1.0
20+import Unity.Test 0.1 as UT
21+import Ubuntu.Components 0.1
22+import Unity.Application 0.1
23+import "../../../qml/Stages"
24+
25+Rectangle {
26+ color: "red"
27+ id: root
28+ width: units.gu(80)
29+ height: units.gu(70)
30+
31+ Connections {
32+ target: sessionContainerLoader.status === Loader.Ready ? sessionContainerLoader.item : null
33+ onSessionChanged: {
34+ sessionCheckbox.checked = sessionContainerLoader.item.session !== null
35+ }
36+ }
37+
38+ Component {
39+ id: sessionContainerComponent
40+
41+ SessionContainer {
42+ id: sessionContainer
43+ anchors.fill: parent
44+ }
45+ }
46+
47+ Loader {
48+ id: sessionContainerLoader
49+ anchors {
50+ top: parent.top
51+ bottom: parent.bottom
52+ left: parent.left
53+ }
54+ width: units.gu(40)
55+ sourceComponent: sessionContainerComponent
56+ }
57+
58+ Rectangle {
59+ color: "white"
60+ anchors {
61+ top: parent.top
62+ bottom: parent.bottom
63+ left: sessionContainerLoader.right
64+ right: parent.right
65+ }
66+
67+ ColumnLayout {
68+ anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
69+ spacing: units.gu(1)
70+
71+ RowLayout {
72+ Layout.fillWidth: true
73+
74+ CheckBox {
75+ id: sessionCheckbox;
76+ checked: false;
77+ onCheckedChanged: {
78+ if (sessionContainerLoader.status !== Loader.Ready)
79+ return;
80+
81+ if (checked) {
82+ var fakeSession = SessionManager.createSession("music-player", Qt.resolvedUrl("../Dash/artwork/music-player-design.png"));
83+ sessionContainerLoader.item.session = fakeSession;
84+ fakeSession.createSurface();
85+ } else {
86+ sessionContainerLoader.item.session.release();
87+ }
88+ }
89+ }
90+
91+ Label {
92+ text: "session"
93+ anchors.verticalCenter: parent.verticalCenter
94+ }
95+ }
96+
97+ Rectangle {
98+ border {
99+ color: "black"
100+ width: 1
101+ }
102+ anchors {
103+ left: parent.left
104+ right: parent.right
105+ }
106+ Layout.preferredHeight: sessionChildrenControl.height
107+
108+ RecursingChildSessionControl {
109+ id: sessionChildrenControl
110+ anchors { left: parent.left; right: parent.right; }
111+
112+ session: sessionContainerLoader.item ? sessionContainerLoader.item.session : null
113+ }
114+ }
115+ }
116+ }
117+
118+ SignalSpy {
119+ id: sessionSpy
120+ target: SessionManager
121+ signalName: "sessionStopping"
122+ }
123+
124+ UT.UnityTestCase {
125+ id: testCase
126+ name: "SessionContainer"
127+
128+ function init() {
129+ // reload our test subject to get it in a fresh state once again
130+ sessionContainerLoader.active = false;
131+ sessionCheckbox.checked = false;
132+ sessionContainerLoader.active = true;
133+
134+ tryCompare(sessionContainerLoader.item, "session", null);
135+ sessionSpy.clear();
136+ }
137+
138+ when: windowShown
139+
140+ function test_addChildSession_data() {
141+ return [ { tag: "count=1", count: 1 },
142+ { tag: "count=4", count: 4 } ];
143+ }
144+
145+ function test_addChildSession(data) {
146+ sessionCheckbox.checked = true;
147+ var sessionContainer = sessionContainerLoader.item;
148+ compare(sessionContainer.childSessions.count(), 0);
149+
150+ var i;
151+ var sessions = [];
152+ for (i = 0; i < data.count; i++) {
153+ var session = ApplicationTest.addChildSession(sessionContainer.session,
154+ "gallery");
155+ session.createSurface();
156+ sessionContainer.session.addChildSession(session);
157+ compare(sessionContainer.childSessions.count(), i+1);
158+
159+ sessions.push(session);
160+ }
161+
162+ for (i = data.count-1; i >= 0; i--) {
163+ ApplicationTest.removeSession(sessions[i]);
164+ tryCompareFunction(function() { return sessionContainer.childSessions.count(); }, i);
165+ }
166+ tryCompare(sessionSpy, "count", data.count);
167+ }
168+
169+ function test_nestedChildSessions_data() {
170+ return [ { tag: "depth=2", depth: 2 },
171+ { tag: "depth=8", depth: 8 }
172+ ];
173+ }
174+
175+ function test_nestedChildSessions(data) {
176+ sessionCheckbox.checked = true;
177+ var sessionContainer = sessionContainerLoader.item;
178+ compare(sessionContainer.childSessions.count(), 0);
179+
180+ var i;
181+ var sessions = [];
182+ var lastSession = sessionContainer.session;
183+ var delegate;
184+ var container = sessionContainer;
185+ for (i = 0; i < data.depth; i++) {
186+ var session = ApplicationTest.addChildSession(lastSession,
187+ "gallery");
188+ session.createSurface();
189+ lastSession.addChildSession(session);
190+ compare(container.childSessions.count(), 1);
191+ sessions.push(session);
192+
193+ delegate = findChild(container, "childDelegate0");
194+ container = findChild(delegate, "sessionContainer");
195+ lastSession = session;
196+ }
197+
198+ for (i = data.depth-1; i >= 0; i--) {
199+ ApplicationTest.removeSession(sessions[i]);
200+ }
201+
202+ tryCompareFunction(function() { return sessionContainer.childSessions.count(); }, 0);
203+ tryCompare(sessionSpy, "count", data.depth);
204+ }
205+
206+ function test_childrenAdjustForParentSize() {
207+ sessionCheckbox.checked = true;
208+ var sessionContainer = sessionContainerLoader.item;
209+
210+ var session = ApplicationTest.addChildSession(sessionContainer.session,
211+ "gallery");
212+ session.createSurface();
213+ sessionContainer.session.addChildSession(session);
214+
215+ var delegate = findChild(sessionContainer, "childDelegate0");
216+ var childContainer = findChild(delegate, "sessionContainer");
217+
218+ tryCompareFunction(function() { return childContainer.height === sessionContainer.height; }, true);
219+ tryCompareFunction(function() { return childContainer.width === sessionContainer.width; }, true);
220+ tryCompareFunction(function() { return childContainer.x === 0; }, true);
221+ tryCompareFunction(function() { return childContainer.y === 0; }, true);
222+
223+ sessionContainer.anchors.margins = units.gu(2);
224+
225+ tryCompareFunction(function() { return childContainer.height === sessionContainer.height; }, true);
226+ tryCompareFunction(function() { return childContainer.width === sessionContainer.width; }, true);
227+ tryCompareFunction(function() { return childContainer.x === 0; }, true);
228+ tryCompareFunction(function() { return childContainer.y === 0; }, true);
229+ }
230+
231+ function isContainerAnimating(container) {
232+ var animation = findInvisibleChild(container, "sessionAnimation");
233+ if (!animation) return false;
234+
235+ var animating = false;
236+ for (var i = 0; i < animation.transitions.length; ++i) {
237+ if (animation.transitions[i].running) {
238+ return true;
239+ }
240+ }
241+ return false;
242+ }
243+
244+ function test_childrenAnimate() {
245+ sessionCheckbox.checked = true;
246+ var sessionContainer = sessionContainerLoader.item;
247+
248+ var session = ApplicationTest.addChildSession(sessionContainer.session,
249+ "gallery");
250+
251+ var delegate = findChild(sessionContainer, "childDelegate0");
252+ var childContainer = findChild(delegate, "sessionContainer");
253+
254+ // wait for animation to begin
255+ tryCompareFunction(function() { return isContainerAnimating(childContainer); }, true);
256+ // wait for animation to end
257+ tryCompareFunction(function() { return isContainerAnimating(childContainer); }, false);
258+
259+ ApplicationTest.removeSession(session);
260+
261+ // wait for animation to begin
262+ tryCompareFunction(function() { return isContainerAnimating(childContainer); }, true);
263+ // wait for animation to end
264+ tryCompareFunction(function() { return isContainerAnimating(childContainer); }, false);
265+ }
266+ }
267+}
tests/qmltests/Stages/tst_SurfaceContainer.qml+28−43
@@ -28,43 +28,6 @@ Rectangle {
28 width: units.gu(70)
28 width: units.gu(70)
29 height: units.gu(70)
29 height: units.gu(70)
30
30
31− Component {
32− id: fakeSurfaceComponent
33− Rectangle {
34− color: "green"
35−
36− Rectangle {
37− color: "blue"
38− anchors.fill: parent
39− anchors.margins: units.gu(2)
40− Text {
41− anchors.fill: parent
42− text: "Surface"
43− color: "green"
44− font.bold: true
45− fontSizeMode: Text.Fit
46− minimumPixelSize: 10; font.pixelSize: 200
47− verticalAlignment: Text.AlignVCenter
48− }
49− }
50−
51− width: units.gu(1)
52− height: units.gu(1)
53−
54− property int type: MirSurfaceItem.Normal
55− property int state: MirSurfaceItem.Restored
56− property string name: "Fake Surface"
57− property Item parentSurface: null
58− property list<Item> childSurfaces
59− function release() {}
60− signal removed();
61− }
62− }
63−
64− Item {
65− id: tempSurfaceHolder
66− }
67−
68 Component {
31 Component {
69 id: surfaceContainerComponent
32 id: surfaceContainerComponent
70 SurfaceContainer {
33 SurfaceContainer {
@@ -98,19 +61,20 @@ Rectangle {
98 Row {
61 Row {
99 anchors { left: parent.left; right: parent.right }
62 anchors { left: parent.left; right: parent.right }
100 CheckBox {
63 CheckBox {
101− id: surfaceCheckbox; checked: false;
64+ id: surfaceCheckbox;
65+ checked: false;
102 onCheckedChanged: {
66 onCheckedChanged: {
103 if (surfaceContainerLoader.status !== Loader.Ready)
67 if (surfaceContainerLoader.status !== Loader.Ready)
104 return;
68 return;
105
69
106 if (checked) {
70 if (checked) {
107− var fakeSurface = fakeSurfaceComponent.createObject(tempSurfaceHolder);
71+ var fakeSurface = SurfaceManager.createSurface("fake-surface",
72+ MirSurfaceItem.Normal,
73+ MirSurfaceItem.Restored,
74+ Qt.resolvedUrl("../Dash/artwork/music-player-design.png"));
108 surfaceContainerLoader.item.surface = fakeSurface;
75 surfaceContainerLoader.item.surface = fakeSurface;
109 } else {
76 } else {
110− var fakeSurface = surfaceContainerLoader.item.surface;
77+ ApplicationTest.removeSurface(surfaceContainerLoader.item.surface);
111− surfaceContainerLoader.item.surface = null;
112− fakeSurface.parent = null;
113− fakeSurface.destroy();
114 }
78 }
115 }
79 }
116 }
80 }
@@ -124,6 +88,12 @@ Rectangle {
124 }
88 }
125 }
89 }
126
90
91+ SignalSpy {
92+ id: surfaceSpy
93+ target: SurfaceManager
94+ signalName: "surfaceDestroyed"
95+ }
96+
127 UT.UnityTestCase {
97 UT.UnityTestCase {
128 id: testCase
98 id: testCase
129 name: "SurfaceContainer"
99 name: "SurfaceContainer"
@@ -134,6 +104,9 @@ Rectangle {
134 surfaceContainerLoader.active = false;
104 surfaceContainerLoader.active = false;
135 surfaceCheckbox.checked = false;
105 surfaceCheckbox.checked = false;
136 surfaceContainerLoader.active = true;
106 surfaceContainerLoader.active = true;
107+
108+ tryCompare(surfaceContainerLoader.item, "surface", null);
109+ surfaceSpy.clear();
137 }
110 }
138
111
139 /*
112 /*
@@ -150,5 +123,17 @@ Rectangle {
150 compare(fakeSurface.width, surfaceContainerLoader.item.width);
123 compare(fakeSurface.width, surfaceContainerLoader.item.width);
151 compare(fakeSurface.height, surfaceContainerLoader.item.height);
124 compare(fakeSurface.height, surfaceContainerLoader.item.height);
152 }
125 }
126+
127+ function test_animateRemoval() {
128+ surfaceCheckbox.checked = true;
129+ var surfaceContainer = surfaceContainerLoader.item;
130+
131+ verify(surfaceContainer.surface !== null);
132+
133+ ApplicationTest.removeSurface(surfaceContainer.surface);
134+
135+ compare(surfaceContainer.state, "zombie");
136+ tryCompare(surfaceContainer, "surface", null);
137+ }
153 }
138 }
154}
139}
tests/qmltests/tst_Shell.qml+23−16
@@ -21,6 +21,7 @@ import QtQuick 2.0
21import QtTest 1.0
21import QtTest 1.0
22import GSettings 1.0
22import GSettings 1.0
23import LightDM 0.1 as LightDM
23import LightDM 0.1 as LightDM
24+import Ubuntu.Telephony 0.1 as Telephony
24import Unity.Application 0.1
25import Unity.Application 0.1
25import Unity.Connectivity 0.1
26import Unity.Connectivity 0.1
26import Unity.Test 0.1 as UT
27import Unity.Test 0.1 as UT
@@ -74,6 +75,11 @@ Item {
74 signalName: "unlockingAllModems"
75 signalName: "unlockingAllModems"
75 }
76 }
76
77
78+ Telephony.CallEntry {
79+ id: phoneCall
80+ phoneNumber: "+447812221111"
81+ }
82+
77 UT.UnityTestCase {
83 UT.UnityTestCase {
78 name: "Shell"
84 name: "Shell"
79 when: windowShown
85 when: windowShown
@@ -151,29 +157,30 @@ Item {
151 verify(mainAppId != "");
157 verify(mainAppId != "");
152 var mainApp = ApplicationManager.findApplication(mainAppId);
158 var mainApp = ApplicationManager.findApplication(mainAppId);
153 verify(mainApp);
159 verify(mainApp);
154− tryCompare(mainApp, "state", ApplicationInfo.Running);
160+ tryCompare(mainApp, "state", ApplicationInfoInterface.Running);
155
161
156− // Try to suspend while proximity is engaged...
162+ // Suspend while call is active...
163+ callManager.foregroundCall = phoneCall;
157− Powerd.displayPowerStateChange(Powerd.Off, Powerd.Proximity);
164+ Powerd.status = Powerd.Off;
158 tryCompare(greeter, "showProgress", 0);
165 tryCompare(greeter, "showProgress", 0);
159
166
160− // Now really suspend
167+ // Now try again after ending call
161− print("suspending")
168+ callManager.foregroundCall = null;
169+ Powerd.status = Powerd.On;
162− Powerd.displayPowerStateChange(Powerd.Off, 0);
170+ Powerd.status = Powerd.Off;
163− print("done suspending")
164 tryCompare(greeter, "showProgress", 1);
171 tryCompare(greeter, "showProgress", 1);
165
172
166 tryCompare(ApplicationManager, "suspended", true);
173 tryCompare(ApplicationManager, "suspended", true);
167− compare(mainApp.state, ApplicationInfo.Suspended);
174+ compare(mainApp.state, ApplicationInfoInterface.Suspended);
168
175
169 // And wake up
176 // And wake up
170− Powerd.displayPowerStateChange(Powerd.On, 0);
177+ Powerd.status = Powerd.On;
171 tryCompare(greeter, "showProgress", 1);
178 tryCompare(greeter, "showProgress", 1);
172
179
173 // Swipe away greeter to focus app
180 // Swipe away greeter to focus app
174 swipeAwayGreeter();
181 swipeAwayGreeter();
175 tryCompare(ApplicationManager, "suspended", false);
182 tryCompare(ApplicationManager, "suspended", false);
176− compare(mainApp.state, ApplicationInfo.Running);
183+ compare(mainApp.state, ApplicationInfoInterface.Running);
177 tryCompare(ApplicationManager, "focusedApplicationId", mainAppId);
184 tryCompare(ApplicationManager, "focusedApplicationId", mainAppId);
178 }
185 }
179
186
@@ -244,9 +251,9 @@ Item {
244 function test_surfaceLosesFocusWhilePanelIsOpen() {
251 function test_surfaceLosesFocusWhilePanelIsOpen() {
245 var app = ApplicationManager.startApplication("dialer-app");
252 var app = ApplicationManager.startApplication("dialer-app");
246 // wait until the app is fully loaded (ie, real surface replaces splash screen)
253 // wait until the app is fully loaded (ie, real surface replaces splash screen)
247− tryCompareFunction(function() { return app.surface != null }, true);
254+ tryCompareFunction(function() { return app.session !== null && app.session.surface !== null }, true);
248
255
249− tryCompare(app.surface, "focus", true);
256+ tryCompare(app.session.surface, "focus", true);
250
257
251 // Drag the indicators panel half-open
258 // Drag the indicators panel half-open
252 var touchX = shell.width / 2;
259 var touchX = shell.width / 2;
@@ -257,7 +264,7 @@ Item {
257 true /* beginTouch */, false /* endTouch */);
264 true /* beginTouch */, false /* endTouch */);
258 verify(indicators.partiallyOpened);
265 verify(indicators.partiallyOpened);
259
266
260− tryCompare(app.surface, "focus", false);
267+ tryCompare(app.session.surface, "focus", false);
261
268
262 // And finish getting it open
269 // And finish getting it open
263 touchFlick(indicators,
270 touchFlick(indicators,
@@ -266,11 +273,11 @@ Item {
266 false /* beginTouch */, true /* endTouch */);
273 false /* beginTouch */, true /* endTouch */);
267 tryCompare(indicators, "fullyOpened", true);
274 tryCompare(indicators, "fullyOpened", true);
268
275
269− tryCompare(app.surface, "focus", false);
276+ tryCompare(app.session.surface, "focus", false);
270
277
271 dragToCloseIndicatorsPanel();
278 dragToCloseIndicatorsPanel();
272
279
273− tryCompare(app.surface, "focus", true);
280+ tryCompare(app.session.surface, "focus", true);
274 }
281 }
275
282
276 // Wait for the whole UI to settle down
283 // Wait for the whole UI to settle down
@@ -368,7 +375,7 @@ Item {
368
375
369 var app = ApplicationManager.startApplication("dialer-app");
376 var app = ApplicationManager.startApplication("dialer-app");
370 // wait until the app is fully loaded (ie, real surface replaces splash screen)
377 // wait until the app is fully loaded (ie, real surface replaces splash screen)
371− tryCompareFunction(function() { return app.surface != null }, true);
378+ tryCompareFunction(function() { return app.session !== null && app.session.surface !== null }, true);
372
379
373 // Minimize the application we just launched
380 // Minimize the application we just launched
374 swipeFromLeftEdge(units.gu(26) + 1);
381 swipeFromLeftEdge(units.gu(26) + 1);
tools/unlock-device+4−5
@@ -19,13 +19,12 @@ done
19
19
20eval "$WAIT_COMMAND"
20eval "$WAIT_COMMAND"
21
21
22−# Force a sleep of twenty no matter what, since we may need to wait for unity8
22+# Force a sleep no matter what, since we may need to wait for unity8
23# to finish coming up (it's hard to tell when the greeter is actually rendered)
23# to finish coming up (it's hard to tell when the greeter is actually rendered)
24−sleep 20
24+sleep 30
25
25
26+# We need to go through sudo to get a proper environment for dbus set up
26−GDBUS_CMD="gdbus call --session --dest com.canonical.UnityGreeter --object-path / --method com.canonical.UnityGreeter.HideGreeter && echo Greeter unlocked"
27+UNLOCK_OUTPUT=$(adb shell "gdbus call --session --dest com.canonical.UnityGreeter --object-path / --method com.canonical.UnityGreeter.HideGreeter && echo Greeter unlocked" 2>&1)
27−
28−UNLOCK_OUTPUT=$(adb shell "if [ \"\$(id -u)\" = 0 ]; then sudo -u phablet -i $GDBUS_CMD; else $GDBUS_CMD; fi" 2>&1)
29if echo "$UNLOCK_OUTPUT" | grep 'Greeter unlocked' >/dev/null; then
28if echo "$UNLOCK_OUTPUT" | grep 'Greeter unlocked' >/dev/null; then
30 echo "I: Unlock passed"
29 echo "I: Unlock passed"
31 exit 0
30 exit 0