on xenial help sign in
Merge trunk
2133ddeGerry Boland
debian/changelog+55
@@ -1,3 +1,58 @@
1+unity8 (7.89+14.10.20140627-0ubuntu1) utopic; urgency=low
2+
3+ [ Michael Terry ]
4+ * Fix path in launcher mock after moving our mock icons, to avoid a
5+ lot of "icon not found" warnings during qmluitests.
6+ * Fix the testMultiGreeter qmluitest. Incoming method variables are
7+ apparently read-only in Qt5.3. (LP: #1332488)
8+
9+ [ CI bot ]
10+ * Resync trunk
11+
12+ [ Michał Sawicz ]
13+ * Adapt scope mock to new api and quiet unused variable warnings.
14+ * Fix dynamic overlay height. (LP: #1334879)
15+ * Don't center items in CardVerticalJournal, kind of beats the
16+ purpose... Also don't bind unnecessarily.
17+
18+ [ Ying-Chun Liu ]
19+ * Fix LP:1330957 Fix some failed test cases. (LP: #1330957)
20+
21+ [ Albert Astals ]
22+ * Don't seem to need this waitForRendering And makes test fail in 5.3
23+
24+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Fri, 27 Jun 2014 08:47:58 +0000
25+
26+unity8 (7.89+14.10.20140624.1-0ubuntu1) utopic; urgency=low
27+
28+ [ Alberto Aguirre ]
29+ * Update Powerd plugin and Shell.qml to accommodate changes in the
30+ display power state notification.
31+
32+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 24 Jun 2014 17:11:08 +0000
33+
34+unity8 (7.89+14.10.20140624-0ubuntu1) utopic; urgency=low
35+
36+ [ Ying-Chun Liu ]
37+ * Add logout support. Reviewed by: Daniel d'Andrada (LP: #1302213)
38+
39+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 24 Jun 2014 08:17:09 +0000
40+
41+unity8 (7.89+14.10.20140623.1-0ubuntu1) utopic; urgency=low
42+
43+ [ Michał Sawicz ]
44+ * Make so that fixedArtShapeSize actually fixes artShapeSize.
45+
46+ [ Albert Astals ]
47+ * Add VerticalJournal integration to Dash/scopes/QML (LP: #1326467)
48+ * Make so that fixedArtShapeSize actually fixes artShapeSize.
49+
50+ [ Mirco Müller ]
51+ * Added the frontend-part of sound-hint support for notifications with
52+ updated QML-tests.
53+
54+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 23 Jun 2014 11:17:12 +0000
55+
1unity8 (7.89+14.10.20140619.3-0ubuntu1) utopic; urgency=low
56unity8 (7.89+14.10.20140619.3-0ubuntu1) utopic; urgency=low
2
57
3 * New rebuild forced
58 * New rebuild forced
debian/control+1−1
@@ -17,7 +17,7 @@ Build-Depends: cmake,
17 libpulse-dev,
17 libpulse-dev,
18 libqmenumodel-dev (>= 0.2.7),
18 libqmenumodel-dev (>= 0.2.7),
19 libqt5xmlpatterns5-dev,
19 libqt5xmlpatterns5-dev,
20− libunity-api-dev (>= 7.82),
20+ libunity-api-dev (>= 7.83),
21 libusermetricsoutput1-dev,
21 libusermetricsoutput1-dev,
22 libxcb1-dev,
22 libxcb1-dev,
23 pkg-config,
23 pkg-config,
plugins/Dash/CardCreator.js+24−14
@@ -55,8 +55,8 @@ var kBackgroundLoaderCode = 'Loader {\n\
55// %3 is used as image height
55// %3 is used as image height
56var kArtShapeHolderCode = 'Item { \n\
56var kArtShapeHolderCode = 'Item { \n\
57 id: artShapeHolder; \n\
57 id: artShapeHolder; \n\
58− height: root.fixedArtShapeSize.height != -1 ? root.fixedArtShapeSize.height : artShapeLoader.height; \n\
58+ height: root.fixedArtShapeSize.height > 0 ? root.fixedArtShapeSize.height : artShapeLoader.height; \n\
59− width: root.fixedArtShapeSize.width != -1 ? root.fixedArtShapeSize.width : artShapeLoader.width; \n\
59+ width: root.fixedArtShapeSize.width > 0 ? root.fixedArtShapeSize.width : artShapeLoader.width; \n\
60 anchors { %1 } \n\
60 anchors { %1 } \n\
61 Loader { \n\
61 Loader { \n\
62 id: artShapeLoader; \n\
62 id: artShapeLoader; \n\
@@ -68,13 +68,18 @@ var kArtShapeHolderCode = 'Item { \n\
68 id: artShape; \n\
68 id: artShape; \n\
69 objectName: "artShape"; \n\
69 objectName: "artShape"; \n\
70 radius: "medium"; \n\
70 radius: "medium"; \n\
71+ visible: image.status == Image.Ready; \n\
72+ readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1; \n\
71− readonly property real aspect: components !== undefined ? components["art"]["aspect-ratio"] : 1; \n\
73+ readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1; \n\
72 readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect; \n\
74 readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect; \n\
73 Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; } \n\
75 Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; } \n\
74 onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings(); \n\
76 onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings(); \n\
75− visible: image.status == Image.Ready; \n\
77+ Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); } \n\
76 function updateWidthHeightBindings() { \n\
78 function updateWidthHeightBindings() { \n\
79+ if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) { \n\
80+ width = root.fixedArtShapeSize.width; \n\
81+ height = root.fixedArtShapeSize.height; \n\
77− if (aspectSmallerThanImageAspect) { \n\
82+ } else if (aspectSmallerThanImageAspect) { \n\
78 width = Qt.binding(function() { return !visible ? 0 : image.width }); \n\
83 width = Qt.binding(function() { return !visible ? 0 : image.width }); \n\
79 height = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.height : width / image.aspect }); \n\
84 height = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.height : width / image.aspect }); \n\
80 } else { \n\
85 } else { \n\
@@ -108,7 +113,7 @@ var kOverlayLoaderCode = 'Loader { \n\
108 visible: showHeader && status == Loader.Ready; \n\
113 visible: showHeader && status == Loader.Ready; \n\
109 sourceComponent: ShaderEffect { \n\
114 sourceComponent: ShaderEffect { \n\
110 id: overlay; \n\
115 id: overlay; \n\
111− height: fixedHeaderHeight != -1 ? fixedHeaderHeight : headerHeight; \n\
116+ height: (fixedHeaderHeight > 0 ? fixedHeaderHeight : headerHeight) + units.gu(2); \n\
112 opacity: 0.6; \n\
117 opacity: 0.6; \n\
113 property var source: ShaderEffectSource { \n\
118 property var source: ShaderEffectSource { \n\
114 id: shaderSource; \n\
119 id: shaderSource; \n\
@@ -145,6 +150,7 @@ var kHeaderRow2Code = 'Row { \n\
145 objectName: "outerRow"; \n\
150 objectName: "outerRow"; \n\
146 property real margins: units.gu(1); \n\
151 property real margins: units.gu(1); \n\
147 spacing: margins; \n\
152 spacing: margins; \n\
153+ height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight; \n\
148 anchors { %1 } \n\
154 anchors { %1 } \n\
149 anchors.right: parent.right; \n\
155 anchors.right: parent.right; \n\
150 anchors.margins: margins;\n\
156 anchors.margins: margins;\n\
@@ -163,6 +169,7 @@ var kHeaderRow3Code = 'Row { \n\
163 objectName: "outerRow"; \n\
169 objectName: "outerRow"; \n\
164 property real margins: units.gu(1); \n\
170 property real margins: units.gu(1); \n\
165 spacing: margins; \n\
171 spacing: margins; \n\
172+ height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight; \n\
166 anchors { %1 } \n\
173 anchors { %1 } \n\
167 anchors.right: parent.right; \n\
174 anchors.right: parent.right; \n\
168 anchors.margins: margins;\n\
175 anchors.margins: margins;\n\
@@ -315,7 +322,7 @@ function cardString(template, components) {
315 anchors = 'left: parent.left';
322 anchors = 'left: parent.left';
316 if (hasMascot || hasTitle) {
323 if (hasMascot || hasTitle) {
317 widthCode = 'height * artShape.aspect'
324 widthCode = 'height * artShape.aspect'
318− heightCode = 'headerHeight';
325+ heightCode = 'headerHeight + 2 * units.gu(1)';
319 } else {
326 } else {
320 // This side of the else is a bit silly, who wants an horizontal layout without mascot and title?
327 // This side of the else is a bit silly, who wants an horizontal layout without mascot and title?
321 // So we define a "random" height of the image height + 2 gu for the margins
328 // So we define a "random" height of the image height + 2 gu for the margins
@@ -356,23 +363,23 @@ function cardString(template, components) {
356 }
363 }
357 }
364 }
358 var headerLeftAnchor;
365 var headerLeftAnchor;
359− var headerLeftAnchorHasMagin = false;
366+ var headerLeftAnchorHasMargin = false;
360 if (isHorizontal && hasArt) {
367 if (isHorizontal && hasArt) {
361 headerLeftAnchor = 'left: artShapeHolder.right; \n\
368 headerLeftAnchor = 'left: artShapeHolder.right; \n\
362 leftMargin: units.gu(1);\n';
369 leftMargin: units.gu(1);\n';
363− headerLeftAnchorHasMagin = true;
370+ headerLeftAnchorHasMargin = true;
364 } else {
371 } else {
365 headerLeftAnchor = 'left: parent.left;\n';
372 headerLeftAnchor = 'left: parent.left;\n';
366 }
373 }
367
374
368 if (hasHeaderRow) {
375 if (hasHeaderRow) {
369− code += 'readonly property int headerHeight: row.height + row.margins * 2;\n'
376+ code += 'readonly property int headerHeight: row.height;\n'
370 } else if (hasMascot) {
377 } else if (hasMascot) {
371− code += 'readonly property int headerHeight: mascotImage.height + units.gu(1) * 2;\n'
378+ code += 'readonly property int headerHeight: mascotImage.height;\n'
372 } else if (hasSubtitle) {
379 } else if (hasSubtitle) {
373− code += 'readonly property int headerHeight: titleLabel.height + titleLabel.anchors.topMargin * 2 + subtitleLabel.height + subtitleLabel.anchors.topMargin;\n'
380+ code += 'readonly property int headerHeight: titleLabel.height + subtitleLabel.height + subtitleLabel.anchors.topMargin;\n'
374 } else if (hasTitle) {
381 } else if (hasTitle) {
375− code += 'readonly property int headerHeight: titleLabel.height + titleLabel.anchors.topMargin * 2;\n'
382+ code += 'readonly property int headerHeight: titleLabel.height;\n'
376 } else {
383 } else {
377 code += 'readonly property int headerHeight: 0;\n'
384 code += 'readonly property int headerHeight: 0;\n'
378 }
385 }
@@ -385,7 +392,7 @@ function cardString(template, components) {
385 if (!hasHeaderRow) {
392 if (!hasHeaderRow) {
386 anchors += headerLeftAnchor;
393 anchors += headerLeftAnchor;
387 anchors += headerVerticalAnchors;
394 anchors += headerVerticalAnchors;
388− if (!headerLeftAnchorHasMagin) {
395+ if (!headerLeftAnchorHasMargin) {
389 anchors += 'leftMargin: units.gu(1);\n'
396 anchors += 'leftMargin: units.gu(1);\n'
390 }
397 }
391 } else {
398 } else {
@@ -437,6 +444,9 @@ function cardString(template, components) {
437 titleAnchors = "right: parent.right;";
444 titleAnchors = "right: parent.right;";
438 titleAnchors += headerLeftAnchor;
445 titleAnchors += headerLeftAnchor;
439 titleAnchors += headerVerticalAnchors;
446 titleAnchors += headerVerticalAnchors;
447+ if (!headerLeftAnchorHasMargin) {
448+ titleAnchors += 'leftMargin: units.gu(1);\n'
449+ }
440 }
450 }
441 subtitleAnchors = 'left: titleLabel.left; \n\
451 subtitleAnchors = 'left: titleLabel.left; \n\
442 leftMargin: titleLabel.leftMargin; \n\
452 leftMargin: titleLabel.leftMargin; \n\
plugins/Powerd/Powerd.cpp+16−16
@@ -19,35 +19,35 @@
19#include "Powerd.h"
19#include "Powerd.h"
20#include <QDBusPendingCall>
20#include <QDBusPendingCall>
21
21
22−void autoBrightnessChanged(GSettings *settings, const gchar *key, QDBusInterface *powerd)
22+void autoBrightnessChanged(GSettings *settings, const gchar *key, QDBusInterface *unityScreen)
23{
23{
24 bool value = g_settings_get_boolean(settings, key);
24 bool value = g_settings_get_boolean(settings, key);
25− powerd->asyncCall("userAutobrightnessEnable", QVariant(value));
25+ unityScreen->asyncCall("userAutobrightnessEnable", QVariant(value));
26}
26}
27
27
28Powerd::Powerd(QObject* parent)
28Powerd::Powerd(QObject* parent)
29 : QObject(parent),
29 : QObject(parent),
30− powerd(NULL)
30+ unityScreen(NULL)
31{
31{
32− powerd = new QDBusInterface("com.canonical.powerd",
32+ unityScreen = new QDBusInterface("com.canonical.Unity.Screen",
33− "/com/canonical/powerd",
33+ "/com/canonical/Unity/Screen",
34− "com.canonical.powerd",
34+ "com.canonical.Unity.Screen",
35− QDBusConnection::SM_BUSNAME(), this);
35+ QDBusConnection::SM_BUSNAME(), this);
36
36
37− powerd->connection().connect("com.canonical.powerd",
37+ unityScreen->connection().connect("com.canonical.Unity.Screen",
38− "/com/canonical/powerd",
38+ "/com/canonical/Unity/Screen",
39− "com.canonical.powerd",
39+ "com.canonical.Unity.Screen",
40− "DisplayPowerStateChange",
40+ "DisplayPowerStateChange",
41− this,
41+ this,
42− SIGNAL(displayPowerStateChange(int, unsigned int)));
42+ SIGNAL(displayPowerStateChange(int, int)));
43
43
44 systemSettings = g_settings_new("com.ubuntu.touch.system");
44 systemSettings = g_settings_new("com.ubuntu.touch.system");
45− g_signal_connect(systemSettings, "changed::auto-brightness", G_CALLBACK(autoBrightnessChanged), powerd);
45+ g_signal_connect(systemSettings, "changed::auto-brightness", G_CALLBACK(autoBrightnessChanged), unityScreen);
46− autoBrightnessChanged(systemSettings, "auto-brightness", powerd);
46+ autoBrightnessChanged(systemSettings, "auto-brightness", unityScreen);
47}
47}
48
48
49Powerd::~Powerd()
49Powerd::~Powerd()
50{
50{
51− g_signal_handlers_disconnect_by_data(systemSettings, powerd);
51+ g_signal_handlers_disconnect_by_data(systemSettings, unityScreen);
52 g_object_unref(systemSettings);
52 g_object_unref(systemSettings);
53}
53}
plugins/Powerd/Powerd.h+8−8
@@ -28,15 +28,15 @@ class Powerd: public QObject
28{
28{
29 Q_OBJECT
29 Q_OBJECT
30 Q_ENUMS(Status)
30 Q_ENUMS(Status)
31− Q_FLAGS(DisplayFlag DisplayFlags)
31+ Q_ENUMS(DisplayStateChangeReason)
32
32
33public:
33public:
34− enum DisplayFlag {
34+ enum DisplayStateChangeReason {
35− UseProximity = 1, // Use proximity sensor to override screen state
35+ Unknown = 0,
36− DisableAutoBrightness = 2, // Force autobrightness to be disabled
36+ Inactivity = 1, // Display changed state due to inactivity
37− Bright = 4, // Request the screen to stay bright
37+ PowerKey = 2, // Display changed state due to user pressing power key
38+ Proximity = 3, // Display changed state due to proximity events
38 };
39 };
39− Q_DECLARE_FLAGS(DisplayFlags, DisplayFlag)
40
40
41 enum Status {
41 enum Status {
42 Off,
42 Off,
@@ -47,10 +47,10 @@ public:
47 ~Powerd();
47 ~Powerd();
48
48
49Q_SIGNALS:
49Q_SIGNALS:
50− void displayPowerStateChange(int status, unsigned int flags);
50+ void displayPowerStateChange(int status, int reason);
51
51
52private:
52private:
53− QDBusInterface *powerd;
53+ QDBusInterface *unityScreen;
54 GSettings *systemSettings;
54 GSettings *systemSettings;
55};
55};
56
56
plugins/Unity/CMakeLists.txt+1
@@ -1,3 +1,4 @@
1add_subdirectory(Indicators)
1add_subdirectory(Indicators)
2add_subdirectory(Launcher)
2add_subdirectory(Launcher)
3+add_subdirectory(Session)
3add_subdirectory(Shell)
4add_subdirectory(Shell)
plugins/Unity/Session/CMakeLists.txtnew file+17
@@ -0,0 +1,17 @@
1+include_directories(
2+ ${CMAKE_CURRENT_SOURCE_DIR}
3+)
4+
5+set(QMLSESSIONPLUGIN_SRC
6+ plugin.cpp
7+ dbusunitysessionservice.cpp
8+ )
9+
10+add_library(UnitySession-qml MODULE
11+ ${QMLSESSIONPLUGIN_SRC}
12+ )
13+
14+qt5_use_modules(UnitySession-qml DBus Qml)
15+
16+# export the qmldir and qmltypes files
17+add_unity8_plugin(Unity.Session 0.1 Unity/Session TARGETS UnitySession-qml)
plugins/Unity/Session/dbusunitysessionservice.cppnew file+46
@@ -0,0 +1,46 @@
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+// local
18+#include "dbusunitysessionservice.h"
19+
20+// Qt
21+#include <QDBusConnection>
22+
23+DBusUnitySessionService::DBusUnitySessionService() : QObject()
24+{
25+ QDBusConnection connection = QDBusConnection::sessionBus();
26+
27+ connection.registerService("com.canonical.Unity");
28+ connection.registerObject("/com/canonical/Unity/Session", this,
29+ QDBusConnection::ExportScriptableSignals
30+ | QDBusConnection::ExportScriptableSlots
31+ | QDBusConnection::ExportScriptableInvokables);
32+}
33+
34+DBusUnitySessionService::~DBusUnitySessionService()
35+{
36+}
37+
38+void DBusUnitySessionService::Logout()
39+{
40+ Q_EMIT logoutReady();
41+}
42+
43+void DBusUnitySessionService::RequestLogout()
44+{
45+ Q_EMIT logoutRequested(false);
46+}
plugins/Unity/Session/dbusunitysessionservice.hnew file+82
@@ -0,0 +1,82 @@
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 DBUSUNITYSESSIONSERVICE_H
18+#define DBUSUNITYSESSIONSERVICE_H
19+
20+#include <QObject>
21+
22+/**
23+ * DBusUnitySessionService provides com.canonical.Unity.Session dbus
24+ * interface.
25+ *
26+ * com.canonical.Unity.Session interface provides public methods
27+ * and signals to handle Logout/Reboot/Shutdown.
28+ */
29+class DBusUnitySessionService : public QObject
30+{
31+ Q_OBJECT
32+ Q_CLASSINFO("D-Bus Interface", "com.canonical.Unity.Session")
33+
34+public:
35+ DBusUnitySessionService();
36+ ~DBusUnitySessionService();
37+
38+Q_SIGNALS:
39+ /**
40+ * logoutRequested signal
41+ *
42+ * This signal is emitted when some applications request the system to
43+ * logout.
44+ * @param have_inhibitors if there are any special running applications
45+ * which inhibit the logout.
46+ */
47+ void logoutRequested(bool have_inhibitors);
48+
49+ /**
50+ * logoutReady signal
51+ *
52+ * This signal is emitted when all the apps are closed. And the system
53+ * is safe to logout.
54+ */
55+ void logoutReady();
56+
57+public Q_SLOTS:
58+ /**
59+ * Logout the system.
60+ *
61+ * This method directly logout the system without user's confirmation.
62+ * Ordinary applications should avoid calling this method. Please call
63+ * RequestLogout() to ask the user to decide logout or not.
64+ * This method will stop all the running applications and then signal
65+ * logoutReady when all the apps stopped.
66+ */
67+ Q_SCRIPTABLE void Logout();
68+
69+ /**
70+ * Issue a logout request.
71+ *
72+ * This method emit the logoutRequested signal to the shell with a boolean
73+ * which indicates if there's any inhibitors. The shell should receive
74+ * this signal and display a dialog to ask the user to confirm the logout
75+ * action. If confirmed, shell can call Logout() method to kill the apps
76+ * and then logout
77+ */
78+ Q_SCRIPTABLE void RequestLogout();
79+
80+};
81+
82+#endif // DBUSUNITYSESSIONSERVICE_H
plugins/Unity/Session/plugin.cppnew file+40
@@ -0,0 +1,40 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Ying-Chun Liu (PaulLiu) <paul.liu@canonical.com>
17+ */
18+
19+#include "plugin.h"
20+#include "dbusunitysessionservice.h"
21+
22+#include <QAbstractItemModel>
23+#include <QDBusConnection>
24+#include <QtQml/qqml.h>
25+
26+static QObject *dbusunitysessionservice_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
27+{
28+ Q_UNUSED(engine)
29+ Q_UNUSED(scriptEngine)
30+
31+ return new DBusUnitySessionService();
32+}
33+
34+void SessionPlugin::registerTypes(const char *uri)
35+{
36+ qmlRegisterType<QAbstractItemModel>();
37+
38+ Q_ASSERT(uri == QLatin1String("Unity.Session"));
39+ qmlRegisterSingletonType<DBusUnitySessionService>(uri, 0, 1, "DBusUnitySessionService", dbusunitysessionservice_provider);
40+}
plugins/Unity/Session/plugin.hnew file+34
@@ -0,0 +1,34 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Ying-Chun Liu (PaulLiu) <paul.liu@canonical.com>
17+ */
18+
19+#ifndef SESSION_PLUGIN_H
20+#define SESSION_PLUGIN_H
21+
22+#include <QtQml/QQmlEngine>
23+#include <QtQml/QQmlExtensionPlugin>
24+
25+class SessionPlugin : public QQmlExtensionPlugin
26+{
27+ Q_OBJECT
28+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
29+
30+public:
31+ void registerTypes(const char *uri);
32+};
33+
34+#endif
plugins/Unity/Session/qmldirnew file+3
@@ -0,0 +1,3 @@
1+module Unity.Session
2+plugin UnitySession-qml
3+typeinfo UnitySession.qmltypes
po/es.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-06-13 09:55+0200\n"
10"POT-Creation-Date: 2014-06-13 09:55+0200\n"
11−"PO-Revision-Date: 2014-06-02 06:28+0000\n"
11+"PO-Revision-Date: 2014-06-26 03:08+0000\n"
12−"Last-Translator: benjisp94 <benjisp94@gmail.com>\n"
12+"Last-Translator: Adolfo Jayme <fitoschido@gmail.com>\n"
13"Language-Team: Spanish <es@li.org>\n"
13"Language-Team: Spanish <es@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-06-17 06:51+0000\n"
17+"X-Launchpad-Export-Date: 2014-06-27 07:13+0000\n"
18−"X-Generator: Launchpad (build 17045)\n"
18+"X-Generator: Launchpad (build 17077)\n"
19
19
20#: plugins/Unity/Launcher/launcheritem.cpp:43
20#: plugins/Unity/Launcher/launcheritem.cpp:43
21#: plugins/Unity/Launcher/launcheritem.cpp:73
21#: plugins/Unity/Launcher/launcheritem.cpp:73
@@ -83,7 +83,7 @@ msgstr "Llamada de emergencia"
83
83
84#: qml/Components/Lockscreen.qml:231
84#: qml/Components/Lockscreen.qml:231
85msgid "OK"
85msgid "OK"
86−msgstr ""
86+msgstr "Aceptar"
87
87
88#: qml/Components/PageHeader.qml:365
88#: qml/Components/PageHeader.qml:365
89msgid "Recent searches"
89msgid "Recent searches"
@@ -100,11 +100,11 @@ msgstr "Hola"
100
100
101#: qml/Components/PinLockscreen.qml:198
101#: qml/Components/PinLockscreen.qml:198
102msgid "CANCEL"
102msgid "CANCEL"
103−msgstr ""
103+msgstr "CANCELAR"
104
104
105#: qml/Components/PinLockscreen.qml:216
105#: qml/Components/PinLockscreen.qml:216
106msgid "DONE"
106msgid "DONE"
107−msgstr ""
107+msgstr "HECHO"
108
108
109#: qml/Components/SeeMore.qml:35
109#: qml/Components/SeeMore.qml:35
110msgid "See more"
110msgid "See more"
po/sl.po+6−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-06-13 09:55+0200\n"
10"POT-Creation-Date: 2014-06-13 09:55+0200\n"
11−"PO-Revision-Date: 2014-05-22 14:07+0000\n"
11+"PO-Revision-Date: 2014-06-23 09:29+0000\n"
12"Last-Translator: Damir Jerovšek <Unknown>\n"
12"Last-Translator: Damir Jerovšek <Unknown>\n"
13"Language-Team: Slovenian <sl@li.org>\n"
13"Language-Team: Slovenian <sl@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-06-17 06:51+0000\n"
17+"X-Launchpad-Export-Date: 2014-06-24 06:33+0000\n"
18−"X-Generator: Launchpad (build 17045)\n"
18+"X-Generator: Launchpad (build 17065)\n"
19
19
20#: plugins/Unity/Launcher/launcheritem.cpp:43
20#: plugins/Unity/Launcher/launcheritem.cpp:43
21#: plugins/Unity/Launcher/launcheritem.cpp:73
21#: plugins/Unity/Launcher/launcheritem.cpp:73
@@ -82,7 +82,7 @@ msgstr "Klic v sili"
82
82
83#: qml/Components/Lockscreen.qml:231
83#: qml/Components/Lockscreen.qml:231
84msgid "OK"
84msgid "OK"
85−msgstr ""
85+msgstr "V REDU"
86
86
87#: qml/Components/PageHeader.qml:365
87#: qml/Components/PageHeader.qml:365
88msgid "Recent searches"
88msgid "Recent searches"
@@ -99,11 +99,11 @@ msgstr "Pozdravljeni"
99
99
100#: qml/Components/PinLockscreen.qml:198
100#: qml/Components/PinLockscreen.qml:198
101msgid "CANCEL"
101msgid "CANCEL"
102−msgstr ""
102+msgstr "PREKLIČI"
103
103
104#: qml/Components/PinLockscreen.qml:216
104#: qml/Components/PinLockscreen.qml:216
105msgid "DONE"
105msgid "DONE"
106−msgstr ""
106+msgstr "KONČANO"
107
107
108#: qml/Components/SeeMore.qml:35
108#: qml/Components/SeeMore.qml:35
109msgid "See more"
109msgid "See more"
qml/Components/ResponsiveVerticalJournal.qmlnew file+74
@@ -0,0 +1,74 @@
1+/*
2+ * Copyright (C) 2013-2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import Ubuntu.Components 0.1
19+import "../Components"
20+import Dash 0.1
21+
22+/*!
23+ \brief A responsive wrapper around VerticalJournal.
24+
25+ Based on defined column width, delegates are laid out in columns following
26+ a top-left most position rule.
27+
28+ Example:
29+ +-----+ +-----+ +-----+
30+ | | | 2 | | |
31+ | | | | | |
32+ | 1 | +-----+ | 3 |
33+ | | +-----+ | |
34+ | | | | +-----+
35+ +-----+ | 4 | +-----+
36+ +-----+ | | | 5 |
37+ | 6 | +-----+ | |
38+ | | +-----+
39+ +-----+
40+*/
41+Item {
42+ property real minimumColumnSpacing: units.gu(1)
43+
44+ property alias columnWidth: verticalJournalView.columnWidth
45+ property alias rowSpacing: verticalJournalView.rowSpacing
46+ property alias model: verticalJournalView.model
47+ property alias delegate: verticalJournalView.delegate
48+ property alias displayMarginBeginning: verticalJournalView.displayMarginBeginning
49+ property alias displayMarginEnd: verticalJournalView.displayMarginEnd
50+ implicitHeight: verticalJournalView.implicitHeight
51+
52+ VerticalJournal {
53+ id: verticalJournalView
54+ objectName: "responsiveVerticalJournalView"
55+ anchors {
56+ fill: parent
57+ leftMargin: columnSpacing / 2
58+ rightMargin: columnSpacing / 2
59+ topMargin: rowSpacing / 2
60+ bottomMargin: rowSpacing / 2
61+ }
62+ clip: parent.height != implicitHeight
63+
64+ function px2gu(pixels) {
65+ return Math.floor(pixels / units.gu(1))
66+ }
67+
68+ columnSpacing: {
69+ // parent.width = columns * columnWidth + (columns-1) * spacing + spacing(margins)
70+ var expectedColumns = Math.max(1, Math.floor(parent.width / (columnWidth + minimumColumnSpacing)));
71+ Math.floor((parent.width - expectedColumns * columnWidth) / expectedColumns);
72+ }
73+ }
74+}
qml/Dash/CardCarousel.qml−2
@@ -27,9 +27,7 @@ DashRenderer {
27 property alias selectedItemScaleFactor: carousel.selectedItemScaleFactor
27 property alias selectedItemScaleFactor: carousel.selectedItemScaleFactor
28 property alias tileAspectRatio: carousel.tileAspectRatio
28 property alias tileAspectRatio: carousel.tileAspectRatio
29
29
30− currentItem: carousel.currentItem
31 height: carousel.implicitHeight + units.gu(6)
30 height: carousel.implicitHeight + units.gu(6)
32− verticalSpacing: units.gu(3)
33
31
34 Carousel {
32 Carousel {
35 id: carousel
33 id: carousel
qml/Dash/CardFilterGrid.qml+1−4
@@ -22,11 +22,8 @@ DashRenderer {
22
22
23 expandable: filterGrid.expandable
23 expandable: filterGrid.expandable
24 collapsedHeight: filterGrid.collapsedHeight
24 collapsedHeight: filterGrid.collapsedHeight
25− margins: filterGrid.margins
26 uncollapsedHeight: filterGrid.uncollapsedHeight
25 uncollapsedHeight: filterGrid.uncollapsedHeight
27 originY: filterGrid.originY
26 originY: filterGrid.originY
28− verticalSpacing: units.gu(1)
29− currentItem: filterGrid.currentItem
30 height: filterGrid.height
27 height: filterGrid.height
31 filtered: filterGrid.filtered
28 filtered: filterGrid.filtered
32
29
@@ -40,7 +37,7 @@ DashRenderer {
40 minimumHorizontalSpacing: units.gu(1)
37 minimumHorizontalSpacing: units.gu(1)
41 delegateWidth: cardTool.cardWidth
38 delegateWidth: cardTool.cardWidth
42 delegateHeight: cardTool.cardHeight
39 delegateHeight: cardTool.cardHeight
43− verticalSpacing: genericFilterGrid.verticalSpacing
40+ verticalSpacing: units.gu(1)
44 model: genericFilterGrid.model
41 model: genericFilterGrid.model
45 collapsedRowCount: Math.min(2, cardTool && cardTool.template && cardTool.template["collapsed-rows"] || 2)
42 collapsedRowCount: Math.min(2, cardTool && cardTool.template && cardTool.template["collapsed-rows"] || 2)
46 displayMarginBeginning: genericFilterGrid.displayMarginBeginning
43 displayMarginBeginning: genericFilterGrid.displayMarginBeginning
qml/Dash/CardVerticalJournal.qmlnew file+86
@@ -0,0 +1,86 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import Ubuntu.Components 0.1
19+import "../Components"
20+
21+DashRenderer {
22+ id: root
23+
24+ readonly property double collapseLimit: units.gu(35)
25+
26+ uncollapsedHeight: cardVerticalJournal.implicitHeight
27+ collapsedHeight: Math.min(collapseLimit, cardVerticalJournal.implicitHeight)
28+ expandable: uncollapsedHeight > collapseLimit
29+
30+ // This minHeight is used as bootstrapper for the height. Vertical Journal
31+ // is special by the fact that it doesn't know how to calculate its implicit height unless we give it
32+ // enough height that it can start creating its children so we make sure it has enough height for that
33+ // in case the model is non empty
34+ readonly property double minHeight: root.model.count > 1 ? cardVerticalJournal.rowSpacing + 1 : 0
35+ height: filtered ? Math.max(collapsedHeight, minHeight) : uncollapsedHeight
36+
37+ Behavior on height {
38+ id: heightBehaviour
39+ enabled: false
40+ animation: UbuntuNumberAnimation {
41+ onRunningChanged: {
42+ if (!running) {
43+ heightBehaviour.enabled = false
44+ }
45+ }
46+ }
47+ }
48+
49+ function setFilter(filter, animate) {
50+ heightBehaviour.enabled = animate;
51+ filtered = filter;
52+ }
53+
54+ ResponsiveVerticalJournal {
55+ id: cardVerticalJournal
56+
57+ model: root.model
58+
59+ anchors.fill: parent
60+ rowSpacing: minimumColumnSpacing
61+ columnWidth: cardTool.cardWidth
62+
63+ displayMarginBeginning: root.displayMarginBeginning
64+ displayMarginEnd: root.displayMarginEnd
65+
66+ delegate: Loader {
67+ id: loader
68+ sourceComponent: cardTool.cardComponent
69+ width: cardTool.cardWidth
70+ onLoaded: {
71+ item.objectName = "delegate" + index;
72+ item.fixedArtShapeSize = Qt.binding(function() { return cardTool.artShapeSize; });
73+ item.fixedHeaderHeight = Qt.binding(function() { return cardTool.headerHeight; });
74+ item.cardData = Qt.binding(function() { return model; });
75+ item.template = Qt.binding(function() { return cardTool.template; });
76+ item.components = Qt.binding(function() { return cardTool.components; });
77+ item.headerAlignment = Qt.binding(function() { return cardTool.headerAlignment; });
78+ }
79+ Connections {
80+ target: loader.item
81+ onClicked: root.clicked(index, result)
82+ onPressAndHold: root.pressAndHold(index)
83+ }
84+ }
85+ }
86+}
qml/Dash/DashRenderer.qml−7
@@ -25,8 +25,6 @@ Item {
25
25
26 property int collapsedHeight: height
26 property int collapsedHeight: height
27
27
28− property int margins: 0
29−
30 property int uncollapsedHeight: height
28 property int uncollapsedHeight: height
31
29
32 property int displayMarginBeginning: 0
30 property int displayMarginBeginning: 0
@@ -35,11 +33,6 @@ Item {
35
33
36 property real originY: 0
34 property real originY: 0
37
35
38− property real verticalSpacing: 0
39−
40− // The current item of the renderer
41− property var currentItem
42−
43 // The model to renderer
36 // The model to renderer
44 property var model
37 property var model
45
38
qml/Dash/GenericScopeView.qml+10−1
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2013 Canonical, Ltd.
2+ * Copyright (C) 2013-2014 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU General Public License as published by
@@ -147,6 +147,7 @@ FocusScope {
147 source: {
147 source: {
148 switch (cardTool.categoryLayout) {
148 switch (cardTool.categoryLayout) {
149 case "carousel": return "CardCarousel.qml";
149 case "carousel": return "CardCarousel.qml";
150+ case "vertical-journal": return "CardVerticalJournal.qml";
150 case "running-apps": return "Apps/RunningApplicationsGrid.qml";
151 case "running-apps": return "Apps/RunningApplicationsGrid.qml";
151 case "grid":
152 case "grid":
152 default: return "CardFilterGrid.qml";
153 default: return "CardFilterGrid.qml";
@@ -203,6 +204,14 @@ FocusScope {
203 previewListView.currentIndex = index;
204 previewListView.currentIndex = index;
204 previewListView.open = true
205 previewListView.open = true
205 }
206 }
207+ onExpandableChanged: {
208+ // This can happen with the VJ that doesn't know how height it will be on creation
209+ // so doesn't set expandable until a bit too late for onLoaded
210+ if (rendererLoader.item.expandable) {
211+ var shouldFilter = baseItem.category != categoryView.expandedCategoryId;
212+ rendererLoader.item.setFilter(shouldFilter, false /*animate*/);
213+ }
214+ }
206 }
215 }
207 Connections {
216 Connections {
208 target: categoryView
217 target: categoryView
qml/Greeter/LoginList.qml+4−4
@@ -257,13 +257,13 @@ Item {
257
257
258 onShowMessage: {
258 onShowMessage: {
259 // inefficient, but we only rarely deal with messages
259 // inefficient, but we only rarely deal with messages
260− text = text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\n/g, "<br>");
260+ var html = text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\n/g, "<br>")
261 if (isError)
261 if (isError)
262− text = "<font color=\"#df382c\">" + text + "</font>"
262+ html = "<font color=\"#df382c\">" + html + "</font>"
263 if (infoLabel.text == "")
263 if (infoLabel.text == "")
264− infoLabel.text = text;
264+ infoLabel.text = html
265 else
265 else
266− infoLabel.text = infoLabel.text + "<br>" + text;
266+ infoLabel.text = infoLabel.text + "<br>" + html
267 }
267 }
268
268
269 onShowPrompt: {
269 onShowPrompt: {
qml/Notifications/Notification.qml+13
@@ -15,6 +15,7 @@
15 */
15 */
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18+import QtMultimedia 5.0
18import Ubuntu.Components 0.1
19import Ubuntu.Components 0.1
19import Unity.Notifications 1.0
20import Unity.Notifications 1.0
20import QMenuModel 0.1
21import QMenuModel 0.1
@@ -66,6 +67,18 @@ Item {
66 return result;
67 return result;
67 }
68 }
68
69
70+ Audio {
71+ id: sound
72+ objectName: "sound"
73+ source: hints["suppress-sound"] != "" ? hints["sound-file"] : undefined
74+ }
75+
76+ onOpacityChanged: {
77+ if (opacity == 1.0 && hints["suppress-sound"] != "true" && sound.source) {
78+ sound.play();
79+ }
80+ }
81+
69 Behavior on height {
82 Behavior on height {
70 id: normalHeightBehavior
83 id: normalHeightBehavior
71
84
qml/Shell.qml+26−1
@@ -32,6 +32,7 @@ import "Components"
32import "Notifications"
32import "Notifications"
33import "Stages"
33import "Stages"
34import Unity.Notifications 1.0 as NotificationBackend
34import Unity.Notifications 1.0 as NotificationBackend
35+import Unity.Session 0.1
35
36
36FocusScope {
37FocusScope {
37 id: shell
38 id: shell
@@ -234,6 +235,30 @@ FocusScope {
234 }
235 }
235 }
236 }
236
237
238+ Connections {
239+ target: DBusUnitySessionService
240+
241+ function closeAllApps() {
242+ while (true) {
243+ var app = ApplicationManager.get(0);
244+ if (app === null) {
245+ break;
246+ }
247+ ApplicationManager.stopApplication(app.appId);
248+ }
249+ }
250+
251+ onLogoutRequested: {
252+ // TODO: Display a dialog to ask the user to confirm.
253+ DBusUnitySessionService.Logout();
254+ }
255+
256+ onLogoutReady: {
257+ closeAllApps();
258+ Qt.quit();
259+ }
260+ }
261+
237 Loader {
262 Loader {
238 id: applicationsDisplayLoader
263 id: applicationsDisplayLoader
239 anchors.fill: parent
264 anchors.fill: parent
@@ -411,7 +436,7 @@ FocusScope {
411 onDisplayPowerStateChange: {
436 onDisplayPowerStateChange: {
412 // We ignore any display-off signals when the proximity sensor
437 // We ignore any display-off signals when the proximity sensor
413 // is active. This usually indicates something like a phone call.
438 // is active. This usually indicates something like a phone call.
414− if (status == Powerd.Off && (flags & Powerd.UseProximity) == 0) {
439+ if (status == Powerd.Off && reason != Powerd.Proximity) {
415 greeter.showNow();
440 greeter.showNow();
416 }
441 }
417
442
src/main.cpp+1
@@ -143,6 +143,7 @@ Load the testability driver");
143 appendImportPaths(view->engine(), ::fallbackImportPaths());
143 appendImportPaths(view->engine(), ::fallbackImportPaths());
144
144
145 view->setSource(source);
145 view->setSource(source);
146+ QObject::connect(view->engine(), SIGNAL(quit()), application, SLOT(quit()));
146
147
147 if (isMirServer || parser.isSet(fullscreenOption)) {
148 if (isMirServer || parser.isSet(fullscreenOption)) {
148 view->showFullScreen();
149 view->showFullScreen();
tests/mocks/AccountsService/AccountsService.cpp+3−1
@@ -18,9 +18,11 @@
18
18
19#include "AccountsService.h"
19#include "AccountsService.h"
20
20
21+#include <paths.h>
22+
21AccountsService::AccountsService(QObject* parent)
23AccountsService::AccountsService(QObject* parent)
22 : QObject(parent),
24 : QObject(parent),
23− m_backgroundFile(TOP_SRCDIR "/qml/graphics/phone_background.jpg"),
25+ m_backgroundFile(qmlDirectory() + "graphics/phone_background.jpg"),
24 m_statsWelcomeScreen(true)
26 m_statsWelcomeScreen(true)
25{
27{
26}
28}
tests/mocks/AccountsService/CMakeLists.txt−2
@@ -1,5 +1,3 @@
1−add_definitions(-DTOP_SRCDIR="${CMAKE_SOURCE_DIR}")
2−
3add_library(MockAccountsService-qml MODULE
1add_library(MockAccountsService-qml MODULE
4 AccountsService.cpp
2 AccountsService.cpp
5 plugin.cpp
3 plugin.cpp
tests/mocks/Powerd/Powerd.h+7−7
@@ -25,15 +25,15 @@ class Powerd: public QObject
25{
25{
26 Q_OBJECT
26 Q_OBJECT
27 Q_ENUMS(Status)
27 Q_ENUMS(Status)
28− Q_FLAGS(DisplayFlag DisplayFlags)
28+ Q_ENUMS(DisplayStateChangeReason)
29
29
30public:
30public:
31− enum DisplayFlag {
31+ enum DisplayStateChangeReason {
32− UseProximity = 1, // Use proximity sensor to override screen state
32+ Unknown = 0,
33− DisableAutoBrightness = 2, // Force autobrightness to be disabled
33+ Inactivity = 1, // Display changed state due to inactivity
34− Bright = 4, // Request the screen to stay bright
34+ PowerKey = 2, // Display changed state due to user pressing power key
35+ Proximity = 3, // Display changed state due to proximity events
35 };
36 };
36− Q_DECLARE_FLAGS(DisplayFlags, DisplayFlag)
37
37
38 enum Status {
38 enum Status {
39 Off,
39 Off,
@@ -43,7 +43,7 @@ public:
43 explicit Powerd(QObject *parent = 0);
43 explicit Powerd(QObject *parent = 0);
44
44
45Q_SIGNALS:
45Q_SIGNALS:
46− void displayPowerStateChange(int status, unsigned int flags);
46+ void displayPowerStateChange(int status, int reason);
47};
47};
48
48
49#endif
49#endif
tests/mocks/Unity/Launcher/CMakeLists.txt−2
@@ -1,7 +1,5 @@
1pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=3)
1pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=3)
2
2
3−add_definitions(-DTOP_SRCDIR="${CMAKE_SOURCE_DIR}")
4−
5include_directories(
3include_directories(
6 ${CMAKE_CURRENT_SOURCE_DIR}
4 ${CMAKE_CURRENT_SOURCE_DIR}
7)
5)
tests/mocks/Unity/Launcher/MockLauncherItem.cpp+3−1
@@ -20,6 +20,8 @@
20#include "MockLauncherItem.h"
20#include "MockLauncherItem.h"
21#include "MockQuickListModel.h"
21#include "MockQuickListModel.h"
22
22
23+#include <paths.h>
24+
23using namespace unity::shell::launcher;
25using namespace unity::shell::launcher;
24
26
25MockLauncherItem::MockLauncherItem(const QString &appId, const QString& desktopFile, const QString& name, const QString& icon, QObject* parent):
27MockLauncherItem::MockLauncherItem(const QString &appId, const QString& desktopFile, const QString& name, const QString& icon, QObject* parent):
@@ -27,7 +29,7 @@ MockLauncherItem::MockLauncherItem(const QString &appId, const QString& desktopF
27 m_appId(appId),
29 m_appId(appId),
28 m_desktopFile(desktopFile),
30 m_desktopFile(desktopFile),
29 m_name(name),
31 m_name(name),
30− m_icon(TOP_SRCDIR "/graphics/applicationIcons/" + icon + ".png"),
32+ m_icon(qmlDirectory() + "graphics/applicationIcons/" + icon + ".png"),
31 m_pinned(false),
33 m_pinned(false),
32 m_running(false),
34 m_running(false),
33 m_recent(false),
35 m_recent(false),
tests/mocks/Unity/fake_categories.cpp+1−1
@@ -50,7 +50,7 @@ void Categories::addSpecialCategory(QString const& categoryId, QString const& na
50 }
50 }
51}
51}
52
52
53−bool Categories::overrideCategoryJson(QString const& categoryId, QString const& json)
53+bool Categories::overrideCategoryJson(QString const& /* categoryId */, QString const& /* json */)
54{
54{
55 qFatal("Using un-implemented Categories::overrideCategoryJson");
55 qFatal("Using un-implemented Categories::overrideCategoryJson");
56}
56}
tests/mocks/Unity/fake_scope.cpp+5
@@ -155,6 +155,11 @@ bool Scope::hasDepartments() const
155 return true;
155 return true;
156}
156}
157
157
158+QVariantMap Scope::customizations() const
159+{
160+ return QVariantMap();
161+}
162+
158unity::shell::scopes::DepartmentInterface* Scope::getDepartment(const QString& id)
163unity::shell::scopes::DepartmentInterface* Scope::getDepartment(const QString& id)
159{
164{
160 if (id.isEmpty())
165 if (id.isEmpty())
tests/mocks/Unity/fake_scope.h+2
@@ -64,6 +64,8 @@ public:
64 Q_INVOKABLE unity::shell::scopes::DepartmentInterface* getDepartment(const QString& id) override;
64 Q_INVOKABLE unity::shell::scopes::DepartmentInterface* getDepartment(const QString& id) override;
65 Q_INVOKABLE void loadDepartment(const QString& id) override;
65 Q_INVOKABLE void loadDepartment(const QString& id) override;
66
66
67+ QVariantMap customizations() const override;
68+
67protected:
69protected:
68
70
69 QString m_id;
71 QString m_id;
tests/plugins/Dash/cardcreator/1.res+15−9
@@ -16,8 +16,8 @@ onArtShapeBorderSourceChanged: { if (artShapeBorderSource !== undefined && artSh
16readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
16readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
17Item {
17Item {
18 id: artShapeHolder;
18 id: artShapeHolder;
19− height: root.fixedArtShapeSize.height != -1 ? root.fixedArtShapeSize.height : artShapeLoader.height;
19+ height: root.fixedArtShapeSize.height > 0 ? root.fixedArtShapeSize.height : artShapeLoader.height;
20− width: root.fixedArtShapeSize.width != -1 ? root.fixedArtShapeSize.width : artShapeLoader.width;
20+ width: root.fixedArtShapeSize.width > 0 ? root.fixedArtShapeSize.width : artShapeLoader.width;
21 anchors { horizontalCenter: parent.horizontalCenter; }
21 anchors { horizontalCenter: parent.horizontalCenter; }
22 Loader {
22 Loader {
23 id: artShapeLoader;
23 id: artShapeLoader;
@@ -28,14 +28,19 @@ Item {
28 sourceComponent: UbuntuShape {
28 sourceComponent: UbuntuShape {
29 id: artShape;
29 id: artShape;
30 objectName: "artShape";
30 objectName: "artShape";
31− radius: "medium";
31+ radius: "medium";
32− readonly property real aspect: components !== undefined ? components["art"]["aspect-ratio"] : 1;
33− readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect;
34− Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
35− onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings();
36 visible: image.status == Image.Ready;
32 visible: image.status == Image.Ready;
33+ readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
34+ readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1;
35+ readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect;
36+ Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
37+ onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings();
38+ Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
37 function updateWidthHeightBindings() {
39 function updateWidthHeightBindings() {
40+ if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) {
41+ width = root.fixedArtShapeSize.width;
42+ height = root.fixedArtShapeSize.height;
38− if (aspectSmallerThanImageAspect) {
43+ } else if (aspectSmallerThanImageAspect) {
39 width = Qt.binding(function() { return !visible ? 0 : image.width });
44 width = Qt.binding(function() { return !visible ? 0 : image.width });
40 height = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.height : width / image.aspect });
45 height = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.height : width / image.aspect });
41 } else {
46 } else {
@@ -56,13 +61,14 @@ Item {
56 }
61 }
57 }
62 }
58 }
63 }
59−readonly property int headerHeight: titleLabel.height + titleLabel.anchors.topMargin * 2;
64+readonly property int headerHeight: titleLabel.height;
60Label {
65Label {
61 id: titleLabel;
66 id: titleLabel;
62 objectName: "titleLabel";
67 objectName: "titleLabel";
63 anchors { right: parent.right;left: parent.left;
68 anchors { right: parent.right;left: parent.left;
64top: artShapeHolder.bottom;
69top: artShapeHolder.bottom;
65 topMargin: units.gu(1);
70 topMargin: units.gu(1);
71+leftMargin: units.gu(1);
66 }
72 }
67 elide: Text.ElideRight;
73 elide: Text.ElideRight;
68 fontSize: "small";
74 fontSize: "small";
tests/plugins/Dash/cardcreator/2.res+2−1
@@ -46,12 +46,13 @@ Loader {
46 }
46 }
47 }
47 }
48readonly property size artShapeSize: Qt.size(-1, -1);
48readonly property size artShapeSize: Qt.size(-1, -1);
49−readonly property int headerHeight: row.height + row.margins * 2;
49+readonly property int headerHeight: row.height;
50Row {
50Row {
51 id: row;
51 id: row;
52 objectName: "outerRow";
52 objectName: "outerRow";
53 property real margins: units.gu(1);
53 property real margins: units.gu(1);
54 spacing: margins;
54 spacing: margins;
55+ height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight;
55 anchors { top: parent.top;
56 anchors { top: parent.top;
56 topMargin: units.gu(1);
57 topMargin: units.gu(1);
57 left: parent.left;
58 left: parent.left;
tests/plugins/Dash/cardcreator/3.res+21−15
@@ -16,8 +16,8 @@ onArtShapeBorderSourceChanged: { if (artShapeBorderSource !== undefined && artSh
16readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
16readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
17Item {
17Item {
18 id: artShapeHolder;
18 id: artShapeHolder;
19− height: root.fixedArtShapeSize.height != -1 ? root.fixedArtShapeSize.height : artShapeLoader.height;
19+ height: root.fixedArtShapeSize.height > 0 ? root.fixedArtShapeSize.height : artShapeLoader.height;
20− width: root.fixedArtShapeSize.width != -1 ? root.fixedArtShapeSize.width : artShapeLoader.width;
20+ width: root.fixedArtShapeSize.width > 0 ? root.fixedArtShapeSize.width : artShapeLoader.width;
21 anchors { horizontalCenter: parent.horizontalCenter; }
21 anchors { horizontalCenter: parent.horizontalCenter; }
22 Loader {
22 Loader {
23 id: artShapeLoader;
23 id: artShapeLoader;
@@ -29,19 +29,24 @@ Item {
29 id: artShape;
29 id: artShape;
30 objectName: "artShape";
30 objectName: "artShape";
31 radius: "medium";
31 radius: "medium";
32− readonly property real aspect: components !== undefined ? components["art"]["aspect-ratio"] : 1;
33− readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect;
34− Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
35− onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings();
36 visible: image.status == Image.Ready;
32 visible: image.status == Image.Ready;
33+ readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
34+ readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1;
35+ readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect;
36+ Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
37+ onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings();
38+ Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
37− function updateWidthHeightBindings() {
39+ function updateWidthHeightBindings() {
40+ if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) {
41+ width = root.fixedArtShapeSize.width;
42+ height = root.fixedArtShapeSize.height;
38− if (aspectSmallerThanImageAspect) {
43+ } else if (aspectSmallerThanImageAspect) {
39− width = Qt.binding(function() { return !visible ? 0 : image.width });
44+ width = Qt.binding(function() { return !visible ? 0 : image.width });
40− height = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.height : width / image.aspect });
45+ height = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.height : width / image.aspect });
41− } else {
46+ } else {
42− width = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.width : height * image.aspect });
47+ width = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.width : height * image.aspect });
43− height = Qt.binding(function() { return !visible ? 0 : image.height });
48+ height = Qt.binding(function() { return !visible ? 0 : image.height });
44− }
49+ }
45 }
50 }
46 image: Image {
51 image: Image {
47 objectName: "artImage";
52 objectName: "artImage";
@@ -56,13 +61,14 @@ Item {
56 }
61 }
57 }
62 }
58 }
63 }
59−readonly property int headerHeight: titleLabel.height + titleLabel.anchors.topMargin * 2 + subtitleLabel.height + subtitleLabel.anchors.topMargin;
64+readonly property int headerHeight: titleLabel.height + subtitleLabel.height + subtitleLabel.anchors.topMargin;
60Label {
65Label {
61 id: titleLabel;
66 id: titleLabel;
62 objectName: "titleLabel";
67 objectName: "titleLabel";
63 anchors { right: parent.right;left: parent.left;
68 anchors { right: parent.right;left: parent.left;
64top: artShapeHolder.bottom;
69top: artShapeHolder.bottom;
65 topMargin: units.gu(1);
70 topMargin: units.gu(1);
71+leftMargin: units.gu(1);
66}
72}
67 elide: Text.ElideRight;
73 elide: Text.ElideRight;
68 fontSize: "small";
74 fontSize: "small";
tests/plugins/Dash/cardcreator/4.res+2−1
@@ -13,12 +13,13 @@ AbstractButton {
13 property bool showHeader: true;
13 property bool showHeader: true;
14 implicitWidth: childrenRect.width;
14 implicitWidth: childrenRect.width;
15readonly property size artShapeSize: Qt.size(-1, -1);
15readonly property size artShapeSize: Qt.size(-1, -1);
16−readonly property int headerHeight: row.height + row.margins * 2;
16+readonly property int headerHeight: row.height;
17Row {
17Row {
18 id: row;
18 id: row;
19 objectName: "outerRow";
19 objectName: "outerRow";
20 property real margins: units.gu(1);
20 property real margins: units.gu(1);
21 spacing: margins;
21 spacing: margins;
22+ height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight;
22 anchors { top: parent.top;
23 anchors { top: parent.top;
23 topMargin: units.gu(1);
24 topMargin: units.gu(1);
24 left: parent.left;
25 left: parent.left;
tests/plugins/Dash/cardcreator/5.res+21−16
@@ -16,8 +16,8 @@ onArtShapeBorderSourceChanged: { if (artShapeBorderSource !== undefined && artSh
16readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
16readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
17Item {
17Item {
18 id: artShapeHolder;
18 id: artShapeHolder;
19− height: root.fixedArtShapeSize.height != -1 ? root.fixedArtShapeSize.height : artShapeLoader.height;
19+ height: root.fixedArtShapeSize.height > 0 ? root.fixedArtShapeSize.height : artShapeLoader.height;
20− width: root.fixedArtShapeSize.width != -1 ? root.fixedArtShapeSize.width : artShapeLoader.width;
20+ width: root.fixedArtShapeSize.width > 0 ? root.fixedArtShapeSize.width : artShapeLoader.width;
21 anchors { horizontalCenter: parent.horizontalCenter; }
21 anchors { horizontalCenter: parent.horizontalCenter; }
22 Loader {
22 Loader {
23 id: artShapeLoader;
23 id: artShapeLoader;
@@ -29,19 +29,24 @@ Item {
29 id: artShape;
29 id: artShape;
30 objectName: "artShape";
30 objectName: "artShape";
31 radius: "medium";
31 radius: "medium";
32− readonly property real aspect: components !== undefined ? components["art"]["aspect-ratio"] : 1;
33− readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect;
34− Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
35− onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings();
36 visible: image.status == Image.Ready;
32 visible: image.status == Image.Ready;
33+ readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
34+ readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1;
35+ readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect;
36+ Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
37+ onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings();
38+ Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
37− function updateWidthHeightBindings() {
39+ function updateWidthHeightBindings() {
40+ if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) {
41+ width = root.fixedArtShapeSize.width;
42+ height = root.fixedArtShapeSize.height;
38− if (aspectSmallerThanImageAspect) {
43+ } else if (aspectSmallerThanImageAspect) {
39− width = Qt.binding(function() { return !visible ? 0 : image.width });
44+ width = Qt.binding(function() { return !visible ? 0 : image.width });
40− height = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.height : width / image.aspect });
45+ height = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.height : width / image.aspect });
41− } else {
46+ } else {
42− width = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.width : height * image.aspect });
47+ width = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.width : height * image.aspect });
43− height = Qt.binding(function() { return !visible ? 0 : image.height });
48+ height = Qt.binding(function() { return !visible ? 0 : image.height });
44− }
49+ }
45 }
50 }
46 image: Image {
51 image: Image {
47 objectName: "artImage";
52 objectName: "artImage";
@@ -68,7 +73,7 @@ Loader {
68 visible: showHeader && status == Loader.Ready;
73 visible: showHeader && status == Loader.Ready;
69 sourceComponent: ShaderEffect {
74 sourceComponent: ShaderEffect {
70 id: overlay;
75 id: overlay;
71− height: fixedHeaderHeight != -1 ? fixedHeaderHeight : headerHeight;
76+ height: (fixedHeaderHeight > 0 ? fixedHeaderHeight : headerHeight) + units.gu(2);
72 opacity: 0.6;
77 opacity: 0.6;
73 property var source: ShaderEffectSource {
78 property var source: ShaderEffectSource {
74 id: shaderSource;
79 id: shaderSource;
@@ -96,7 +101,7 @@ Loader {
96 }";
101 }";
97 }
102 }
98 }
103 }
99−readonly property int headerHeight: titleLabel.height + titleLabel.anchors.topMargin * 2 + subtitleLabel.height + subtitleLabel.anchors.topMargin;
104+readonly property int headerHeight: titleLabel.height + subtitleLabel.height + subtitleLabel.anchors.topMargin;
100Label {
105Label {
101 id: titleLabel;
106 id: titleLabel;
102 objectName: "titleLabel";
107 objectName: "titleLabel";
tests/plugins/Unity/CMakeLists.txt+1
@@ -1,2 +1,3 @@
1add_subdirectory(Indicators)
1add_subdirectory(Indicators)
2add_subdirectory(Launcher)
2add_subdirectory(Launcher)
3+add_subdirectory(Session)
tests/plugins/Unity/Session/CMakeLists.txtnew file+20
@@ -0,0 +1,20 @@
1+include_directories(
2+ ${CMAKE_CURRENT_BINARY_DIR}
3+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Session
4+)
5+
6+add_definitions(-DSM_BUSNAME=sessionBus)
7+add_definitions(-DSRCDIR="${CMAKE_CURRENT_SOURCE_DIR}")
8+add_definitions(-DSESSION_TESTING)
9+
10+### SessionBackendTest
11+set(testBackendCommand dbus-test-runner --task ${CMAKE_CURRENT_BINARY_DIR}/sessionbackendtestExec
12+ --parameter -o --parameter ${CMAKE_BINARY_DIR}/sessionbackendtest.xml,xunitxml
13+ --parameter -o --parameter -,txt)
14+add_test(NAME sessionbackendtest COMMAND ${testBackendCommand})
15+add_custom_target(sessionbackendtest ${testBackendCommand})
16+add_executable(sessionbackendtestExec
17+ sessionbackendtest.cpp
18+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Session/dbusunitysessionservice.cpp
19+)
20+qt5_use_modules(sessionbackendtestExec Test Core Qml DBus)
tests/plugins/Unity/Session/sessionbackendtest.cppnew file+64
@@ -0,0 +1,64 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Ying-Chun Liu (PaulLiu) <paul.liu@canonical.com>
18+ */
19+
20+#include <QtTest>
21+#include <QDBusConnection>
22+#include <QDBusMessage>
23+#include <QDBusInterface>
24+#include <QDBusReply>
25+#include <QDBusVariant>
26+
27+#include "dbusunitysessionservice.h"
28+
29+class SessionBackendTest : public QObject
30+{
31+ Q_OBJECT
32+
33+private Q_SLOTS:
34+
35+ void initTestCase() {
36+ }
37+
38+ void testDbusIfaceMethods_data() {
39+ QTest::addColumn<QString>("method");
40+
41+ QTest::newRow("Logout") << "RequestLogout";
42+ }
43+
44+ void testDbusIfaceMethods() {
45+ QFETCH(QString, method);
46+
47+ DBusUnitySessionService dbusUnitySessionService;
48+
49+ QDBusConnection con = QDBusConnection::sessionBus();
50+ QDBusInterface interface ("com.canonical.Unity",
51+ "/com/canonical/Unity/Session",
52+ "com.canonical.Unity.Session",
53+ con);
54+ QDBusReply<void> reply;
55+
56+ QCOMPARE(interface.isValid(), true);
57+ reply = interface.call(method);
58+ QCOMPARE(reply.isValid(), true);
59+
60+ }
61+};
62+
63+QTEST_GUILESS_MAIN(SessionBackendTest)
64+#include "sessionbackendtest.moc"
tests/qmltests/CMakeLists.txt+1
@@ -29,6 +29,7 @@ add_qml_test(Components LazyImage)
29add_qml_test(Components Rating)
29add_qml_test(Components Rating)
30add_qml_test(Components ResponsiveFlowView)
30add_qml_test(Components ResponsiveFlowView)
31add_qml_test(Components ResponsiveGridView)
31add_qml_test(Components ResponsiveGridView)
32+add_qml_test(Components ResponsiveVerticalJournal IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins)
32add_qml_test(Components SeeMore)
33add_qml_test(Components SeeMore)
33add_qml_test(Components Showable)
34add_qml_test(Components Showable)
34add_qml_test(Components PageHeaderLabel)
35add_qml_test(Components PageHeaderLabel)
tests/qmltests/Components/tst_LazyImage.qml−1
@@ -152,7 +152,6 @@ Rectangle {
152
152
153 function test_lazyimage(data) {
153 function test_lazyimage(data) {
154 data.func();
154 data.func();
155− waitForRendering(baseRect);
156
155
157 if (data.transition) {
156 if (data.transition) {
158 // wait for the transition to complete
157 // wait for the transition to complete
tests/qmltests/Components/tst_ResponsiveVerticalJournal.qmlnew file+183
@@ -0,0 +1,183 @@
1+/*
2+ * Copyright 2013-2014 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import QtTest 1.0
19+import ".."
20+import "../../../qml/Components"
21+import Ubuntu.Components.ListItems 0.1 as ListItem
22+import Ubuntu.Components 0.1
23+import Utils 0.1
24+import Unity.Test 0.1 as UT
25+
26+Item {
27+ width: units.gu(80) + controls.width
28+ height: units.gu(80)
29+
30+ Column {
31+ id: controls
32+ width: units.gu(40)
33+ height: parent.height
34+ anchors.top: parent.top
35+ anchors.right: parent.right
36+ ListItem.ValueSelector {
37+ id: cardSizeSelector
38+ text: "card-size"
39+ // small, medium, large card sizes
40+ values: [units.gu(12), units.gu(18.5), units.gu(38)]
41+ selectedIndex: 0
42+ }
43+ ListItem.ValueSelector {
44+ id: minColumnSpacingSelector
45+ text: "minColumnSpacing"
46+ values: [0, units.gu(2), units.gu(8), units.gu(25)]
47+ selectedIndex: 0
48+ }
49+ ListItem.ValueSelector {
50+ id: rowSpacingSelector
51+ text: "rowSpacing"
52+ values: [units.gu(1), units.gu(2), units.gu(4), units.gu(8)]
53+ selectedIndex: 1
54+ }
55+ }
56+
57+ ListModel {
58+ id: fakeModel
59+ ListElement { name: "A" }
60+ ListElement { name: "B" }
61+ ListElement { name: "C" }
62+ ListElement { name: "D" }
63+ ListElement { name: "E" }
64+ ListElement { name: "F" }
65+ ListElement { name: "G" }
66+ ListElement { name: "H" }
67+ ListElement { name: "I" }
68+ ListElement { name: "J" }
69+ ListElement { name: "K" }
70+ ListElement { name: "L" }
71+ ListElement { name: "M" }
72+ ListElement { name: "N" }
73+ ListElement { name: "O" }
74+ ListElement { name: "P" }
75+ ListElement { name: "Q" }
76+ ListElement { name: "R" }
77+ ListElement { name: "S" }
78+ ListElement { name: "T" }
79+ ListElement { name: "U" }
80+ }
81+
82+ SortFilterProxyModel {
83+ id: wrappedFakeModel
84+ model: fakeModel
85+ }
86+
87+ Rectangle {
88+ id: journalRect
89+ height: parent.height
90+ color: "grey"
91+ anchors.top: parent.top
92+ anchors.left: parent.left
93+ anchors.right: controls.left
94+
95+ ResponsiveVerticalJournal {
96+ id: journal
97+ anchors.fill: parent
98+ model: wrappedFakeModel
99+ minimumColumnSpacing: minColumnSpacingSelector.values[minColumnSpacingSelector.selectedIndex]
100+ rowSpacing: rowSpacingSelector.values[rowSpacingSelector.selectedIndex]
101+ columnWidth: cardSizeSelector.values[cardSizeSelector.selectedIndex]
102+
103+ delegate: Rectangle {
104+ id: delegateItem
105+ // So that it can be identified by test code
106+ property bool isJournalDelegate: true
107+ objectName: "delegate" + index
108+ color: "grey"
109+ border.color: "red"
110+ border.width: 1
111+
112+ // width derived from Card's template['card-size']
113+ width: cardSizeSelector.values[cardSizeSelector.selectedIndex]
114+ height: Math.max(units.gu(8), Math.floor(Math.random() * 300))
115+
116+ Rectangle {
117+ color: "green"
118+ anchors.centerIn: parent
119+ width: units.gu(6)
120+ height: units.gu(6)
121+ Text {
122+ anchors.centerIn: parent
123+ text: name
124+ }
125+ }
126+
127+ Text { x:0; y:0; text:"(" + parent.x + ", " + parent.y + ")"}
128+ }
129+ }
130+ }
131+
132+ UT.UnityTestCase {
133+ name: "ResponsiveVerticalJournal"
134+ when: windowShown
135+
136+ function test_minimumColumnSpacing_data() {
137+ return [{minColumnSpacingIndex: 0, expectedColumns: 2},
138+ {minColumnSpacingIndex: 1, expectedColumns: 2},
139+ {minColumnSpacingIndex: 2, expectedColumns: 1}]
140+ }
141+
142+ // Test how minimumColumnSpacing affects column count.
143+ function test_minimumColumnSpacing(data) {
144+ cardSizeSelector.selectedIndex = 2 // large card
145+
146+ minColumnSpacingSelector.selectedIndex = data.minColumnSpacingIndex
147+
148+ tryCompareFunction(countJournalDelegatesOnFirstRow, data.expectedColumns)
149+ }
150+
151+ function test_maximumNumberOfColumns_data() {
152+ return [{cardSizeIndex: 0, expectedColumns: 6},
153+ {cardSizeIndex: 1, expectedColumns: 4},
154+ {cardSizeIndex: 2, expectedColumns: 2}]
155+ }
156+
157+ // Test how maximumNumberOfColumns and columnWidth affect column count.
158+ function test_maximumNumberOfColumns(data) {
159+ minColumnSpacingSelector.selectedIndex = 0 // no spacing
160+
161+ cardSizeSelector.selectedIndex = data.cardSizeIndex // columnWidth
162+
163+ tryCompareFunction(countJournalDelegatesOnFirstRow, data.expectedColumns)
164+ }
165+
166+ function countJournalDelegatesOnFirstRow() {
167+ return __countJournalDelegatesOnFirstRow(journal.visibleChildren, 0)
168+ }
169+
170+ function __countJournalDelegatesOnFirstRow(objList, total) {
171+ for (var i = 0; i < objList.length; ++i) {
172+ var child = objList[i];
173+ if (child.isJournalDelegate !== undefined && child.y === 0) {
174+ ++total;
175+ } else {
176+ total = __countJournalDelegatesOnFirstRow(
177+ child.visibleChildren, total)
178+ }
179+ }
180+ return total
181+ }
182+ }
183+}
tests/qmltests/Dash/tst_Card.qml+9
@@ -305,6 +305,15 @@ Rectangle {
305 }
305 }
306 }
306 }
307
307
308+ function test_art_shape_fixed_size() {
309+ selector.selectedIndex = 6;
310+ card.fixedArtShapeSize = Qt.size( units.gu(8), units.gu(4) );
311+ waitForRendering(card);
312+ tryCompare(art, "width", units.gu(8));
313+ tryCompare(art, "height", units.gu(4));
314+ tryCompare(art, "fixedArtShapeSizeAspect", 2);
315+ }
316+
308 function test_art_layout_data() {
317 function test_art_layout_data() {
309 return [
318 return [
310 { tag: "Vertical", left: function() { return units.gu(1); }, index: 0},
319 { tag: "Vertical", left: function() { return units.gu(1); }, index: 0},
tests/qmltests/Notifications/tst_Notifications.qml+29−12
@@ -21,6 +21,7 @@ import "../../../qml/Notifications"
21import Ubuntu.Components 0.1
21import Ubuntu.Components 0.1
22import Unity.Test 0.1
22import Unity.Test 0.1
23import Unity.Notifications 1.0
23import Unity.Notifications 1.0
24+import QtMultimedia 5.0
24
25
25Row {
26Row {
26 id: rootRow
27 id: rootRow
@@ -245,7 +246,8 @@ Row {
245 nonShapedIcon: false,
246 nonShapedIcon: false,
246 secondaryIconVisible: true,
247 secondaryIconVisible: true,
247 buttonRowVisible: true,
248 buttonRowVisible: true,
248− buttonTinted: true
249+ buttonTinted: true,
250+ hasSound: false
249 },
251 },
250 {
252 {
251 tag: "Ephemeral notification - icon-summary layout",
253 tag: "Ephemeral notification - icon-summary layout",
@@ -263,12 +265,15 @@ Row {
263 nonShapedIcon: false,
265 nonShapedIcon: false,
264 secondaryIconVisible: true,
266 secondaryIconVisible: true,
265 buttonRowVisible: false,
267 buttonRowVisible: false,
266− buttonTinted: false
268+ buttonTinted: false,
269+ hasSound: false
267 },
270 },
268 {
271 {
269 tag: "Ephemeral notification - check suppression of secondary icon for icon-summary layout",
272 tag: "Ephemeral notification - check suppression of secondary icon for icon-summary layout",
270 type: Notification.Ephemeral,
273 type: Notification.Ephemeral,
271− hints: {"x-canonical-private-button-tint": "false"},
274+ hints: {"x-canonical-private-button-tint": "false",
275+ "sound-file": "dummy.ogg",
276+ "suppress-sound": "true"},
272 summary: "New comment successfully published",
277 summary: "New comment successfully published",
273 body: "",
278 body: "",
274 icon: "",
279 icon: "",
@@ -282,12 +287,14 @@ Row {
282 nonShapedIcon: false,
287 nonShapedIcon: false,
283 secondaryIconVisible: true,
288 secondaryIconVisible: true,
284 buttonRowVisible: false,
289 buttonRowVisible: false,
285− buttonTinted: false
290+ buttonTinted: false,
291+ hasSound: false
286 },
292 },
287 {
293 {
288 tag: "Interactive notification",
294 tag: "Interactive notification",
289 type: Notification.Interactive,
295 type: Notification.Interactive,
290− hints: {"x-canonical-private-button-tint": "false"},
296+ hints: {"x-canonical-private-button-tint": "false",
297+ "sound-file": "dummy.ogg"},
291 summary: "Interactive notification",
298 summary: "Interactive notification",
292 body: "This is a notification that can be clicked",
299 body: "This is a notification that can be clicked",
293 icon: "../graphics/avatars/amanda.png",
300 icon: "../graphics/avatars/amanda.png",
@@ -300,12 +307,14 @@ Row {
300 nonShapedIcon: false,
307 nonShapedIcon: false,
301 secondaryIconVisible: false,
308 secondaryIconVisible: false,
302 buttonRowVisible: false,
309 buttonRowVisible: false,
303− buttonTinted: false
310+ buttonTinted: false,
311+ hasSound: true
304 },
312 },
305 {
313 {
306 tag: "Snap Decision without secondary icon and no button-tint",
314 tag: "Snap Decision without secondary icon and no button-tint",
307 type: Notification.SnapDecision,
315 type: Notification.SnapDecision,
308− hints: {"x-canonical-private-button-tint": "false"},
316+ hints: {"x-canonical-private-button-tint": "false",
317+ "sound-file": "dummy.ogg"},
309 summary: "Bro Coly",
318 summary: "Bro Coly",
310 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.",
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.",
311 icon: "../graphics/avatars/anna_olsson.png",
320 icon: "../graphics/avatars/anna_olsson.png",
@@ -319,12 +328,14 @@ Row {
319 nonShapedIcon: false,
328 nonShapedIcon: false,
320 secondaryIconVisible: false,
329 secondaryIconVisible: false,
321 buttonRowVisible: true,
330 buttonRowVisible: true,
322− buttonTinted: false
331+ buttonTinted: false,
332+ hasSound: true
323 },
333 },
324 {
334 {
325 tag: "Ephemeral notification",
335 tag: "Ephemeral notification",
326 type: Notification.Ephemeral,
336 type: Notification.Ephemeral,
327− hints: {"x-canonical-private-button-tint": "false"},
337+ hints: {"x-canonical-private-button-tint": "false",
338+ "sound-file": "dummy.ogg"},
328 summary: "Cole Raby",
339 summary: "Cole Raby",
329 body: "I did not expect it to be that late.",
340 body: "I did not expect it to be that late.",
330 icon: "../graphics/avatars/funky.png",
341 icon: "../graphics/avatars/funky.png",
@@ -337,13 +348,15 @@ Row {
337 nonShapedIcon: false,
348 nonShapedIcon: false,
338 secondaryIconVisible: true,
349 secondaryIconVisible: true,
339 buttonRowVisible: false,
350 buttonRowVisible: false,
340− buttonTinted: false
351+ buttonTinted: false,
352+ hasSound: true
341 },
353 },
342 {
354 {
343 tag: "Ephemeral notification with non-shaped icon",
355 tag: "Ephemeral notification with non-shaped icon",
344 type: Notification.Ephemeral,
356 type: Notification.Ephemeral,
345 hints: {"x-canonical-private-button-tint": "false",
357 hints: {"x-canonical-private-button-tint": "false",
346− "x-canonical-non-shaped-icon": "true"},
358+ "x-canonical-non-shaped-icon": "true",
359+ "sound-file": "dummy.ogg"},
347 summary: "Contacts",
360 summary: "Contacts",
348 body: "Synchronised contacts-database with cloud-storage.",
361 body: "Synchronised contacts-database with cloud-storage.",
349 icon: "../graphics/applicationIcons/contacts-app.png",
362 icon: "../graphics/applicationIcons/contacts-app.png",
@@ -356,7 +369,8 @@ Row {
356 nonShapedIcon: true,
369 nonShapedIcon: true,
357 secondaryIconVisible: false,
370 secondaryIconVisible: false,
358 buttonRowVisible: false,
371 buttonRowVisible: false,
359− buttonTinted: false
372+ buttonTinted: false,
373+ hasSound: true
360 }
374 }
361 ]
375 ]
362 }
376 }
@@ -419,6 +433,9 @@ Row {
419 compare(bodyLabel.visible, data.bodyVisible, "body-text visibility is incorrect")
433 compare(bodyLabel.visible, data.bodyVisible, "body-text visibility is incorrect")
420 compare(buttonRow.visible, data.buttonRowVisible, "button visibility is incorrect")
434 compare(buttonRow.visible, data.buttonRowVisible, "button visibility is incorrect")
421
435
436+ var audioItem = findInvisibleChild(notification, "sound")
437+ tryCompare(audioItem, "playbackState", data.hasSound ? Audio.PlayingState : Audio.StoppedState)
438+
422 if(data.buttonRowVisible) {
439 if(data.buttonRowVisible) {
423 var buttonCancel = findChild(buttonRow, "button1")
440 var buttonCancel = findChild(buttonRow, "button1")
424 var buttonAccept = findChild(buttonRow, "button0")
441 var buttonAccept = findChild(buttonRow, "button0")
tests/qmltests/tst_Shell.qml+1−1
@@ -195,7 +195,7 @@ Item {
195 tryCompare(mainApp, "state", ApplicationInfo.Running);
195 tryCompare(mainApp, "state", ApplicationInfo.Running);
196
196
197 // Try to suspend while proximity is engaged...
197 // Try to suspend while proximity is engaged...
198− Powerd.displayPowerStateChange(Powerd.Off, Powerd.UseProximity);
198+ Powerd.displayPowerStateChange(Powerd.Off, Powerd.Proximity);
199 tryCompare(greeter, "showProgress", 0);
199 tryCompare(greeter, "showProgress", 0);
200
200
201 // Now really suspend
201 // Now really suspend