on xenial help sign in
* No-change rebuild against Qt 5.4.2.
57b5790Josh Arenson
CMakeLists.txt+3
@@ -56,6 +56,8 @@ find_package(Qt5DBus 5.2 REQUIRED)
56find_package(Qt5Concurrent 5.2 REQUIRED)
56find_package(Qt5Concurrent 5.2 REQUIRED)
57find_package(Qt5Sql 5.2 REQUIRED)
57find_package(Qt5Sql 5.2 REQUIRED)
58
58
59+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=6)
60+
59# Standard install paths
61# Standard install paths
60include(GNUInstallDirs)
62include(GNUInstallDirs)
61
63
@@ -111,6 +113,7 @@ set(MOCK_INDICATOR_SERVICE_APP unity-mock-indicator-service)
111include_directories(
113include_directories(
112 ${CMAKE_SOURCE_DIR}/include
114 ${CMAKE_SOURCE_DIR}/include
113 ${CMAKE_BINARY_DIR}/include
115 ${CMAKE_BINARY_DIR}/include
116+ ${APPLICATION_API_INCLUDE_DIRS}
114)
117)
115
118
116# add subdirectories to build
119# add subdirectories to build
data/unity8-dash.desktop.in+1
@@ -7,3 +7,4 @@ Terminal=false
7Icon=
7Icon=
8NoDisplay=true
8NoDisplay=true
9X-Ubuntu-Touch=true
9X-Ubuntu-Touch=true
10+X-Ubuntu-Supported-Orientations=primary
debian/changelog+75
@@ -1,3 +1,78 @@
1+unity8 (8.10+15.10.20150612-0ubuntu2) wily; urgency=medium
2+
3+ * No-change rebuild against Qt 5.4.2.
4+
5+ -- Timo Jyrinki <timo-jyrinki@ubuntu.com> Mon, 15 Jun 2015 12:33:07 +0300
6+
7+unity8 (8.10+15.10.20150612-0ubuntu1) wily; urgency=medium
8+
9+ [ Michał Sawicz ]
10+ * Implement full-shell rotation (LP: #1210199)
11+
12+ [ CI Train Bot ]
13+ * New rebuild forced.
14+ * Resync trunk.
15+
16+ [ Daniel d'Andrada ]
17+ * Implemented autopilot-test and fake-sensors for shell-rotation.
18+
19+ [ Mirco Müller ]
20+ * Implemented autopilot-test and fake-sensors for shell-rotation.
21+
22+ -- CI Train Bot <ci-train-bot@canonical.com> Fri, 12 Jun 2015 16:07:47 +0000
23+
24+unity8 (8.02+15.10.20150603.1-0ubuntu1) wily; urgency=medium
25+
26+ [ CI Train Bot ]
27+ * New rebuild forced.
28+ * Resync trunk.
29+
30+ [ Renato Araujo Oliveira Filho ]
31+ * Set the device led color to green. (LP: #1450894)
32+
33+ -- CI Train Bot <ci-train-bot@canonical.com> Wed, 03 Jun 2015 21:42:35 +0000
34+
35+unity8 (8.02+15.10.20150518.1-0ubuntu1) wily; urgency=medium
36+
37+ [ Albert Astals Cid ]
38+ * Add overrides to override functions
39+ * Implement "rating-edit" preview widget (LP: #1318144)
40+ * Make the DashContent::test_mainNavigation test more stable (LP:
41+ #1450809)
42+ * Use art height as implicitHeight when the header is overlayed and
43+ there's no summary
44+
45+ [ CI Train Bot ]
46+ * New rebuild forced.
47+ * Resync trunk.
48+
49+ [ Daniel d'Andrada ]
50+ * Introducing FloatingFlickable
51+ * Make Ubuntu.Gestures components install TouchRegistry by themselves
52+
53+ [ Michael Terry ]
54+ * Fix a possible crash in our PAM threading code. (LP: #1425362) (LP:
55+ #1425362)
56+ * Fix the lockscreen becoming unresponsive after testing an app on the
57+ device from QtCreator. (LP: #1435364)
58+
59+ [ Nick Dedekind ]
60+ * Fixed desktop stage app focus.
61+ * Fixed issue in laggy indicator autpilot tests (LP: #1446846)
62+
63+ -- CI Train Bot <ci-train-bot@canonical.com> Mon, 18 May 2015 23:04:39 +0000
64+
65+unity8 (8.02+15.04.20150511-0ubuntu1) vivid; urgency=medium
66+
67+ [ Albert Astals Cid ]
68+ * Workarounds for concierge mode.
69+
70+ [ CI Train Bot ]
71+ * New rebuild forced.
72+ * Resync trunk.
73+
74+ -- CI Train Bot <ci-train-bot@canonical.com> Mon, 11 May 2015 08:29:58 +0000
75+
1unity8 (8.02+15.04.20150505-0ubuntu1) vivid; urgency=medium
76unity8 (8.02+15.04.20150505-0ubuntu1) vivid; urgency=medium
2
77
3 [ Albert Astals Cid ]
78 [ Albert Astals Cid ]
debian/control+5−4
@@ -12,6 +12,7 @@ Build-Depends: cmake,
12# append :native to g++-4.9 so we don't try to run armhf g++
12# append :native to g++-4.9 so we don't try to run armhf g++
13# on an x86 CPU for eaxmple, when cross-compiling.
13# on an x86 CPU for eaxmple, when cross-compiling.
14 g++-4.9:native,
14 g++-4.9:native,
15+ libandroid-properties-dev,
15 graphviz,
16 graphviz,
16 gsettings-ubuntu-schemas (>= 0.0.2+14.10.20140815),
17 gsettings-ubuntu-schemas (>= 0.0.2+14.10.20140815),
17 libconnectivity-qt1-dev,
18 libconnectivity-qt1-dev,
@@ -27,7 +28,7 @@ Build-Depends: cmake,
27 libqmenumodel-dev (>= 0.2.9),
28 libqmenumodel-dev (>= 0.2.9),
28 libqt5xmlpatterns5-dev,
29 libqt5xmlpatterns5-dev,
29 libsystemsettings-dev,
30 libsystemsettings-dev,
30− libunity-api-dev (>= 7.96),
31+ libunity-api-dev (>= 7.97),
31 libusermetricsoutput1-dev,
32 libusermetricsoutput1-dev,
32 libxcb1-dev,
33 libxcb1-dev,
33 pkg-config,
34 pkg-config,
@@ -94,7 +95,7 @@ Depends: gsettings-desktop-schemas,
94 qml-module-qtquick-xmllistmodel,
95 qml-module-qtquick-xmllistmodel,
95 qml-module-qtsysteminfo,
96 qml-module-qtsysteminfo,
96 qtdeclarative5-gsettings1.0,
97 qtdeclarative5-gsettings1.0,
97− qtdeclarative5-qtmir-plugin (>= 0.4.4),
98+ qtdeclarative5-qtmir-plugin (>= 0.4.5),
98 qtdeclarative5-ubuntu-telephony0.1,
99 qtdeclarative5-ubuntu-telephony0.1,
99 qtdeclarative5-ubuntu-web-plugin,
100 qtdeclarative5-ubuntu-web-plugin,
100 ubuntu-system-settings,
101 ubuntu-system-settings,
@@ -124,7 +125,7 @@ Depends: qml-module-qtquick-layouts,
124 qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.1.1239) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.1.1239),
125 qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.1.1239) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.1.1239),
125 qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl,
126 qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl,
126 ubuntu-thumbnailer-impl-0,
127 ubuntu-thumbnailer-impl-0,
127− unity-application-impl-4,
128+ unity-application-impl-6,
128 unity-notifications-impl-3,
129 unity-notifications-impl-3,
129 unity-plugin-scopes | unity-scopes-impl,
130 unity-plugin-scopes | unity-scopes-impl,
130 unity-scopes-impl-6,
131 unity-scopes-impl-6,
@@ -168,7 +169,7 @@ Pre-Depends: ${misc:Pre-Depends},
168Depends: ${misc:Depends},
169Depends: ${misc:Depends},
169 ${shlibs:Depends},
170 ${shlibs:Depends},
170Provides: unity-application-impl,
171Provides: unity-application-impl,
171− unity-application-impl-4,
172+ unity-application-impl-6,
172Replaces: unity8-autopilot (<< 8.02+15.04.20150422-0ubuntu1)
173Replaces: unity8-autopilot (<< 8.02+15.04.20150422-0ubuntu1)
173Description: Fake environment for running Unity 8 shell
174Description: Fake environment for running Unity 8 shell
174 Provides fake implementations of some QML modules used by Unity 8 shell
175 Provides fake implementations of some QML modules used by Unity 8 shell
debian/unity8.install+3
@@ -8,6 +8,9 @@ usr/share/applications/unity8.desktop
8usr/share/unity8/Greeter
8usr/share/unity8/Greeter
9usr/share/unity8/Launcher
9usr/share/unity8/Launcher
10usr/share/unity8/Panel
10usr/share/unity8/Panel
11+usr/share/unity8/Rotation
12+usr/share/unity8/DeviceConfiguration.qml
13+usr/share/unity8/OrientedShell.qml
11usr/share/unity8/Shell.qml
14usr/share/unity8/Shell.qml
12usr/share/unity8/Stages
15usr/share/unity8/Stages
13usr/share/unity8/Tutorial
16usr/share/unity8/Tutorial
libs/UbuntuGestures/CandidateInactivityTimer.cpp+7−2
@@ -19,12 +19,12 @@
19namespace UbuntuGestures {
19namespace UbuntuGestures {
20
20
21CandidateInactivityTimer::CandidateInactivityTimer(int touchId, QQuickItem *candidate,
21CandidateInactivityTimer::CandidateInactivityTimer(int touchId, QQuickItem *candidate,
22− AbstractTimerFactory &timerFactory, QObject *parent)
22+ AbstractTimer *timer, QObject *parent)
23 : QObject(parent)
23 : QObject(parent)
24+ , m_timer(timer)
24 , m_touchId(touchId)
25 , m_touchId(touchId)
25 , m_candidate(candidate)
26 , m_candidate(candidate)
26{
27{
27− m_timer = timerFactory.createTimer(this);
28 connect(m_timer, &AbstractTimer::timeout,
28 connect(m_timer, &AbstractTimer::timeout,
29 this, &CandidateInactivityTimer::onTimeout);
29 this, &CandidateInactivityTimer::onTimeout);
30 m_timer->setInterval(durationMs);
30 m_timer->setInterval(durationMs);
@@ -32,6 +32,11 @@ CandidateInactivityTimer::CandidateInactivityTimer(int touchId, QQuickItem *cand
32 m_timer->start();
32 m_timer->start();
33}
33}
34
34
35+CandidateInactivityTimer::~CandidateInactivityTimer()
36+{
37+ delete m_timer;
38+}
39+
35void CandidateInactivityTimer::onTimeout()
40void CandidateInactivityTimer::onTimeout()
36{
41{
37 qWarning("[TouchRegistry] Candidate for touch %d defaulted!", m_touchId);
42 qWarning("[TouchRegistry] Candidate for touch %d defaulted!", m_touchId);
libs/UbuntuGestures/CandidateInactivityTimer.h+3−1
@@ -29,9 +29,11 @@ class UBUNTUGESTURES_EXPORT CandidateInactivityTimer : public QObject {
29 Q_OBJECT
29 Q_OBJECT
30public:
30public:
31 CandidateInactivityTimer(int touchId, QQuickItem *candidate,
31 CandidateInactivityTimer(int touchId, QQuickItem *candidate,
32− AbstractTimerFactory &timerFactory,
32+ AbstractTimer *timer,
33 QObject *parent = nullptr);
33 QObject *parent = nullptr);
34
34
35+ virtual ~CandidateInactivityTimer();
36+
35 const int durationMs = 1000;
37 const int durationMs = 1000;
36
38
37Q_SIGNALS:
39Q_SIGNALS:
libs/UbuntuGestures/Timer.cpp−10
@@ -115,16 +115,6 @@ FakeTimerFactory::FakeTimerFactory()
115 m_timeSource.reset(new FakeTimeSource);
115 m_timeSource.reset(new FakeTimeSource);
116}
116}
117
117
118−FakeTimerFactory::~FakeTimerFactory()
119−{
120− for (int i = 0; i < timers.count(); ++i) {
121− FakeTimer *timer = timers[i].data();
122− if (timer) {
123− delete timer;
124− }
125− }
126−}
127−
128void FakeTimerFactory::updateTime(qint64 targetTime)
118void FakeTimerFactory::updateTime(qint64 targetTime)
129{
119{
130 qint64 minTimeoutTime = targetTime;
120 qint64 minTimeoutTime = targetTime;
libs/UbuntuGestures/Timer.h+1−1
@@ -101,7 +101,7 @@ class UBUNTUGESTURES_EXPORT FakeTimerFactory : public AbstractTimerFactory
101{
101{
102public:
102public:
103 FakeTimerFactory();
103 FakeTimerFactory();
104− virtual ~FakeTimerFactory();
104+ virtual ~FakeTimerFactory() {}
105
105
106 void updateTime(qint64 msecsSinceReference);
106 void updateTime(qint64 msecsSinceReference);
107 QSharedPointer<TimeSource> timeSource() { return m_timeSource; }
107 QSharedPointer<TimeSource> timeSource() { return m_timeSource; }
libs/UbuntuGestures/TouchRegistry.cpp+16−12
@@ -41,20 +41,10 @@ using namespace UbuntuGestures;
41TouchRegistry *TouchRegistry::m_instance = nullptr;
41TouchRegistry *TouchRegistry::m_instance = nullptr;
42
42
43TouchRegistry::TouchRegistry(QObject *parent)
43TouchRegistry::TouchRegistry(QObject *parent)
44− : TouchRegistry(parent, new TimerFactory)
45−{
46−}
47−
48−TouchRegistry::TouchRegistry(QObject *parent, AbstractTimerFactory *timerFactory)
49 : QObject(parent)
44 : QObject(parent)
50 , m_inDispatchLoop(false)
45 , m_inDispatchLoop(false)
51− , m_timerFactory(timerFactory)
46+ , m_timerFactory(new TimerFactory)
52{
47{
53− if (m_instance == nullptr) {
54− m_instance = this;
55− } else {
56− qFatal("Cannot have more than one instance of TouchRegistry. It must be a singleton.");
57− }
58}
48}
59
49
60TouchRegistry::~TouchRegistry()
50TouchRegistry::~TouchRegistry()
@@ -64,6 +54,20 @@ TouchRegistry::~TouchRegistry()
64 delete m_timerFactory;
54 delete m_timerFactory;
65}
55}
66
56
57+TouchRegistry *TouchRegistry::instance()
58+{
59+ if (m_instance == nullptr) {
60+ m_instance = new TouchRegistry;
61+ }
62+ return m_instance;
63+}
64+
65+void TouchRegistry::setTimerFactory(AbstractTimerFactory *timerFactory)
66+{
67+ delete m_timerFactory;
68+ m_timerFactory = timerFactory;
69+}
70+
67void TouchRegistry::update(const QTouchEvent *event)
71void TouchRegistry::update(const QTouchEvent *event)
68{
72{
69 #if TOUCHREGISTRY_DEBUG
73 #if TOUCHREGISTRY_DEBUG
@@ -261,7 +265,7 @@ void TouchRegistry::addCandidateOwnerForTouch(int id, QQuickItem *candidate)
261 candidateInfo.state = CandidateInfo::Undecided;
265 candidateInfo.state = CandidateInfo::Undecided;
262 candidateInfo.item = candidate;
266 candidateInfo.item = candidate;
263 candidateInfo.inactivityTimer = new CandidateInactivityTimer(id, candidate,
267 candidateInfo.inactivityTimer = new CandidateInactivityTimer(id, candidate,
264− *m_timerFactory,
268+ m_timerFactory->createTimer(),
265 this);
269 this);
266 connect(candidateInfo.inactivityTimer, &CandidateInactivityTimer::candidateDefaulted,
270 connect(candidateInfo.inactivityTimer, &CandidateInactivityTimer::candidateDefaulted,
267 this, &TouchRegistry::rejectCandidateOwnerForTouch);
271 this, &TouchRegistry::rejectCandidateOwnerForTouch);
libs/UbuntuGestures/TouchRegistry.h+8−6
@@ -25,6 +25,7 @@
25
25
26#include "UbuntuGesturesGlobal.h"
26#include "UbuntuGesturesGlobal.h"
27#include "CandidateInactivityTimer.h"
27#include "CandidateInactivityTimer.h"
28+#include "Timer.h"
28#include "Pool.h"
29#include "Pool.h"
29
30
30namespace UbuntuGestures {
31namespace UbuntuGestures {
@@ -93,15 +94,10 @@ class UBUNTUGESTURES_EXPORT TouchRegistry : public QObject
93{
94{
94 Q_OBJECT
95 Q_OBJECT
95public:
96public:
96− TouchRegistry(QObject *parent = nullptr);
97− // Useful for tests, where you should feed a fake timer
98− TouchRegistry(QObject *parent, UbuntuGestures::AbstractTimerFactory *timerFactory);
99−
100 virtual ~TouchRegistry();
97 virtual ~TouchRegistry();
101
98
102 // Returns a pointer to the application's TouchRegistry instance.
99 // Returns a pointer to the application's TouchRegistry instance.
103− // If no instance has been allocated, null is returned.
104− static TouchRegistry *instance() { return m_instance; }
100+ static TouchRegistry *instance();
105
101
106 void update(const QTouchEvent *event);
102 void update(const QTouchEvent *event);
107
103
@@ -128,10 +124,16 @@ public:
128 // but would nonetheless like to be kept up-to-date on its state.
124 // but would nonetheless like to be kept up-to-date on its state.
129 void addTouchWatcher(int touchId, QQuickItem *watcherItem);
125 void addTouchWatcher(int touchId, QQuickItem *watcherItem);
130
126
127+ // Useful for tests, where you should use fake timers
128+ void setTimerFactory(UbuntuGestures::AbstractTimerFactory *timerFactory);
129+
131private Q_SLOTS:
130private Q_SLOTS:
132 void rejectCandidateOwnerForTouch(int id, QQuickItem *candidate);
131 void rejectCandidateOwnerForTouch(int id, QQuickItem *candidate);
133
132
134private:
133private:
134+ // Only instance() can cronstruct one
135+ TouchRegistry(QObject *parent = nullptr);
136+
135 class CandidateInfo {
137 class CandidateInfo {
136 public:
138 public:
137 enum {
139 enum {
plugins/AccountsService/plugin.h+1−1
@@ -28,7 +28,7 @@ class AccountsServicePlugin : public QQmlExtensionPlugin
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
29
29
30public:
30public:
31− void registerTypes(const char *uri);
31+ void registerTypes(const char *uri) override;
32};
32};
33
33
34#endif
34#endif
plugins/Dash/CardCreator.js+20−5
@@ -64,11 +64,26 @@ var kArtShapeHolderCode = 'Item { \n\
64 active: cardData && cardData["art"] || false; \n\
64 active: cardData && cardData["art"] || false; \n\
65 asynchronous: root.asynchronous; \n\
65 asynchronous: root.asynchronous; \n\
66 visible: status == Loader.Ready; \n\
66 visible: status == Loader.Ready; \n\
67− sourceComponent: UbuntuShape { \n\
67+ sourceComponent: Item { \n\
68 id: artShape; \n\
68 id: artShape; \n\
69 objectName: "artShape"; \n\
69 objectName: "artShape"; \n\
70− radius: "medium"; \n\
70+ property bool doShapeItem: components["art"]["conciergeMode"] !== true; \n\
71 visible: image.status == Image.Ready; \n\
71 visible: image.status == Image.Ready; \n\
72+ readonly property alias image: artImage.image; \n\
73+ ShaderEffectSource { \n\
74+ id: artShapeSource; \n\
75+ sourceItem: artImage; \n\
76+ anchors.centerIn: parent; \n\
77+ width: 1; \n\
78+ height: 1; \n\
79+ hideSource: doShapeItem; \n\
80+ } \n\
81+ Shape { \n\
82+ image: artShapeSource; \n\
83+ anchors.fill: parent; \n\
84+ visible: doShapeItem; \n\
85+ radius: "medium"; \n\
86+ } \n\
72 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1; \n\
87 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1; \n\
73 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1; \n\
88 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1; \n\
74 Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; } \n\
89 Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; } \n\
@@ -87,11 +102,9 @@ var kArtShapeHolderCode = 'Item { \n\
87 objectName: "artImage"; \n\
102 objectName: "artImage"; \n\
88 source: cardData && cardData["art"] || ""; \n\
103 source: cardData && cardData["art"] || ""; \n\
89 asynchronous: root.asynchronous; \n\
104 asynchronous: root.asynchronous; \n\
90− visible: false; \n\
91 width: %2; \n\
105 width: %2; \n\
92 height: %3; \n\
106 height: %3; \n\
93 } \n\
107 } \n\
94− image: artImage.image; \n\
95 } \n\
108 } \n\
96 } \n\
109 } \n\
97 }\n';
110 }\n';
@@ -322,7 +335,7 @@ function cardString(template, components) {
322
335
323 var hasArt = components["art"] && components["art"]["field"] || false;
336 var hasArt = components["art"] && components["art"]["field"] || false;
324 var hasSummary = components["summary"] || false;
337 var hasSummary = components["summary"] || false;
325− var artAndSummary = hasArt && hasSummary;
338+ var artAndSummary = hasArt && hasSummary && components["art"]["conciergeMode"] !== true;
326 var isHorizontal = template["card-layout"] === "horizontal";
339 var isHorizontal = template["card-layout"] === "horizontal";
327 var hasBackground = (!isHorizontal && (template["card-background"] || components["background"] || artAndSummary)) ||
340 var hasBackground = (!isHorizontal && (template["card-background"] || components["background"] || artAndSummary)) ||
328 (hasSummary && (template["card-background"] || components["background"]));
341 (hasSummary && (template["card-background"] || components["background"]));
@@ -631,6 +644,8 @@ function cardString(template, components) {
631 var implicitHeight = 'implicitHeight: ';
644 var implicitHeight = 'implicitHeight: ';
632 if (hasSummary) {
645 if (hasSummary) {
633 implicitHeight += 'summary.y + summary.height + units.gu(1);\n';
646 implicitHeight += 'summary.y + summary.height + units.gu(1);\n';
647+ } else if (headerAsOverlay) {
648+ implicitHeight += 'artShapeHolder.height;\n';
634 } else if (hasHeaderRow) {
649 } else if (hasHeaderRow) {
635 implicitHeight += 'row.y + row.height + units.gu(1);\n';
650 implicitHeight += 'row.y + row.height + units.gu(1);\n';
636 } else if (hasMascot) {
651 } else if (hasMascot) {
plugins/Dash/plugin.h+1−1
@@ -27,7 +27,7 @@ class DashPlugin : public QQmlExtensionPlugin
27 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
27 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28
28
29public:
29public:
30− void registerTypes(const char *uri);
30+ void registerTypes(const char *uri) override;
31};
31};
32
32
33#endif
33#endif
plugins/Greeter/Unity/Launcher/CMakeLists.txt+1−1
@@ -1,5 +1,5 @@
1pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
1pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
2−pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=5)
2+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=6)
3pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
3pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
4
4
5add_definitions(-DSM_BUSNAME=systemBus)
5add_definitions(-DSM_BUSNAME=systemBus)
plugins/Greeter/Unity/Launcher/launchermodelas.h+9−9
@@ -37,19 +37,19 @@ public:
37 LauncherModel(QObject *parent = 0);
37 LauncherModel(QObject *parent = 0);
38 ~LauncherModel();
38 ~LauncherModel();
39
39
40− int rowCount(const QModelIndex &parent = QModelIndex()) const;
40+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
41
41
42− QVariant data(const QModelIndex &index, int role) const;
42+ QVariant data(const QModelIndex &index, int role) const override;
43
43
44− Q_INVOKABLE unity::shell::launcher::LauncherItemInterface* get(int index) const;
44+ Q_INVOKABLE unity::shell::launcher::LauncherItemInterface* get(int index) const override;
45− Q_INVOKABLE void move(int oldIndex, int newIndex);
45+ Q_INVOKABLE void move(int oldIndex, int newIndex) override;
46− Q_INVOKABLE void pin(const QString &appId, int index = -1);
46+ Q_INVOKABLE void pin(const QString &appId, int index = -1) override;
47− Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex);
47+ Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex) override;
48− Q_INVOKABLE void setUser(const QString &username);
48+ Q_INVOKABLE void setUser(const QString &username) override;
49 Q_INVOKABLE QString getUrlForAppId(const QString &appId) const;
49 Q_INVOKABLE QString getUrlForAppId(const QString &appId) const;
50
50
51− unity::shell::application::ApplicationManagerInterface* applicationManager() const;
51+ unity::shell::application::ApplicationManagerInterface* applicationManager() const override;
52− void setApplicationManager(unity::shell::application::ApplicationManagerInterface *appManager);
52+ void setApplicationManager(unity::shell::application::ApplicationManagerInterface *appManager) override;
53
53
54 bool onlyPinned() const override;
54 bool onlyPinned() const override;
55 void setOnlyPinned(bool onlyPinned) override;
55 void setOnlyPinned(bool onlyPinned) override;
plugins/Greeter/Unity/Launcher/plugin.h+1−1
@@ -26,7 +26,7 @@ class UnityLauncherPlugin : public QQmlExtensionPlugin
26 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
27
27
28public:
28public:
29− void registerTypes(const char *uri);
29+ void registerTypes(const char *uri) override;
30};
30};
31
31
32#endif
32#endif
plugins/Greeter/Unity/Launcher/quicklistmodel.h+2−2
@@ -45,8 +45,8 @@ public:
45
45
46 QuickListEntry get(int index) const;
46 QuickListEntry get(int index) const;
47
47
48− int rowCount(const QModelIndex &parent = QModelIndex()) const;
48+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
49− QVariant data(const QModelIndex &index, int role) const;
49+ QVariant data(const QModelIndex &index, int role) const override;
50
50
51private:
51private:
52 QList<QuickListEntry> m_list;
52 QList<QuickListEntry> m_list;
plugins/LightDM/UsersModel.cpp+1−1
@@ -32,7 +32,7 @@ class MangleModel : public QSortFilterProxyModel
32public:
32public:
33 explicit MangleModel(QObject* parent=0);
33 explicit MangleModel(QObject* parent=0);
34
34
35− virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
35+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
36};
36};
37
37
38MangleModel::MangleModel(QObject* parent)
38MangleModel::MangleModel(QObject* parent)
plugins/LightDM/liblightdm/GreeterPrivate.cpp+29−5
@@ -56,7 +56,8 @@ public:
56 this, SLOT(handleMessage(pam_handle *, QString, QLightDM::Greeter::MessageType)));
56 this, SLOT(handleMessage(pam_handle *, QString, QLightDM::Greeter::MessageType)));
57 // This next connect is how we pass ResponseFutures between threads
57 // This next connect is how we pass ResponseFutures between threads
58 connect(this, SIGNAL(showPrompt(pam_handle *, QString, QLightDM::Greeter::PromptType, QLightDM::GreeterImpl::ResponseFuture)),
58 connect(this, SIGNAL(showPrompt(pam_handle *, QString, QLightDM::Greeter::PromptType, QLightDM::GreeterImpl::ResponseFuture)),
59− this, SLOT(handlePrompt(pam_handle *, QString, QLightDM::Greeter::PromptType, QLightDM::GreeterImpl::ResponseFuture)));
59+ this, SLOT(handlePrompt(pam_handle *, QString, QLightDM::Greeter::PromptType, QLightDM::GreeterImpl::ResponseFuture)),
60+ Qt::BlockingQueuedConnection);
60 }
61 }
61
62
62 ~GreeterImpl()
63 ~GreeterImpl()
@@ -68,6 +69,13 @@ public:
68 {
69 {
69 // Clear out any existing PAM interactions first
70 // Clear out any existing PAM interactions first
70 cancelPam();
71 cancelPam();
72+ if (pamHandle != nullptr) {
73+ // While we were cancelling pam above, we processed Qt events.
74+ // Which may have allowed someone to call start() on us again.
75+ // In which case, we'll bail on our current start() call.
76+ // This isn't racy because it's all in the same thread.
77+ return;
78+ }
71
79
72 AppData *appData = new AppData();
80 AppData *appData = new AppData();
73 appData->impl = this;
81 appData->impl = this;
@@ -79,7 +87,7 @@ public:
79
87
80 if (pam_start("lightdm", username.toUtf8(), &conversation, &pamHandle) == PAM_SUCCESS) {
88 if (pam_start("lightdm", username.toUtf8(), &conversation, &pamHandle) == PAM_SUCCESS) {
81 appData->handle = pamHandle;
89 appData->handle = pamHandle;
82− futureWatcher.setFuture(QtConcurrent::run(authenticateWithPam, pamHandle));
90+ futureWatcher.setFuture(QtConcurrent::mapped(QList<pam_handle*>() << pamHandle, authenticateWithPam));
83 } else {
91 } else {
84 delete appData;
92 delete appData;
85 greeterPrivate->authenticated = false;
93 greeterPrivate->authenticated = false;
@@ -88,7 +96,7 @@ public:
88 }
96 }
89 }
97 }
90
98
91− static int authenticateWithPam(pam_handle* pamHandle)
99+ static int authenticateWithPam(pam_handle* const& pamHandle)
92 {
100 {
93 int pamStatus = pam_authenticate(pamHandle, 0);
101 int pamStatus = pam_authenticate(pamHandle, 0);
94 if (pamStatus == PAM_SUCCESS) {
102 if (pamStatus == PAM_SUCCESS) {
@@ -242,11 +250,22 @@ private Q_SLOTS:
242private:
250private:
243 void cancelPam()
251 void cancelPam()
244 {
252 {
245− // Unfortunately we can't simply cancel our QFuture because QtConcurrent::run doesn't support cancel
246 if (pamHandle != nullptr) {
253 if (pamHandle != nullptr) {
254+ QFuture<int> pamFuture = futureWatcher.future();
247 pam_handle *handle = pamHandle;
255 pam_handle *handle = pamHandle;
248 pamHandle = nullptr; // to disable normal finishPam() handling
256 pamHandle = nullptr; // to disable normal finishPam() handling
257+ pamFuture.cancel();
258+
259+ // Note the empty loop, we just want to clear the futures queue.
260+ // Any further prompts from the pam thread will be immediately
261+ // responded to/dismissed in handlePrompt().
249− while (respond(QString())); // clear our local queue of QFutures
262+ while (respond(QString()));
263+
264+ // Now let signal/slot handling happen so the thread can finish
265+ while (!pamFuture.isFinished()) {
266+ QCoreApplication::processEvents();
267+ }
268+
250 pam_end(handle, PAM_CONV_ERR);
269 pam_end(handle, PAM_CONV_ERR);
251 }
270 }
252 }
271 }
@@ -266,6 +285,11 @@ GreeterPrivate::GreeterPrivate(Greeter* parent)
266{
285{
267}
286}
268
287
288+GreeterPrivate::~GreeterPrivate()
289+{
290+ delete m_impl;
291+}
292+
269void GreeterPrivate::handleAuthenticate()
293void GreeterPrivate::handleAuthenticate()
270{
294{
271 m_impl->start(authenticationUser);
295 m_impl->start(authenticationUser);
plugins/LightDM/liblightdm/GreeterPrivate.h+1−1
@@ -30,7 +30,7 @@ class GreeterPrivate
30{
30{
31public:
31public:
32 explicit GreeterPrivate(Greeter* parent=0);
32 explicit GreeterPrivate(Greeter* parent=0);
33− virtual ~GreeterPrivate() = default;
33+ virtual ~GreeterPrivate();
34
34
35 // These variables may not be used by all subclasses, that's no problem
35 // These variables may not be used by all subclasses, that's no problem
36 bool authenticated;
36 bool authenticated;
plugins/LightDM/liblightdm/UsersModel.h+2−2
@@ -53,8 +53,8 @@ public:
53 BackgroundPathRole
53 BackgroundPathRole
54 };
54 };
55
55
56− int rowCount(const QModelIndex &parent) const;
56+ int rowCount(const QModelIndex &parent) const override;
57− QVariant data(const QModelIndex &index, int role) const;
57+ QVariant data(const QModelIndex &index, int role) const override;
58
58
59private:
59private:
60 UsersModelPrivate * const d_ptr;
60 UsersModelPrivate * const d_ptr;
plugins/LightDM/plugin.h+1−1
@@ -29,7 +29,7 @@ class LightDMPlugin : public QQmlExtensionPlugin
29 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
29 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
30
30
31public:
31public:
32− void registerTypes(const char *uri);
32+ void registerTypes(const char *uri) override;
33};
33};
34
34
35#endif
35#endif
plugins/Lights/plugin.h+1−1
@@ -28,7 +28,7 @@ class LightsPlugin : public QQmlExtensionPlugin
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
29
29
30public:
30public:
31− void registerTypes(const char *uri);
31+ void registerTypes(const char *uri) override;
32};
32};
33
33
34#endif
34#endif
plugins/Powerd/plugin.h+1−1
@@ -29,7 +29,7 @@ class PowerdPlugin : public QQmlExtensionPlugin
29 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
29 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
30
30
31public:
31public:
32− void registerTypes(const char *uri);
32+ void registerTypes(const char *uri) override;
33};
33};
34
34
35#endif
35#endif
plugins/ScreenGrabber/plugin.h+1−1
@@ -27,7 +27,7 @@ class ScreenGrabberPlugin : public QQmlExtensionPlugin
27 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
27 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28
28
29public:
29public:
30− void registerTypes(const char *uri);
30+ void registerTypes(const char *uri) override;
31};
31};
32
32
33#endif // SCREENGRABBER_PLUGIN_H
33#endif // SCREENGRABBER_PLUGIN_H
plugins/SessionBroadcast/plugin.h+1−1
@@ -27,7 +27,7 @@ class SessionBroadcastPlugin : public QQmlExtensionPlugin
27 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
27 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28
28
29public:
29public:
30− void registerTypes(const char *uri);
30+ void registerTypes(const char *uri) override;
31};
31};
32
32
33#endif
33#endif
plugins/Ubuntu/DownloadDaemonListener/plugin.h+2−2
@@ -31,7 +31,7 @@ class BackendPlugin : public QQmlExtensionPlugin
31 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
31 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
32
32
33public:
33public:
34− void registerTypes(const char *uri);
34+ void registerTypes(const char *uri) override;
35− void initializeEngine(QQmlEngine *engine, const char *uri);
35+ void initializeEngine(QQmlEngine *engine, const char *uri) override;
36};
36};
37#endif // BACKEND_PLUGIN_H
37#endif // BACKEND_PLUGIN_H
plugins/Ubuntu/Gestures/CMakeLists.txt+1
@@ -7,6 +7,7 @@ set(UbuntuGesturesQml_SOURCES
7 Damper.cpp
7 Damper.cpp
8 Direction.cpp
8 Direction.cpp
9 DirectionalDragArea.cpp
9 DirectionalDragArea.cpp
10+ FloatingFlickable.cpp
10 PressedOutsideNotifier.cpp
11 PressedOutsideNotifier.cpp
11 TouchDispatcher.cpp
12 TouchDispatcher.cpp
12 TouchGate.cpp
13 TouchGate.cpp
plugins/Ubuntu/Gestures/Direction.cpp+6−3
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2013 Canonical, Ltd.
2+ * Copyright (C) 2013,2015 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
@@ -25,12 +25,15 @@ bool Direction::isHorizontal(Direction::Type type)
25
25
26bool Direction::isVertical(Direction::Type type)
26bool Direction::isVertical(Direction::Type type)
27{
27{
28− return type == Direction::Upwards || type == Direction::Downwards;
28+ return type == Direction::Upwards
29+ || type == Direction::Downwards
30+ || type == Direction::Vertical;
29}
31}
30
32
31bool Direction::isPositive(Direction::Type type)
33bool Direction::isPositive(Direction::Type type)
32{
34{
33 return type == Rightwards
35 return type == Rightwards
34 || type == Downwards
36 || type == Downwards
35− || type == Horizontal;
37+ || type == Horizontal
38+ || type == Vertical;
36}
39}
plugins/Ubuntu/Gestures/Direction.h+3−2
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2013 Canonical, Ltd.
2+ * Copyright (C) 2013,2015 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
@@ -34,7 +34,8 @@ public:
34 Leftwards, // Along the negative direction of the X axis
34 Leftwards, // Along the negative direction of the X axis
35 Downwards, // Along the positive direction of the Y axis
35 Downwards, // Along the positive direction of the Y axis
36 Upwards, // Along the negative direction of the Y axis
36 Upwards, // Along the negative direction of the Y axis
37− Horizontal // Along the X axis, in any direction
37+ Horizontal, // Along the X axis, in any direction
38+ Vertical // Along the Y axis, in any direction
38 };
39 };
39
40
40 Q_INVOKABLE static bool isHorizontal(Direction::Type type);
41 Q_INVOKABLE static bool isHorizontal(Direction::Type type);
plugins/Ubuntu/Gestures/DirectionalDragArea.cpp+5−2
@@ -506,7 +506,7 @@ const QTouchEvent::TouchPoint *DirectionalDragAreaPrivate::fetchTargetTouchPoint
506
506
507bool DirectionalDragAreaPrivate::movingInRightDirection() const
507bool DirectionalDragAreaPrivate::movingInRightDirection() const
508{
508{
509− if (direction == Direction::Horizontal) {
509+ if (direction == Direction::Horizontal || direction == Direction::Vertical) {
510 return true;
510 return true;
511 } else {
511 } else {
512 QPointF movementVector(dampedScenePos.x() - previousDampedScenePos.x(),
512 QPointF movementVector(dampedScenePos.x() - previousDampedScenePos.x(),
@@ -532,7 +532,7 @@ bool DirectionalDragAreaPrivate::movedFarEnoughAlongGestureAxis() const
532 ddaDebug(" movedFarEnoughAlongGestureAxis: scalarProjection=" << scalarProjection
532 ddaDebug(" movedFarEnoughAlongGestureAxis: scalarProjection=" << scalarProjection
533 << ", distanceThreshold=" << distanceThreshold);
533 << ", distanceThreshold=" << distanceThreshold);
534
534
535− if (direction == Direction::Horizontal) {
535+ if (direction == Direction::Horizontal || direction == Direction::Vertical) {
536 return qAbs(scalarProjection) > distanceThreshold;
536 return qAbs(scalarProjection) > distanceThreshold;
537 } else {
537 } else {
538 return scalarProjection > distanceThreshold;
538 return scalarProjection > distanceThreshold;
@@ -712,6 +712,8 @@ void DirectionalDragArea::itemChange(ItemChange change, const ItemChangeData &va
712{
712{
713 if (change == QQuickItem::ItemSceneChange) {
713 if (change == QQuickItem::ItemSceneChange) {
714 if (value.window != nullptr) {
714 if (value.window != nullptr) {
715+ value.window->installEventFilter(TouchRegistry::instance());
716+
715 // TODO: Handle window->screen() changes (ie window changing screens)
717 // TODO: Handle window->screen() changes (ie window changing screens)
716 qreal pixelsPerMm = value.window->screen()->physicalDotsPerInch() / 25.4;
718 qreal pixelsPerMm = value.window->screen()->physicalDotsPerInch() / 25.4;
717 d->setPixelsPerMm(pixelsPerMm);
719 d->setPixelsPerMm(pixelsPerMm);
@@ -843,6 +845,7 @@ void DirectionalDragAreaPrivate::updateSceneDirectionVector()
843 localDirection.ry() = -1.;
845 localDirection.ry() = -1.;
844 break;
846 break;
845 case Direction::Downwards:
847 case Direction::Downwards:
848+ case Direction::Vertical:
846 localDirection.rx() = 0.;
849 localDirection.rx() = 0.;
847 localDirection.ry() = 1;
850 localDirection.ry() = 1;
848 break;
851 break;
plugins/Ubuntu/Gestures/DirectionalDragArea.h+2−2
@@ -125,8 +125,8 @@ Q_SIGNALS:
125 void immediateRecognitionChanged(bool value);
125 void immediateRecognitionChanged(bool value);
126
126
127protected:
127protected:
128− virtual void touchEvent(QTouchEvent *event);
128+ void touchEvent(QTouchEvent *event) override;
129− virtual void itemChange(ItemChange change, const ItemChangeData &value);
129+ void itemChange(ItemChange change, const ItemChangeData &value) override;
130
130
131public: // so tests can access it
131public: // so tests can access it
132 DirectionalDragAreaPrivate *d;
132 DirectionalDragAreaPrivate *d;
plugins/Ubuntu/Gestures/FloatingFlickable.cppnew file+150
@@ -0,0 +1,150 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "FloatingFlickable.h"
18+
19+#include <private/qquickflickable_p.h>
20+#include "DirectionalDragArea.h"
21+
22+#include <QDebug>
23+
24+FloatingFlickable::FloatingFlickable(QQuickItem *parent)
25+ : QQuickItem(parent)
26+ , m_mousePressed(false)
27+{
28+ m_dragArea = new DirectionalDragArea(this);
29+ m_dragArea->setWidth(width());
30+ m_dragArea->setHeight(height());
31+ m_dragArea->setDirection(Direction::Horizontal);
32+ connect(m_dragArea, &DirectionalDragArea::touchXChanged,
33+ this, &FloatingFlickable::onDragAreaTouchPosChanged);
34+ connect(m_dragArea, &DirectionalDragArea::touchYChanged,
35+ this, &FloatingFlickable::onDragAreaTouchPosChanged);
36+ connect(m_dragArea, &DirectionalDragArea::draggingChanged,
37+ this, &FloatingFlickable::onDragAreaDraggingChanged);
38+ connect(m_dragArea, &DirectionalDragArea::directionChanged, this, &FloatingFlickable::directionChanged);
39+
40+ m_flickable = new QQuickFlickable(this);
41+ m_flickable->setEnabled(false);
42+ m_flickable->setWidth(width());
43+ m_flickable->setHeight(height());
44+ connect(m_flickable, &QQuickFlickable::contentWidthChanged, this, &FloatingFlickable::contentWidthChanged);
45+ connect(m_flickable, &QQuickFlickable::contentHeightChanged, this, &FloatingFlickable::contentHeightChanged);
46+ connect(m_flickable, &QQuickFlickable::contentXChanged, this, &FloatingFlickable::contentXChanged);
47+ connect(m_flickable, &QQuickFlickable::contentYChanged, this, &FloatingFlickable::contentYChanged);
48+
49+ connect(this, &QQuickItem::widthChanged, this, &FloatingFlickable::updateChildrenWidth);
50+ connect(this, &QQuickItem::heightChanged, this, &FloatingFlickable::updateChildrenHeight);
51+}
52+
53+qreal FloatingFlickable::contentWidth() const
54+{
55+ return m_flickable->contentWidth();
56+}
57+
58+void FloatingFlickable::setContentWidth(qreal contentWidth)
59+{
60+ m_flickable->setContentWidth(contentWidth);
61+}
62+
63+qreal FloatingFlickable::contentHeight() const
64+{
65+ return m_flickable->contentHeight();
66+}
67+
68+void FloatingFlickable::setContentHeight(qreal contentHeight)
69+{
70+ m_flickable->setContentHeight(contentHeight);
71+}
72+
73+qreal FloatingFlickable::contentX() const
74+{
75+ return m_flickable->contentX();
76+}
77+
78+void FloatingFlickable::setContentX(qreal contentX)
79+{
80+ m_flickable->setContentX(contentX);
81+}
82+
83+qreal FloatingFlickable::contentY() const
84+{
85+ return m_flickable->contentY();
86+}
87+
88+void FloatingFlickable::setContentY(qreal contentY)
89+{
90+ m_flickable->setContentY(contentY);
91+}
92+
93+Direction::Type FloatingFlickable::direction() const
94+{
95+ return m_dragArea->direction();
96+}
97+
98+void FloatingFlickable::setDirection(Direction::Type direction)
99+{
100+ m_dragArea->setDirection(direction);
101+ if (Direction::isHorizontal(direction)) {
102+ m_flickable->setFlickableDirection(QQuickFlickable::HorizontalFlick);
103+ } else {
104+ m_flickable->setFlickableDirection(QQuickFlickable::VerticalFlick);
105+ }
106+}
107+
108+void FloatingFlickable::updateChildrenWidth()
109+{
110+ m_dragArea->setWidth(width());
111+ m_flickable->setWidth(width());
112+}
113+
114+void FloatingFlickable::updateChildrenHeight()
115+{
116+ m_dragArea->setHeight(height());
117+ m_flickable->setHeight(height());
118+}
119+
120+void FloatingFlickable::onDragAreaTouchPosChanged(qreal)
121+{
122+ if (m_mousePressed) {
123+ QMouseEvent mouseEvent(QEvent::MouseMove,
124+ QPointF(m_dragArea->touchX(),m_dragArea->touchY()),
125+ Qt::NoButton, Qt::LeftButton, Qt::NoModifier);
126+
127+ QCoreApplication::sendEvent(m_flickable, &mouseEvent);
128+
129+ }
130+}
131+
132+void FloatingFlickable::onDragAreaDraggingChanged(bool dragging)
133+{
134+ if (dragging && !m_mousePressed) {
135+ QMouseEvent mouseEvent(QEvent::MouseButtonPress,
136+ QPointF(m_dragArea->touchX(),m_dragArea->touchY()),
137+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
138+
139+ QCoreApplication::sendEvent(m_flickable, &mouseEvent);
140+ m_mousePressed = true;
141+
142+ } else if (!dragging && m_mousePressed) {
143+ QMouseEvent mouseEvent(QEvent::MouseButtonRelease,
144+ QPointF(m_dragArea->touchX(),m_dragArea->touchY()),
145+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
146+
147+ QCoreApplication::sendEvent(m_flickable, &mouseEvent);
148+ m_mousePressed = false;
149+ }
150+}
plugins/Ubuntu/Gestures/FloatingFlickable.hnew file+86
@@ -0,0 +1,86 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef FLOATING_FLICKABLE_H
18+#define FLOATING_FLICKABLE_H
19+
20+#include <QQuickItem>
21+#include "UbuntuGesturesQmlGlobal.h"
22+#include "Direction.h"
23+
24+class DirectionalDragArea;
25+class QQuickFlickable;
26+
27+/*
28+ A Flickable that can be put in front of the item to be flicked and
29+ still have the item-to-be-flicked receive input events that are not flicks.
30+
31+ Ie, it's a Flickable that, input-wise, is transparent to non-flick gestures.
32+
33+ With a regular Flickable you would have to make the item-to-be-flicked a child
34+ of Flicakble to achieve the same result. FloatingFlickable has no such requirement
35+ or limitation.
36+ */
37+class UBUNTUGESTURESQML_EXPORT FloatingFlickable : public QQuickItem {
38+ Q_OBJECT
39+
40+ Q_PROPERTY(qreal contentWidth READ contentWidth WRITE setContentWidth NOTIFY contentWidthChanged)
41+ Q_PROPERTY(qreal contentHeight READ contentHeight WRITE setContentHeight NOTIFY contentHeightChanged)
42+ Q_PROPERTY(qreal contentX READ contentX WRITE setContentX NOTIFY contentXChanged)
43+ Q_PROPERTY(qreal contentY READ contentY WRITE setContentY NOTIFY contentYChanged)
44+
45+ Q_PROPERTY(Direction::Type direction READ direction WRITE setDirection NOTIFY directionChanged)
46+
47+Q_SIGNALS:
48+ void contentWidthChanged();
49+ void contentHeightChanged();
50+ void contentXChanged();
51+ void contentYChanged();
52+ void directionChanged();
53+
54+public:
55+ FloatingFlickable(QQuickItem *parent = nullptr);
56+
57+ qreal contentWidth() const;
58+ void setContentWidth(qreal contentWidth);
59+
60+ qreal contentHeight() const;
61+ void setContentHeight(qreal contentHeight);
62+
63+ qreal contentX() const;
64+ void setContentX(qreal contentX);
65+
66+ qreal contentY() const;
67+ void setContentY(qreal contentY);
68+
69+ Direction::Type direction() const;
70+ void setDirection(Direction::Type);
71+
72+private Q_SLOTS:
73+ void updateChildrenWidth();
74+ void updateChildrenHeight();
75+ void onDragAreaTouchPosChanged(qreal);
76+ void onDragAreaDraggingChanged(bool value);
77+
78+private:
79+ DirectionalDragArea *m_dragArea;
80+ QQuickFlickable *m_flickable;
81+ bool m_mousePressed;
82+
83+ friend class tst_FloatingFlickable;
84+};
85+
86+#endif // FLOATING_FLICKABLE_H
plugins/Ubuntu/Gestures/TouchGate.cpp+10
@@ -18,6 +18,7 @@
18
18
19#include <QCoreApplication>
19#include <QCoreApplication>
20#include <QDebug>
20#include <QDebug>
21+#include <QQuickWindow>
21
22
22#include <TouchOwnershipEvent.h>
23#include <TouchOwnershipEvent.h>
23#include <TouchRegistry.h>
24#include <TouchRegistry.h>
@@ -102,6 +103,15 @@ void TouchGate::touchEvent(QTouchEvent *event)
102 }
103 }
103}
104}
104
105
106+void TouchGate::itemChange(ItemChange change, const ItemChangeData &value)
107+{
108+ if (change == QQuickItem::ItemSceneChange) {
109+ if (value.window != nullptr) {
110+ value.window->installEventFilter(TouchRegistry::instance());
111+ }
112+ }
113+}
114+
105void TouchGate::touchOwnershipEvent(TouchOwnershipEvent *event)
115void TouchGate::touchOwnershipEvent(TouchOwnershipEvent *event)
106{
116{
107 // TODO: Optimization: batch those actions as TouchOwnershipEvents
117 // TODO: Optimization: batch those actions as TouchOwnershipEvents
plugins/Ubuntu/Gestures/TouchGate.h+1
@@ -57,6 +57,7 @@ Q_SIGNALS:
57
57
58protected:
58protected:
59 void touchEvent(QTouchEvent *event) override;
59 void touchEvent(QTouchEvent *event) override;
60+ void itemChange(ItemChange change, const ItemChangeData &value) override;
60
61
61private Q_SLOTS:
62private Q_SLOTS:
62 void onEnabledChanged();
63 void onEnabledChanged();
plugins/Ubuntu/Gestures/plugin.cpp+3−1
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2013 Canonical, Ltd.
2+ * Copyright (C) 2013,2015 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
@@ -18,6 +18,7 @@
18#include "AxisVelocityCalculator.h"
18#include "AxisVelocityCalculator.h"
19#include "Direction.h"
19#include "Direction.h"
20#include "DirectionalDragArea.h"
20#include "DirectionalDragArea.h"
21+#include "FloatingFlickable.h"
21#include "PressedOutsideNotifier.h"
22#include "PressedOutsideNotifier.h"
22#include "TouchGate.h"
23#include "TouchGate.h"
23
24
@@ -34,6 +35,7 @@ void UbuntuGesturesQmlPlugin::registerTypes(const char *uri)
34 qmlRegisterSingletonType<Direction>(uri, 0, 1, "Direction", directionSingleton);
35 qmlRegisterSingletonType<Direction>(uri, 0, 1, "Direction", directionSingleton);
35 qmlRegisterType<DirectionalDragArea>(uri, 0, 1, "DirectionalDragArea");
36 qmlRegisterType<DirectionalDragArea>(uri, 0, 1, "DirectionalDragArea");
36 qmlRegisterType<AxisVelocityCalculator>(uri, 0, 1, "AxisVelocityCalculator");
37 qmlRegisterType<AxisVelocityCalculator>(uri, 0, 1, "AxisVelocityCalculator");
38+ qmlRegisterType<FloatingFlickable>(uri, 0, 1, "FloatingFlickable");
37 qmlRegisterType<PressedOutsideNotifier>(uri, 0, 1, "PressedOutsideNotifier");
39 qmlRegisterType<PressedOutsideNotifier>(uri, 0, 1, "PressedOutsideNotifier");
38 qmlRegisterType<TouchGate>(uri, 0, 1, "TouchGate");
40 qmlRegisterType<TouchGate>(uri, 0, 1, "TouchGate");
39}
41}
plugins/Ubuntu/Gestures/plugin.h+1−1
@@ -24,7 +24,7 @@ class UbuntuGesturesQmlPlugin : public QQmlExtensionPlugin
24 Q_OBJECT
24 Q_OBJECT
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26public:
26public:
27− void registerTypes(const char *uri);
27+ void registerTypes(const char *uri) override;
28};
28};
29
29
30
30
plugins/Ubuntu/Payments/plugin.h+1−1
@@ -25,7 +25,7 @@ class BackendPlugin : public QQmlExtensionPlugin
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26
26
27public:
27public:
28− void registerTypes(const char *uri);
28+ void registerTypes(const char *uri) override;
29};
29};
30
30
31#endif // PAYMENTS_PLUGIN_H
31#endif // PAYMENTS_PLUGIN_H
plugins/Ubuntu/SystemImage/plugin.h+1−1
@@ -25,7 +25,7 @@ class BackendPlugin : public QQmlExtensionPlugin
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26
26
27public:
27public:
28− void registerTypes(const char *uri);
28+ void registerTypes(const char *uri) override;
29};
29};
30
30
31#endif // SYSTEMIMAGE_PLUGIN_H
31#endif // SYSTEMIMAGE_PLUGIN_H
plugins/Unity/Connectivity/plugin.h+1−1
@@ -25,7 +25,7 @@ class BackendPlugin : public QQmlExtensionPlugin
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26
26
27public:
27public:
28− void registerTypes(const char *uri);
28+ void registerTypes(const char *uri) override;
29};
29};
30
30
31#endif // CONNECTIVITY_PLUGIN_H
31#endif // CONNECTIVITY_PLUGIN_H
plugins/Unity/DashCommunicator/plugin.h+1−1
@@ -28,7 +28,7 @@ class DashCommunicatorPlugin : public QQmlExtensionPlugin
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
29
29
30public:
30public:
31− void registerTypes(const char *uri);
31+ void registerTypes(const char *uri) override;
32};
32};
33
33
34#endif
34#endif
plugins/Unity/Indicators/indicatorsmodel.h+5−5
@@ -50,11 +50,11 @@ public:
50 void setProfile(const QString& profile);
50 void setProfile(const QString& profile);
51
51
52 /* QAbstractItemModel */
52 /* QAbstractItemModel */
53− QHash<int, QByteArray> roleNames() const;
53+ QHash<int, QByteArray> roleNames() const override;
54− int columnCount(const QModelIndex &parent = QModelIndex()) const;
54+ int columnCount(const QModelIndex &parent = QModelIndex()) const override;
55− QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
55+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
56− QModelIndex parent (const QModelIndex &index) const;
56+ QModelIndex parent (const QModelIndex &index) const override;
57− int rowCount(const QModelIndex &parent = QModelIndex()) const;
57+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
58
58
59
59
60Q_SIGNALS:
60Q_SIGNALS:
plugins/Unity/Indicators/menucontentactivator.cpp+4−4
@@ -28,10 +28,10 @@ public:
28 connect(&m_timer, &QTimer::timeout,
28 connect(&m_timer, &QTimer::timeout,
29 this, &UnityIndicators::AbstractTimer::timeout);
29 this, &UnityIndicators::AbstractTimer::timeout);
30 }
30 }
31− virtual int interval() const { return m_timer.interval(); }
31+ int interval() const override { return m_timer.interval(); }
32− virtual void setInterval(int msecs) { m_timer.setInterval(msecs); }
32+ void setInterval(int msecs) override { m_timer.setInterval(msecs); }
33− virtual void start() { m_timer.start(); UnityIndicators::AbstractTimer::start(); }
33+ void start() override { m_timer.start(); UnityIndicators::AbstractTimer::start(); }
34− virtual void stop() { m_timer.stop(); UnityIndicators::AbstractTimer::stop(); }
34+ void stop() override { m_timer.stop(); UnityIndicators::AbstractTimer::stop(); }
35private:
35private:
36 QTimer m_timer;
36 QTimer m_timer;
37};
37};
plugins/Unity/Indicators/plugin.h+1−1
@@ -27,7 +27,7 @@ class IndicatorsPlugin : public QQmlExtensionPlugin
27 Q_OBJECT
27 Q_OBJECT
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
29public:
29public:
30− void registerTypes(const char *uri);
30+ void registerTypes(const char *uri) override;
31};
31};
32
32
33#endif // INDICATORS2_PLUGIN_H
33#endif // INDICATORS2_PLUGIN_H
plugins/Unity/Launcher/CMakeLists.txt+1−1
@@ -1,5 +1,5 @@
1pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
1pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
2−pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=5)
2+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=6)
3pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
3pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
4
4
5add_definitions(-DSM_BUSNAME=systemBus)
5add_definitions(-DSM_BUSNAME=systemBus)
plugins/Unity/Launcher/launchermodel.h+10−10
@@ -41,19 +41,19 @@ public:
41 LauncherModel(QObject *parent = 0);
41 LauncherModel(QObject *parent = 0);
42 ~LauncherModel();
42 ~LauncherModel();
43
43
44− int rowCount(const QModelIndex &parent = QModelIndex()) const;
44+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
45
45
46− QVariant data(const QModelIndex &index, int role) const;
46+ QVariant data(const QModelIndex &index, int role) const override;
47
47
48− Q_INVOKABLE unity::shell::launcher::LauncherItemInterface* get(int index) const;
48+ Q_INVOKABLE unity::shell::launcher::LauncherItemInterface* get(int index) const override;
49− Q_INVOKABLE void move(int oldIndex, int newIndex);
49+ Q_INVOKABLE void move(int oldIndex, int newIndex) override;
50− Q_INVOKABLE void pin(const QString &appId, int index = -1);
50+ Q_INVOKABLE void pin(const QString &appId, int index = -1) override;
51− Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex);
51+ Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex) override;
52− Q_INVOKABLE void setUser(const QString &username);
52+ Q_INVOKABLE void setUser(const QString &username) override;
53 Q_INVOKABLE QString getUrlForAppId(const QString &appId) const;
53 Q_INVOKABLE QString getUrlForAppId(const QString &appId) const;
54
54
55− unity::shell::application::ApplicationManagerInterface* applicationManager() const;
55+ unity::shell::application::ApplicationManagerInterface* applicationManager() const override;
56− void setApplicationManager(unity::shell::application::ApplicationManagerInterface *appManager);
56+ void setApplicationManager(unity::shell::application::ApplicationManagerInterface *appManager) override;
57
57
58 bool onlyPinned() const override;
58 bool onlyPinned() const override;
59 void setOnlyPinned(bool onlyPinned) override;
59 void setOnlyPinned(bool onlyPinned) override;
@@ -61,7 +61,7 @@ public:
61 int findApplication(const QString &appId);
61 int findApplication(const QString &appId);
62
62
63public Q_SLOTS:
63public Q_SLOTS:
64− void requestRemove(const QString &appId);
64+ void requestRemove(const QString &appId) override;
65 Q_INVOKABLE void refresh();
65 Q_INVOKABLE void refresh();
66
66
67private:
67private:
plugins/Unity/Launcher/plugin.h+1−1
@@ -28,7 +28,7 @@ class UnityLauncherPlugin : public QQmlExtensionPlugin
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
29
29
30public:
30public:
31− void registerTypes(const char *uri);
31+ void registerTypes(const char *uri) override;
32};
32};
33
33
34#endif
34#endif
plugins/Unity/Launcher/quicklistmodel.h+2−2
@@ -48,8 +48,8 @@ public:
48
48
49 QuickListEntry get(int index) const;
49 QuickListEntry get(int index) const;
50
50
51− int rowCount(const QModelIndex &parent = QModelIndex()) const;
51+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
52− QVariant data(const QModelIndex &index, int role) const;
52+ QVariant data(const QModelIndex &index, int role) const override;
53
53
54private:
54private:
55 QList<QuickListEntry> m_list;
55 QList<QuickListEntry> m_list;
plugins/Unity/Session/plugin.h+1−1
@@ -28,7 +28,7 @@ class SessionPlugin : public QQmlExtensionPlugin
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
29
29
30public:
30public:
31− void registerTypes(const char *uri);
31+ void registerTypes(const char *uri) override;
32};
32};
33
33
34#endif
34#endif
plugins/Utils/CMakeLists.txt+1
@@ -18,6 +18,7 @@ set(QMLPLUGIN_SRC
18 Timer.cpp
18 Timer.cpp
19 unitymenumodelpaths.cpp
19 unitymenumodelpaths.cpp
20 windowkeysfilter.cpp
20 windowkeysfilter.cpp
21+ windowscreenshotprovider.cpp
21 easingcurve.cpp
22 easingcurve.cpp
22 windowstatestorage.cpp
23 windowstatestorage.cpp
23 plugin.cpp
24 plugin.cpp
plugins/Utils/HomeKeyWatcher.h+1−1
@@ -49,7 +49,7 @@ public:
49
49
50 virtual ~HomeKeyWatcher();
50 virtual ~HomeKeyWatcher();
51
51
52− bool eventFilter(QObject *watched, QEvent *event);
52+ bool eventFilter(QObject *watched, QEvent *event) override;
53
53
54 void update(QEvent *event);
54 void update(QEvent *event);
55
55
plugins/Utils/plugin.cpp+4−1
@@ -23,6 +23,7 @@
23#include "plugin.h"
23#include "plugin.h"
24
24
25// local
25// local
26+#include "easingcurve.h"
26#include "HomeKeyWatcher.h"
27#include "HomeKeyWatcher.h"
27#include "inputwatcher.h"
28#include "inputwatcher.h"
28#include "qlimitproxymodelqml.h"
29#include "qlimitproxymodelqml.h"
@@ -31,7 +32,7 @@
31#include "timeformatter.h"
32#include "timeformatter.h"
32#include "unitymenumodelpaths.h"
33#include "unitymenumodelpaths.h"
33#include "windowkeysfilter.h"
34#include "windowkeysfilter.h"
34−#include "easingcurve.h"
35+#include "windowscreenshotprovider.h"
35#include "windowstatestorage.h"
36#include "windowstatestorage.h"
36#include "constants.h"
37#include "constants.h"
37
38
@@ -70,4 +71,6 @@ void UtilsPlugin::registerTypes(const char *uri)
70void UtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
71void UtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
71{
72{
72 QQmlExtensionPlugin::initializeEngine(engine, uri);
73 QQmlExtensionPlugin::initializeEngine(engine, uri);
74+
75+ engine->addImageProvider(QLatin1String("window"), new WindowScreenshotProvider);
73}
76}
plugins/Utils/plugin.h+2−2
@@ -28,8 +28,8 @@ class UtilsPlugin : public QQmlExtensionPlugin
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
29
29
30public:
30public:
31− void registerTypes(const char *uri);
31+ void registerTypes(const char *uri) override;
32− void initializeEngine(QQmlEngine *engine, const char *uri);
32+ void initializeEngine(QQmlEngine *engine, const char *uri) override;
33};
33};
34
34
35#endif
35#endif
plugins/Utils/qlimitproxymodelqml.h+2−2
@@ -32,8 +32,8 @@ public:
32
32
33 /* getters */
33 /* getters */
34 int limit() const;
34 int limit() const;
35− int rowCount(const QModelIndex &parent = QModelIndex()) const;
35+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
36− QHash<int, QByteArray> roleNames() const;
36+ QHash<int, QByteArray> roleNames() const override;
37
37
38 /* setters */
38 /* setters */
39 void setModel(QAbstractItemModel *model);
39 void setModel(QAbstractItemModel *model);
plugins/Utils/qvariantlistmodel.h+6−6
@@ -54,14 +54,14 @@ public:
54
54
55 ~QVariantListModel();
55 ~QVariantListModel();
56
56
57− int rowCount(const QModelIndex &parent = QModelIndex()) const;
57+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
58− QModelIndex sibling(int row, int column, const QModelIndex &idx) const;
58+ QModelIndex sibling(int row, int column, const QModelIndex &idx) const override;
59
59
60− QVariant data(const QModelIndex &index, int role) const;
60+ QVariant data(const QModelIndex &index, int role) const override;
61− bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
61+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
62
62
63− bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex());
63+ bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
64− bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
64+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
65
65
66 QVariantList variantList() const;
66 QVariantList variantList() const;
67 void setVariantList(const QVariantList &list);
67 void setVariantList(const QVariantList &list);
plugins/Utils/timeformatter.h+1−1
@@ -62,7 +62,7 @@ public:
62 GDateTimeFormatter(QObject *parent = 0);
62 GDateTimeFormatter(QObject *parent = 0);
63
63
64protected:
64protected:
65− virtual QString formatTime() const;
65+ QString formatTime() const override;
66};
66};
67
67
68#endif
68#endif
plugins/Utils/unitysortfilterproxymodelqml.h+2−2
@@ -36,12 +36,12 @@ public:
36 Q_INVOKABLE int count();
36 Q_INVOKABLE int count();
37 Q_INVOKABLE int findFirst(int role, const QVariant& value) const;
37 Q_INVOKABLE int findFirst(int role, const QVariant& value) const;
38 Q_INVOKABLE int mapRowToSource(int row);
38 Q_INVOKABLE int mapRowToSource(int row);
39− virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
39+ bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
40
40
41 /* getters */
41 /* getters */
42 int totalCount() const;
42 int totalCount() const;
43 bool invertMatch() const;
43 bool invertMatch() const;
44− QHash<int, QByteArray> roleNames() const;
44+ QHash<int, QByteArray> roleNames() const override;
45
45
46 /* setters */
46 /* setters */
47 void setModel(QAbstractItemModel *model);
47 void setModel(QAbstractItemModel *model);
plugins/Utils/windowkeysfilter.h+1−1
@@ -39,7 +39,7 @@ class WindowKeysFilter : public QQuickItem
39public:
39public:
40 WindowKeysFilter(QQuickItem *parent = 0);
40 WindowKeysFilter(QQuickItem *parent = 0);
41
41
42− bool eventFilter(QObject *watched, QEvent *event);
42+ bool eventFilter(QObject *watched, QEvent *event) override;
43
43
44private Q_SLOTS:
44private Q_SLOTS:
45 void setupFilterOnWindow(QQuickWindow *window);
45 void setupFilterOnWindow(QQuickWindow *window);
plugins/Utils/windowscreenshotprovider.cppnew file+59
@@ -0,0 +1,59 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "windowscreenshotprovider.h"
18+
19+#include <QGuiApplication>
20+#include <QQuickWindow>
21+
22+WindowScreenshotProvider::WindowScreenshotProvider()
23+ : QQuickImageProvider(QQmlImageProviderBase::Image, 0)
24+{
25+}
26+
27+// A very simple implementation where we assume that there's only one window and that it's a
28+// QQuickWindow. Thus the id parameter is irrelevant.
29+//
30+// Idea: Make the id contain the objectName of the QQuickWindow once we care about a multi-display
31+// compositor?
32+// Strictly speaking that could be the actual QWindow::winId(), but that's mostly a
33+// meaningless arbitrary number.
34+QImage WindowScreenshotProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
35+{
36+ Q_UNUSED(id);
37+ Q_UNUSED(requestedSize);
38+
39+ QWindowList windows = QGuiApplication::topLevelWindows();
40+
41+ if (windows.count() != 1) {
42+ size->rwidth() = 0;
43+ size->rheight() = 0;
44+ return QImage();
45+ }
46+
47+ QQuickWindow *quickWindow = qobject_cast<QQuickWindow *>(windows[0]);
48+
49+ if (!quickWindow) {
50+ size->rwidth() = 0;
51+ size->rheight() = 0;
52+ return QImage();
53+ }
54+
55+ QImage image = quickWindow->grabWindow();
56+ size->rwidth() = image.width();
57+ size->rheight() = image.height();
58+ return image;
59+}
plugins/Utils/windowscreenshotprovider.hnew file+31
@@ -0,0 +1,31 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef WINDOW_SCREENSHOT_PROVIDER_H_
18+#define WINDOW_SCREENSHOT_PROVIDER_H_
19+
20+#include <QQuickImageProvider>
21+
22+class WindowScreenshotProvider : public QQuickImageProvider
23+{
24+public:
25+ WindowScreenshotProvider();
26+
27+ // id is ignored for now
28+ QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override;
29+};
30+
31+#endif // WINDOW_SCREENSHOT_PROVIDER_H_
plugins/Wizard/plugin.h+1−1
@@ -26,7 +26,7 @@ class WizardPlugin : public QQmlExtensionPlugin
26 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
27
27
28public:
28public:
29− void registerTypes(const char *uri);
29+ void registerTypes(const char *uri) override;
30};
30};
31
31
32#endif
32#endif
po/am.po+4−4
@@ -8,15 +8,15 @@ 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: 2015-04-14 16:13+0200\n"
10"POT-Creation-Date: 2015-04-14 16:13+0200\n"
11−"PO-Revision-Date: 2015-03-19 23:16+0000\n"
11+"PO-Revision-Date: 2015-05-24 14:07+0000\n"
12"Last-Translator: samson <Unknown>\n"
12"Last-Translator: samson <Unknown>\n"
13"Language-Team: Amharic <am@li.org>\n"
13"Language-Team: Amharic <am@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"Plural-Forms: nplurals=2; plural=n > 1;\n"
17"Plural-Forms: nplurals=2; plural=n > 1;\n"
18−"X-Launchpad-Export-Date: 2015-04-23 06:47+0000\n"
18+"X-Launchpad-Export-Date: 2015-05-25 06:04+0000\n"
19−"X-Generator: Launchpad (build 17430)\n"
19+"X-Generator: Launchpad (build 17514)\n"
20
20
21#: plugins/LightDM/Greeter.cpp:112
21#: plugins/LightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
@@ -371,7 +371,7 @@ msgstr "እዚህ መታ ይድርጉ ለመቀጠል"
371
371
372#: qml/Tutorial/TutorialContent.qml:81
372#: qml/Tutorial/TutorialContent.qml:81
373msgid "Click here to finish."
373msgid "Click here to finish."
374−msgstr ""
374+msgstr "ለመጨረስ እዚህ ይጫኑ"
375
375
376#: qml/Tutorial/TutorialLeftFinish.qml:24
376#: qml/Tutorial/TutorialLeftFinish.qml:24
377msgid "These are the shortcuts to favorite apps"
377msgid "These are the shortcuts to favorite apps"
po/ast.po+86−86
@@ -8,15 +8,15 @@ 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: 2015-04-14 16:13+0200\n"
10"POT-Creation-Date: 2015-04-14 16:13+0200\n"
11−"PO-Revision-Date: 2015-03-02 18:12+0000\n"
11+"PO-Revision-Date: 2015-06-11 23:39+0000\n"
12−"Last-Translator: ivarela <ivarela@ubuntu.com>\n"
12+"Last-Translator: enolp <enolp@softastur.org>\n"
13"Language-Team: Asturian <ast@li.org>\n"
13"Language-Team: Asturian <ast@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"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-04-23 06:48+0000\n"
18+"X-Launchpad-Export-Date: 2015-06-13 05:48+0000\n"
19−"X-Generator: Launchpad (build 17430)\n"
19+"X-Generator: Launchpad (build 17557)\n"
20
20
21#: plugins/LightDM/Greeter.cpp:112
21#: plugins/LightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
@@ -25,11 +25,11 @@ msgstr "Contraseña: "
25#: plugins/Unity/Launcher/launcheritem.cpp:45
25#: plugins/Unity/Launcher/launcheritem.cpp:45
26#: plugins/Unity/Launcher/launcheritem.cpp:100
26#: plugins/Unity/Launcher/launcheritem.cpp:100
27msgid "Pin shortcut"
27msgid "Pin shortcut"
28−msgstr "Anclar"
28+msgstr "Anclar atayu"
29
29
30#: plugins/Unity/Launcher/launcheritem.cpp:100
30#: plugins/Unity/Launcher/launcheritem.cpp:100
31msgid "Unpin shortcut"
31msgid "Unpin shortcut"
32−msgstr "Desanclar"
32+msgstr "Desanclar atayu"
33
33
34#: qml/Components/DelayedLockscreen.qml:49
34#: qml/Components/DelayedLockscreen.qml:49
35msgid "Device Locked"
35msgid "Device Locked"
@@ -37,7 +37,7 @@ msgstr "Preséu bloquiáu"
37
37
38#: qml/Components/DelayedLockscreen.qml:64
38#: qml/Components/DelayedLockscreen.qml:64
39msgid "You have been locked out due to too many failed passphrase attempts."
39msgid "You have been locked out due to too many failed passphrase attempts."
40−msgstr "Quedasti bloquiáu polos escesivos intentos fallíos de frase de pasu."
40+msgstr "Quedasti bloquiáu polos escesivos intentos fallíos de fras de pasu."
41
41
42#: qml/Components/DelayedLockscreen.qml:65
42#: qml/Components/DelayedLockscreen.qml:65
43msgid "You have been locked out due to too many failed passcode attempts."
43msgid "You have been locked out due to too many failed passcode attempts."
@@ -48,27 +48,27 @@ msgstr ""
48#, qt-format
48#, qt-format
49msgid "Please wait %1 minute and then try again…"
49msgid "Please wait %1 minute and then try again…"
50msgid_plural "Please wait %1 minutes and then try again…"
50msgid_plural "Please wait %1 minutes and then try again…"
51−msgstr[0] "Espera %1 minutu y vuelvi a intentalo…"
51+msgstr[0] "Por favor, espera %1 minutu y vuelvi a intentalo…"
52−msgstr[1] "Espera %1 minutos y vuelvi a intentalo…"
52+msgstr[1] "Por favor, espera %1 minutos y vuelvi a intentalo…"
53
53
54#: qml/Components/Dialogs.qml:69
54#: qml/Components/Dialogs.qml:69
55msgctxt "Title: Lock/Log out dialog"
55msgctxt "Title: Lock/Log out dialog"
56msgid "Log out"
56msgid "Log out"
57−msgstr ""
57+msgstr "Zarrar sesión"
58
58
59#: qml/Components/Dialogs.qml:70
59#: qml/Components/Dialogs.qml:70
60msgid "Are you sure you want to log out?"
60msgid "Are you sure you want to log out?"
61−msgstr "De xuru que quies zarrar la sesión?"
61+msgstr "¿De xuru que quies zarrar la sesión?"
62
62
63#: qml/Components/Dialogs.qml:72
63#: qml/Components/Dialogs.qml:72
64msgctxt "Button: Lock the system"
64msgctxt "Button: Lock the system"
65msgid "Lock"
65msgid "Lock"
66−msgstr ""
66+msgstr "Bloquiar"
67
67
68#: qml/Components/Dialogs.qml:79
68#: qml/Components/Dialogs.qml:79
69msgctxt "Button: Log out from the system"
69msgctxt "Button: Log out from the system"
70msgid "Log Out"
70msgid "Log Out"
71−msgstr ""
71+msgstr "Zarrar sesión"
72
72
73#: qml/Components/Dialogs.qml:86 qml/Components/Dialogs.qml:117
73#: qml/Components/Dialogs.qml:86 qml/Components/Dialogs.qml:117
74#: qml/Components/Dialogs.qml:173
74#: qml/Components/Dialogs.qml:173
@@ -78,30 +78,30 @@ msgstr "Encaboxar"
78#: qml/Components/Dialogs.qml:98
78#: qml/Components/Dialogs.qml:98
79msgctxt "Title: Reboot/Shut down dialog"
79msgctxt "Title: Reboot/Shut down dialog"
80msgid "Shut down"
80msgid "Shut down"
81−msgstr ""
81+msgstr "Apagáu"
82
82
83#: qml/Components/Dialogs.qml:99
83#: qml/Components/Dialogs.qml:99
84msgid "Are you sure you want to shut down?"
84msgid "Are you sure you want to shut down?"
85−msgstr "De xuru que quies apagar?"
85+msgstr "¿De xuru que quies apagar?"
86
86
87#: qml/Components/Dialogs.qml:101
87#: qml/Components/Dialogs.qml:101
88msgctxt "Button: Reboot the system"
88msgctxt "Button: Reboot the system"
89msgid "Reboot"
89msgid "Reboot"
90−msgstr ""
90+msgstr "Reaniciar"
91
91
92#: qml/Components/Dialogs.qml:109
92#: qml/Components/Dialogs.qml:109
93msgctxt "Button: Shut down the system"
93msgctxt "Button: Shut down the system"
94msgid "Shut down"
94msgid "Shut down"
95−msgstr ""
95+msgstr "Apagar"
96
96
97#: qml/Components/Dialogs.qml:129
97#: qml/Components/Dialogs.qml:129
98msgctxt "Title: Reboot dialog"
98msgctxt "Title: Reboot dialog"
99msgid "Reboot"
99msgid "Reboot"
100−msgstr ""
100+msgstr "Reaniciu"
101
101
102#: qml/Components/Dialogs.qml:130
102#: qml/Components/Dialogs.qml:130
103msgid "Are you sure you want to reboot?"
103msgid "Are you sure you want to reboot?"
104−msgstr "De xuru que quies reaniciar?"
104+msgstr "¿De xuru que quies reaniciar?"
105
105
106#: qml/Components/Dialogs.qml:132
106#: qml/Components/Dialogs.qml:132
107msgid "No"
107msgid "No"
@@ -121,18 +121,18 @@ msgid ""
121"Are you sure you would like\n"
121"Are you sure you would like\n"
122"to power off?"
122"to power off?"
123msgstr ""
123msgstr ""
124−"De xuru que quies\n"
124+"¿De xuru que te prestaría\n"
125"apagar?"
125"apagar?"
126
126
127#: qml/Components/Dialogs.qml:155
127#: qml/Components/Dialogs.qml:155
128msgctxt "Button: Power off the system"
128msgctxt "Button: Power off the system"
129msgid "Power off"
129msgid "Power off"
130−msgstr ""
130+msgstr "Apagar"
131
131
132#: qml/Components/Dialogs.qml:164
132#: qml/Components/Dialogs.qml:164
133msgctxt "Button: Restart the system"
133msgctxt "Button: Restart the system"
134msgid "Restart"
134msgid "Restart"
135−msgstr ""
135+msgstr "Reaniciar"
136
136
137#: qml/Components/Lockscreen.qml:245
137#: qml/Components/Lockscreen.qml:245
138msgid "Return to Call"
138msgid "Return to Call"
@@ -157,22 +157,22 @@ msgstr "Ver too"
157#: qml/Dash/GenericScopeView.qml:594
157#: qml/Dash/GenericScopeView.qml:594
158msgctxt "Label: Hint for dash search line edit"
158msgctxt "Label: Hint for dash search line edit"
159msgid "Search"
159msgid "Search"
160−msgstr ""
160+msgstr "Guetar"
161
161
162#: qml/Dash/PageHeader.qml:269
162#: qml/Dash/PageHeader.qml:269
163msgctxt "Button: Open the Ubuntu Store"
163msgctxt "Button: Open the Ubuntu Store"
164msgid "Store"
164msgid "Store"
165−msgstr ""
165+msgstr "Tienda"
166
166
167#: qml/Dash/PageHeader.qml:276
167#: qml/Dash/PageHeader.qml:276
168msgctxt "Button: Start a search in the current dash scope"
168msgctxt "Button: Start a search in the current dash scope"
169msgid "Search"
169msgid "Search"
170−msgstr ""
170+msgstr "Guetar"
171
171
172#: qml/Dash/PageHeader.qml:286
172#: qml/Dash/PageHeader.qml:286
173msgctxt "Button: Show the current dash scope settings"
173msgctxt "Button: Show the current dash scope settings"
174msgid "Settings"
174msgid "Settings"
175−msgstr ""
175+msgstr "Axustes"
176
176
177#: qml/Dash/PageHeader.qml:293
177#: qml/Dash/PageHeader.qml:293
178msgid "Remove from Favorites"
178msgid "Remove from Favorites"
@@ -204,19 +204,19 @@ msgstr "Unviar"
204
204
205#: qml/Dash/PullToRefreshScopeStyle.qml:55
205#: qml/Dash/PullToRefreshScopeStyle.qml:55
206msgid "Pull to refresh…"
206msgid "Pull to refresh…"
207−msgstr "Tirar p'anovar..."
207+msgstr "Tira p'anovar..."
208
208
209#: qml/Dash/PullToRefreshScopeStyle.qml:60
209#: qml/Dash/PullToRefreshScopeStyle.qml:60
210msgid "Release to refresh…"
210msgid "Release to refresh…"
211−msgstr "Soltar p'anovar..."
211+msgstr "Sueltar p'anovar..."
212
212
213#: qml/Dash/ScopeSettings/ScopeSettingBoolean.qml:43
213#: qml/Dash/ScopeSettings/ScopeSettingBoolean.qml:43
214msgid "Enable location data"
214msgid "Enable location data"
215−msgstr "Activar datos de llocalización"
215+msgstr "Habilitar datos d'allugamientu"
216
216
217#: qml/Dash/ScopesList.qml:66
217#: qml/Dash/ScopesList.qml:66
218msgid "Manage"
218msgid "Manage"
219−msgstr "Alministrar"
219+msgstr "Xestionar"
220
220
221#: qml/Dash/ScopesList.qml:112
221#: qml/Dash/ScopesList.qml:112
222msgid "Home"
222msgid "Home"
@@ -232,52 +232,52 @@ msgstr "Desbloquiar"
232
232
233#: qml/Greeter/LoginList.qml:236
233#: qml/Greeter/LoginList.qml:236
234msgid "Retry"
234msgid "Retry"
235−msgstr ""
235+msgstr "Reintentar"
236
236
237#: qml/Greeter/LoginList.qml:237
237#: qml/Greeter/LoginList.qml:237
238msgid "Tap to unlock"
238msgid "Tap to unlock"
239−msgstr ""
239+msgstr "Calca pa desbloquiar"
240
240
241#: qml/Greeter/NarrowView.qml:53 qml/Wizard/Pages/passwd-confirm.qml:53
241#: qml/Greeter/NarrowView.qml:53 qml/Wizard/Pages/passwd-confirm.qml:53
242msgid "Sorry, incorrect passphrase."
242msgid "Sorry, incorrect passphrase."
243−msgstr "Fras de pasu incorreuta"
243+msgstr "Perdón, fras de pasu incorreuta"
244
244
245#: qml/Greeter/NarrowView.qml:54 qml/Wizard/Pages/passwd-confirm.qml:54
245#: qml/Greeter/NarrowView.qml:54 qml/Wizard/Pages/passwd-confirm.qml:54
246msgid "Sorry, incorrect passcode."
246msgid "Sorry, incorrect passcode."
247−msgstr "Códigu de pasu incorreutu"
247+msgstr "Perdón, códigu de pasu incorreutu."
248
248
249#: qml/Greeter/NarrowView.qml:55
249#: qml/Greeter/NarrowView.qml:55
250msgid "This will be your last attempt."
250msgid "This will be your last attempt."
251−msgstr "Esti ye'l caberu intentu."
251+msgstr "Esti sedra'l to caberu intentu"
252
252
253#: qml/Greeter/NarrowView.qml:57
253#: qml/Greeter/NarrowView.qml:57
254msgid ""
254msgid ""
255"If passphrase is entered incorrectly, your phone will conduct a factory "
255"If passphrase is entered incorrectly, your phone will conduct a factory "
256"reset and all personal data will be deleted."
256"reset and all personal data will be deleted."
257msgstr ""
257msgstr ""
258−"Si s'inxerta la fras incorreutamente, el teléfonu va volver a la "
258+"Si s'inxerta la fras de pasu incorreutamente, el to teléfonu va reafitase y "
259−"configuración de fábrica y van perdese tolos datos personales."
259+"van desaniciase tolos datos personales."
260
260
261#: qml/Greeter/NarrowView.qml:58
261#: qml/Greeter/NarrowView.qml:58
262msgid ""
262msgid ""
263"If passcode is entered incorrectly, your phone will conduct a factory reset "
263"If passcode is entered incorrectly, your phone will conduct a factory reset "
264"and all personal data will be deleted."
264"and all personal data will be deleted."
265msgstr ""
265msgstr ""
266−"Si s'inxerta'l códigu incorreutamente, el teléfonu va volver a la "
266+"Si s'inxerta'l códigu de pasu incorreutamente, el to teléfonu va reafitase y "
267−"configuración de fábrica y van perdese tolos datos personales."
267+"van desaniciase tolos datos personales."
268
268
269#: qml/Greeter/NarrowView.qml:115
269#: qml/Greeter/NarrowView.qml:115
270#, qt-format
270#, qt-format
271msgid "Enter %1"
271msgid "Enter %1"
272−msgstr "Escribi %1"
272+msgstr "Introduz %1"
273
273
274#: qml/Greeter/NarrowView.qml:116 qml/Wizard/Pages/passwd-set.qml:60
274#: qml/Greeter/NarrowView.qml:116 qml/Wizard/Pages/passwd-set.qml:60
275msgid "Enter passphrase"
275msgid "Enter passphrase"
276−msgstr "Escribi la frase contraseña"
276+msgstr "Introduz la fras de pasu"
277
277
278#: qml/Greeter/NarrowView.qml:117
278#: qml/Greeter/NarrowView.qml:117
279msgid "Enter passcode"
279msgid "Enter passcode"
280−msgstr "Escribi'l códigu de pasu"
280+msgstr "Introduz el códigu de pasu"
281
281
282#: qml/Greeter/NarrowView.qml:118
282#: qml/Greeter/NarrowView.qml:118
283#, qt-format
283#, qt-format
@@ -290,7 +290,7 @@ msgstr "Sentímoslo, contraseña incorreuta"
290
290
291#: qml/Greeter/NarrowView.qml:120
291#: qml/Greeter/NarrowView.qml:120
292msgid "Please re-enter"
292msgid "Please re-enter"
293−msgstr "Vuelvi a escribila"
293+msgstr "Por favor, reintroduzla"
294
294
295#: qml/Greeter/NarrowView.qml:121
295#: qml/Greeter/NarrowView.qml:121
296msgid "Sorry, incorrect passcode"
296msgid "Sorry, incorrect passcode"
@@ -302,7 +302,7 @@ msgstr "Amosar contraseña"
302
302
303#: qml/Panel/ActiveCallHint.qml:79
303#: qml/Panel/ActiveCallHint.qml:79
304msgid "Tap to return to call..."
304msgid "Tap to return to call..."
305−msgstr "Tocar pa tornar a la llamada..."
305+msgstr "Toca pa tornar a la llamada..."
306
306
307#: qml/Panel/ActiveCallHint.qml:92
307#: qml/Panel/ActiveCallHint.qml:92
308msgid "Conference"
308msgid "Conference"
@@ -310,11 +310,11 @@ msgstr "Conferencia"
310
310
311#: qml/Panel/Indicators/MenuItemFactory.qml:639
311#: qml/Panel/Indicators/MenuItemFactory.qml:639
312msgid "Nothing is playing"
312msgid "Nothing is playing"
313−msgstr "Nun hai nada en reproducción"
313+msgstr "Nun ta reproduciéndose nada"
314
314
315#: qml/Panel/Indicators/MenuItemFactory.qml:787
315#: qml/Panel/Indicators/MenuItemFactory.qml:787
316msgid "In queue…"
316msgid "In queue…"
317−msgstr "N'espera…"
317+msgstr "Na cola..."
318
318
319#: qml/Panel/Indicators/MenuItemFactory.qml:791
319#: qml/Panel/Indicators/MenuItemFactory.qml:791
320msgid "Downloading"
320msgid "Downloading"
@@ -339,7 +339,7 @@ msgstr "Falló, toca pa reintentar"
339#: qml/Panel/Indicators/MessageMenuItemFactory.qml:149
339#: qml/Panel/Indicators/MessageMenuItemFactory.qml:149
340msgctxt "Label: Hint in message indicator line edit"
340msgctxt "Label: Hint in message indicator line edit"
341msgid "Reply"
341msgid "Reply"
342−msgstr ""
342+msgstr "Responder"
343
343
344#: qml/Panel/Indicators/ModemInfoItem.qml:105
344#: qml/Panel/Indicators/ModemInfoItem.qml:105
345msgid "Unlock SIM"
345msgid "Unlock SIM"
@@ -351,7 +351,7 @@ msgstr "Roaming"
351
351
352#: qml/Tutorial/TutorialBottomFinish.qml:24
352#: qml/Tutorial/TutorialBottomFinish.qml:24
353msgid "This action does different things for different apps"
353msgid "This action does different things for different apps"
354−msgstr "Esta aición tiene efeutos distintos en cada aplicación"
354+msgstr "Esta aición fai coses distintes p'aplicaciones estremaes"
355
355
356#: qml/Tutorial/TutorialBottomFinish.qml:25
356#: qml/Tutorial/TutorialBottomFinish.qml:25
357msgid "Tap here to finish."
357msgid "Tap here to finish."
@@ -363,7 +363,7 @@ msgstr "Abrir menús especiales"
363
363
364#: qml/Tutorial/TutorialBottom.qml:29
364#: qml/Tutorial/TutorialBottom.qml:29
365msgid "Swipe up from the bottom edge."
365msgid "Swipe up from the bottom edge."
366−msgstr ""
366+msgstr "Esliza dende'l berbesu d'embaxo."
367
367
368#: qml/Tutorial/TutorialContent.qml:81 qml/Tutorial/TutorialLeftFinish.qml:25
368#: qml/Tutorial/TutorialContent.qml:81 qml/Tutorial/TutorialLeftFinish.qml:25
369#: qml/Tutorial/TutorialRight.qml:144
369#: qml/Tutorial/TutorialRight.qml:144
@@ -372,11 +372,11 @@ msgstr "Toca equí pa siguir."
372
372
373#: qml/Tutorial/TutorialContent.qml:81
373#: qml/Tutorial/TutorialContent.qml:81
374msgid "Click here to finish."
374msgid "Click here to finish."
375−msgstr ""
375+msgstr "Primi equí pa finar."
376
376
377#: qml/Tutorial/TutorialLeftFinish.qml:24
377#: qml/Tutorial/TutorialLeftFinish.qml:24
378msgid "These are the shortcuts to favorite apps"
378msgid "These are the shortcuts to favorite apps"
379−msgstr ""
379+msgstr "Estos son los atayos a les aplicaciones favorites"
380
380
381#: qml/Tutorial/TutorialLeft.qml:26
381#: qml/Tutorial/TutorialLeft.qml:26
382msgid "Open the launcher"
382msgid "Open the launcher"
@@ -384,44 +384,44 @@ msgstr "Abrir el llanzador"
384
384
385#: qml/Tutorial/TutorialLeft.qml:27
385#: qml/Tutorial/TutorialLeft.qml:27
386msgid "Short swipe from the left edge."
386msgid "Short swipe from the left edge."
387−msgstr ""
387+msgstr "Esliza un poco dende'l berbesu esquierdu."
388
388
389#: qml/Tutorial/TutorialPage.qml:178
389#: qml/Tutorial/TutorialPage.qml:178
390msgid "You almost got it!"
390msgid "You almost got it!"
391−msgstr ""
391+msgstr "¡Yá cuasi finamos!"
392
392
393#: qml/Tutorial/TutorialPage.qml:195
393#: qml/Tutorial/TutorialPage.qml:195
394msgid "Try again."
394msgid "Try again."
395−msgstr ""
395+msgstr "Intentar de nueves"
396
396
397#: qml/Tutorial/TutorialRight.qml:31
397#: qml/Tutorial/TutorialRight.qml:31
398msgid "To view open apps"
398msgid "To view open apps"
399−msgstr ""
399+msgstr "Pa ver aplicaciones abiertes"
400
400
401#: qml/Tutorial/TutorialRight.qml:32
401#: qml/Tutorial/TutorialRight.qml:32
402msgid "Long swipe from the right edge."
402msgid "Long swipe from the right edge."
403−msgstr ""
403+msgstr "Eslizamientu llargu dende'l berbesu drechu."
404
404
405#: qml/Tutorial/TutorialRight.qml:122
405#: qml/Tutorial/TutorialRight.qml:122
406msgid "View all your running tasks."
406msgid "View all your running tasks."
407−msgstr ""
407+msgstr "Mira toles tos aplicaciones n'execución."
408
408
409#: qml/Wizard/Page.qml:89
409#: qml/Wizard/Page.qml:89
410msgctxt "Button: Go back one page in the Wizard"
410msgctxt "Button: Go back one page in the Wizard"
411msgid "Back"
411msgid "Back"
412−msgstr ""
412+msgstr "Atrás"
413
413
414#: qml/Wizard/Pages/10-welcome.qml:27
414#: qml/Wizard/Pages/10-welcome.qml:27
415msgid "Hi!"
415msgid "Hi!"
416−msgstr "Hola!"
416+msgstr "¡Hola!"
417
417
418#: qml/Wizard/Pages/10-welcome.qml:44
418#: qml/Wizard/Pages/10-welcome.qml:44
419msgid "Welcome to your Ubuntu phone."
419msgid "Welcome to your Ubuntu phone."
420−msgstr "Dámoste l'acoyida a Ubuntu Phone"
420+msgstr "Bienllegáu/ada al to teléfonu d'Ubuntu"
421
421
422#: qml/Wizard/Pages/10-welcome.qml:52
422#: qml/Wizard/Pages/10-welcome.qml:52
423msgid "Let’s get started."
423msgid "Let’s get started."
424−msgstr "Entamamos."
424+msgstr "Entamemos."
425
425
426#: qml/Wizard/Pages/10-welcome.qml:88 qml/Wizard/Pages/30-passwd-type.qml:128
426#: qml/Wizard/Pages/10-welcome.qml:88 qml/Wizard/Pages/30-passwd-type.qml:128
427#: qml/Wizard/Pages/40-wifi.qml:215 qml/Wizard/Pages/50-location.qml:131
427#: qml/Wizard/Pages/40-wifi.qml:215 qml/Wizard/Pages/50-location.qml:131
@@ -432,7 +432,7 @@ msgstr "Siguir"
432
432
433#: qml/Wizard/Pages/20-sim.qml:25
433#: qml/Wizard/Pages/20-sim.qml:25
434msgid "Add a SIM card and restart your device"
434msgid "Add a SIM card and restart your device"
435−msgstr "Amiesta una tarxeta SIM y reanicia'l preséu"
435+msgstr "Amiesta una tarxeta SIM y reanicia'l to preséu"
436
436
437#: qml/Wizard/Pages/20-sim.qml:59
437#: qml/Wizard/Pages/20-sim.qml:59
438msgid "Without it, you won’t be able to make calls or use text messaging."
438msgid "Without it, you won’t be able to make calls or use text messaging."
@@ -440,49 +440,49 @@ msgstr "Ensin ella, nun vas poder facer llamaes nin unviar mensaxes."
440
440
441#: qml/Wizard/Pages/20-sim.qml:73 qml/Wizard/Pages/40-wifi.qml:215
441#: qml/Wizard/Pages/20-sim.qml:73 qml/Wizard/Pages/40-wifi.qml:215
442msgid "Skip"
442msgid "Skip"
443−msgstr "Omitir"
443+msgstr "Saltar"
444
444
445#: qml/Wizard/Pages/30-passwd-type.qml:39
445#: qml/Wizard/Pages/30-passwd-type.qml:39
446msgid "Lock security"
446msgid "Lock security"
447−msgstr "Seguridá de bloquéu"
447+msgstr "Seguranza del bloquéu"
448
448
449#: qml/Wizard/Pages/30-passwd-type.qml:74
449#: qml/Wizard/Pages/30-passwd-type.qml:74
450msgid "Please select how you’d like to unlock your phone."
450msgid "Please select how you’d like to unlock your phone."
451−msgstr "Seleiciona cómo te prestaría desbloquiar el teléfonu."
451+msgstr "Por favor, esbilla como te prestaría desbloquiar el teléfonu."
452
452
453#: qml/Wizard/Pages/30-passwd-type.qml:97
453#: qml/Wizard/Pages/30-passwd-type.qml:97
454msgctxt "Label: Type of security method"
454msgctxt "Label: Type of security method"
455msgid "Swipe"
455msgid "Swipe"
456−msgstr ""
456+msgstr "Eslizar"
457
457
458#: qml/Wizard/Pages/30-passwd-type.qml:98
458#: qml/Wizard/Pages/30-passwd-type.qml:98
459msgctxt "Label: Description of security method"
459msgctxt "Label: Description of security method"
460msgid "No security"
460msgid "No security"
461−msgstr ""
461+msgstr "Ensin seguranza"
462
462
463#: qml/Wizard/Pages/30-passwd-type.qml:100
463#: qml/Wizard/Pages/30-passwd-type.qml:100
464msgctxt "Label: Type of security method"
464msgctxt "Label: Type of security method"
465msgid "Passcode"
465msgid "Passcode"
466−msgstr ""
466+msgstr "Códigu de pasu"
467
467
468#: qml/Wizard/Pages/30-passwd-type.qml:101
468#: qml/Wizard/Pages/30-passwd-type.qml:101
469msgctxt "Label: Description of security method"
469msgctxt "Label: Description of security method"
470msgid "4 digits only"
470msgid "4 digits only"
471−msgstr ""
471+msgstr "Namái 4 díxitos"
472
472
473#: qml/Wizard/Pages/30-passwd-type.qml:103
473#: qml/Wizard/Pages/30-passwd-type.qml:103
474msgctxt "Label: Type of security method"
474msgctxt "Label: Type of security method"
475msgid "Passphrase"
475msgid "Passphrase"
476−msgstr ""
476+msgstr "Fras de pasu"
477
477
478#: qml/Wizard/Pages/30-passwd-type.qml:104
478#: qml/Wizard/Pages/30-passwd-type.qml:104
479msgctxt "Label: Description of security method"
479msgctxt "Label: Description of security method"
480msgid "Numbers and letters"
480msgid "Numbers and letters"
481−msgstr ""
481+msgstr "Númberos y lletres"
482
482
483#: qml/Wizard/Pages/40-wifi.qml:29
483#: qml/Wizard/Pages/40-wifi.qml:29
484msgid "Connect to Wi‑Fi"
484msgid "Connect to Wi‑Fi"
485−msgstr "Coneutar a WiFi"
485+msgstr "Coneutase al WiFi"
486
486
487#: qml/Wizard/Pages/40-wifi.qml:168
487#: qml/Wizard/Pages/40-wifi.qml:168
488msgid "Available networks…"
488msgid "Available networks…"
@@ -494,11 +494,11 @@ msgstr "Nun hai redes disponibles"
494
494
495#: qml/Wizard/Pages/50-location.qml:27
495#: qml/Wizard/Pages/50-location.qml:27
496msgid "Location"
496msgid "Location"
497−msgstr "Llocalización"
497+msgstr "Allugamientu"
498
498
499#: qml/Wizard/Pages/50-location.qml:62
499#: qml/Wizard/Pages/50-location.qml:62
500msgid "Let the phone detect your location:"
500msgid "Let the phone detect your location:"
501−msgstr "Permitir al teléfonu deteutar la llocalización:"
501+msgstr "Dexar al teléfonu deteutar l'allugamientu:"
502
502
503#: qml/Wizard/Pages/50-location.qml:69
503#: qml/Wizard/Pages/50-location.qml:69
504msgid "Using GPS only (less accurate)"
504msgid "Using GPS only (less accurate)"
@@ -507,7 +507,7 @@ msgstr "Namái usando GPS (menos precisión)"
507#: qml/Wizard/Pages/50-location.qml:86
507#: qml/Wizard/Pages/50-location.qml:86
508msgid "Using GPS, anonymized Wi-Fi and cellular network info (recommended)"
508msgid "Using GPS, anonymized Wi-Fi and cellular network info (recommended)"
509msgstr ""
509msgstr ""
510−"Usando GPS, Wifi anónimes ya información de redes móviles (recomiéndase)"
510+"Usando GPS, Wi-fi anónimes ya información de redes móviles (aconseyao)"
511
511
512#. TRANSLATORS: HERE is a trademark for Nokia's location service, you probably shouldn't translate it
512#. TRANSLATORS: HERE is a trademark for Nokia's location service, you probably shouldn't translate it
513#: qml/Wizard/Pages/50-location.qml:103
513#: qml/Wizard/Pages/50-location.qml:103
@@ -515,8 +515,8 @@ msgid ""
515"By selecting this option you agree to the Nokia HERE <a href='#'>terms and "
515"By selecting this option you agree to the Nokia HERE <a href='#'>terms and "
516"conditions</a>."
516"conditions</a>."
517msgstr ""
517msgstr ""
518−"Seleicionando esta opción, aceutes los <a href='#'>términos y "
518+"Esbillando esta opción aceutes los <a href='#'>términos y condiciones</a> de "
519−"condiciones</a> de Nokia HERE."
519+"Nokia HERE."
520
520
521#: qml/Wizard/Pages/50-location.qml:112
521#: qml/Wizard/Pages/50-location.qml:112
522msgid "Not at all"
522msgid "Not at all"
@@ -528,7 +528,7 @@ msgstr "Pues cambialo dempués n'<b>Axustes del sistema</b>."
528
528
529#: qml/Wizard/Pages/60-reporting.qml:24
529#: qml/Wizard/Pages/60-reporting.qml:24
530msgid "Improving your experience"
530msgid "Improving your experience"
531−msgstr "Ameyorar la esperiencia"
531+msgstr "Ameyorando la to esperiencia"
532
532
533#: qml/Wizard/Pages/60-reporting.qml:36
533#: qml/Wizard/Pages/60-reporting.qml:36
534msgid ""
534msgid ""
@@ -543,7 +543,7 @@ msgid ""
543"This can be disabled in <b>System Settings</b> under <b>Security &amp; "
543"This can be disabled in <b>System Settings</b> under <b>Security &amp; "
544"Privacy</b>"
544"Privacy</b>"
545msgstr ""
545msgstr ""
546−"Esto pue desactivase nos <b>Axustes del sistema</b> en <b>Seguranza y "
546+"Esto pue deshabilitase nos <b>Axustes del sistema</b> en <b>Seguranza y "
547"privacidá</b>"
547"privacidá</b>"
548
548
549#: qml/Wizard/Pages/80-finished.qml:24
549#: qml/Wizard/Pages/80-finished.qml:24
@@ -552,11 +552,11 @@ msgstr "Too fecho"
552
552
553#: qml/Wizard/Pages/80-finished.qml:39
553#: qml/Wizard/Pages/80-finished.qml:39
554msgid "Nice work!"
554msgid "Nice work!"
555−msgstr "Bon trabayu!"
555+msgstr "¡Bon trabayu!"
556
556
557#: qml/Wizard/Pages/80-finished.qml:46
557#: qml/Wizard/Pages/80-finished.qml:46
558msgid "Your phone is now ready to use."
558msgid "Your phone is now ready to use."
559−msgstr "El teléfonu yá ta preparáu pa usar."
559+msgstr "El teléfonu yá ta tresnáu pa usase."
560
560
561#: qml/Wizard/Pages/80-finished.qml:53
561#: qml/Wizard/Pages/80-finished.qml:53
562msgid "Finish"
562msgid "Finish"
@@ -568,24 +568,24 @@ msgstr "Términos y condiciones"
568
568
569#: qml/Wizard/Pages/passwd-confirm.qml:49
569#: qml/Wizard/Pages/passwd-confirm.qml:49
570msgid "Confirm passphrase"
570msgid "Confirm passphrase"
571−msgstr "Confirmar fras secreta"
571+msgstr "Confirmar frase de pasu"
572
572
573#: qml/Wizard/Pages/passwd-confirm.qml:50
573#: qml/Wizard/Pages/passwd-confirm.qml:50
574msgid "Confirm passcode"
574msgid "Confirm passcode"
575−msgstr "Confirmar el códigu de pasu"
575+msgstr "Confirmar códigu de pasu"
576
576
577#: qml/Wizard/Pages/passwd-confirm.qml:53
577#: qml/Wizard/Pages/passwd-confirm.qml:53
578#: qml/Wizard/Pages/passwd-confirm.qml:54
578#: qml/Wizard/Pages/passwd-confirm.qml:54
579msgid "Please try again."
579msgid "Please try again."
580−msgstr "Vuelvi a intentalo."
580+msgstr "Por favor, vuelvi a intentalo."
581
581
582#: qml/Wizard/Pages/passwd-set.qml:61
582#: qml/Wizard/Pages/passwd-set.qml:61
583msgid "Choose your passcode"
583msgid "Choose your passcode"
584−msgstr "Escueyi'l códigu de pasu"
584+msgstr "Escueyi'l to códigu de pasu"
585
585
586#: qml/Wizard/Pages/passwd-set.qml:68
586#: qml/Wizard/Pages/passwd-set.qml:68
587msgid "Passphrase must be 4 characters long"
587msgid "Passphrase must be 4 characters long"
588−msgstr "La fras de contraseña tien de ser de 4 caráuteres"
588+msgstr "La fras de pasu tien de ser 4 caráuteres de llargor"
589
589
590#: qml/Wizard/StackButton.qml:39
590#: qml/Wizard/StackButton.qml:39
591#, qt-format
591#, qt-format
po/cs.po+136−119
@@ -8,132 +8,138 @@ 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: 2015-04-14 16:13+0200\n"
10"POT-Creation-Date: 2015-04-14 16:13+0200\n"
11−"PO-Revision-Date: 2014-01-08 10:11+0000\n"
11+"PO-Revision-Date: 2015-05-11 20:42+0000\n"
12"Last-Translator: Tadeáš Pařík <tadeas.parik@gmail.com>\n"
12"Last-Translator: Tadeáš Pařík <tadeas.parik@gmail.com>\n"
13"Language-Team: Czech <cs@li.org>\n"
13"Language-Team: Czech <cs@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"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
17"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
18−"X-Launchpad-Export-Date: 2015-04-23 06:48+0000\n"
18+"X-Launchpad-Export-Date: 2015-05-13 05:31+0000\n"
19−"X-Generator: Launchpad (build 17430)\n"
19+"X-Generator: Launchpad (build 17493)\n"
20+"Language: cs\n"
20
21
21#: plugins/LightDM/Greeter.cpp:112
22#: plugins/LightDM/Greeter.cpp:112
22msgid "Password: "
23msgid "Password: "
23−msgstr ""
24+msgstr "Heslo: "
24
25
25#: plugins/Unity/Launcher/launcheritem.cpp:45
26#: plugins/Unity/Launcher/launcheritem.cpp:45
26#: plugins/Unity/Launcher/launcheritem.cpp:100
27#: plugins/Unity/Launcher/launcheritem.cpp:100
27msgid "Pin shortcut"
28msgid "Pin shortcut"
28−msgstr ""
29+msgstr "Připíchnout zkratku"
29
30
30#: plugins/Unity/Launcher/launcheritem.cpp:100
31#: plugins/Unity/Launcher/launcheritem.cpp:100
31msgid "Unpin shortcut"
32msgid "Unpin shortcut"
32−msgstr ""
33+msgstr "Odpíchnout zkratku"
33
34
34#: qml/Components/DelayedLockscreen.qml:49
35#: qml/Components/DelayedLockscreen.qml:49
35msgid "Device Locked"
36msgid "Device Locked"
36−msgstr ""
37+msgstr "Zařízení uzamčeno"
37
38
38#: qml/Components/DelayedLockscreen.qml:64
39#: qml/Components/DelayedLockscreen.qml:64
39msgid "You have been locked out due to too many failed passphrase attempts."
40msgid "You have been locked out due to too many failed passphrase attempts."
40msgstr ""
41msgstr ""
42+"Zařízení bylo uzamčeno z důvodu mnoha neúspěšných pokusů o přihlášení."
41
43
42#: qml/Components/DelayedLockscreen.qml:65
44#: qml/Components/DelayedLockscreen.qml:65
43msgid "You have been locked out due to too many failed passcode attempts."
45msgid "You have been locked out due to too many failed passcode attempts."
44msgstr ""
46msgstr ""
47+"Zařízení bylo uzamčeno z důvodu mnoha neúspěšných pokusů o přihlášení."
45
48
46#: qml/Components/DelayedLockscreen.qml:74
49#: qml/Components/DelayedLockscreen.qml:74
47#, qt-format
50#, qt-format
48msgid "Please wait %1 minute and then try again…"
51msgid "Please wait %1 minute and then try again…"
49msgid_plural "Please wait %1 minutes and then try again…"
52msgid_plural "Please wait %1 minutes and then try again…"
50−msgstr[0] ""
53+msgstr[0] "Počkejte, prosím, %1 minut a poté to zkuste znovu..."
51−msgstr[1] ""
54+msgstr[1] "Počkejte, prosím, %1 minuty a poté to zkuste znovu..."
55+msgstr[2] "Počkejte, prosím, %1 minut a poté to zkuste znovu..."
52
56
53#: qml/Components/Dialogs.qml:69
57#: qml/Components/Dialogs.qml:69
54msgctxt "Title: Lock/Log out dialog"
58msgctxt "Title: Lock/Log out dialog"
55msgid "Log out"
59msgid "Log out"
56−msgstr ""
60+msgstr "Odhlásit se"
57
61
58#: qml/Components/Dialogs.qml:70
62#: qml/Components/Dialogs.qml:70
59msgid "Are you sure you want to log out?"
63msgid "Are you sure you want to log out?"
60−msgstr ""
64+msgstr "Jste si jistí, že se chcete odhlásit?"
61
65
62#: qml/Components/Dialogs.qml:72
66#: qml/Components/Dialogs.qml:72
63msgctxt "Button: Lock the system"
67msgctxt "Button: Lock the system"
64msgid "Lock"
68msgid "Lock"
65−msgstr ""
69+msgstr "Uzamknout"
66
70
67#: qml/Components/Dialogs.qml:79
71#: qml/Components/Dialogs.qml:79
68msgctxt "Button: Log out from the system"
72msgctxt "Button: Log out from the system"
69msgid "Log Out"
73msgid "Log Out"
70−msgstr ""
74+msgstr "Odhlásit"
71
75
72#: qml/Components/Dialogs.qml:86 qml/Components/Dialogs.qml:117
76#: qml/Components/Dialogs.qml:86 qml/Components/Dialogs.qml:117
73#: qml/Components/Dialogs.qml:173
77#: qml/Components/Dialogs.qml:173
74msgid "Cancel"
78msgid "Cancel"
75−msgstr ""
79+msgstr "Zrušit"
76
80
77#: qml/Components/Dialogs.qml:98
81#: qml/Components/Dialogs.qml:98
78msgctxt "Title: Reboot/Shut down dialog"
82msgctxt "Title: Reboot/Shut down dialog"
79msgid "Shut down"
83msgid "Shut down"
80−msgstr ""
84+msgstr "Vypnout"
81
85
82#: qml/Components/Dialogs.qml:99
86#: qml/Components/Dialogs.qml:99
83msgid "Are you sure you want to shut down?"
87msgid "Are you sure you want to shut down?"
84−msgstr ""
88+msgstr "Jste si jistí, že chcete zařízení vypnout?"
85
89
86#: qml/Components/Dialogs.qml:101
90#: qml/Components/Dialogs.qml:101
87msgctxt "Button: Reboot the system"
91msgctxt "Button: Reboot the system"
88msgid "Reboot"
92msgid "Reboot"
89−msgstr ""
93+msgstr "Restartovat"
90
94
91#: qml/Components/Dialogs.qml:109
95#: qml/Components/Dialogs.qml:109
92msgctxt "Button: Shut down the system"
96msgctxt "Button: Shut down the system"
93msgid "Shut down"
97msgid "Shut down"
94−msgstr ""
98+msgstr "Vypnout"
95
99
96#: qml/Components/Dialogs.qml:129
100#: qml/Components/Dialogs.qml:129
97msgctxt "Title: Reboot dialog"
101msgctxt "Title: Reboot dialog"
98msgid "Reboot"
102msgid "Reboot"
99−msgstr ""
103+msgstr "Restartovat"
100
104
101#: qml/Components/Dialogs.qml:130
105#: qml/Components/Dialogs.qml:130
102msgid "Are you sure you want to reboot?"
106msgid "Are you sure you want to reboot?"
103−msgstr ""
107+msgstr "Jste si jistí, že chcete zařízení restartovat?"
104
108
105#: qml/Components/Dialogs.qml:132
109#: qml/Components/Dialogs.qml:132
106msgid "No"
110msgid "No"
107−msgstr ""
111+msgstr "Ne"
108
112
109#: qml/Components/Dialogs.qml:138
113#: qml/Components/Dialogs.qml:138
110msgid "Yes"
114msgid "Yes"
111−msgstr ""
115+msgstr "Ano"
112
116
113#: qml/Components/Dialogs.qml:152
117#: qml/Components/Dialogs.qml:152
114msgctxt "Title: Power off/Restart dialog"
118msgctxt "Title: Power off/Restart dialog"
115msgid "Power"
119msgid "Power"
116−msgstr ""
120+msgstr "Vypnutí"
117
121
118#: qml/Components/Dialogs.qml:153
122#: qml/Components/Dialogs.qml:153
119msgid ""
123msgid ""
120"Are you sure you would like\n"
124"Are you sure you would like\n"
121"to power off?"
125"to power off?"
122msgstr ""
126msgstr ""
127+"Jste si jistí, že chcete\n"
128+"telefon vypnout?"
123
129
124#: qml/Components/Dialogs.qml:155
130#: qml/Components/Dialogs.qml:155
125msgctxt "Button: Power off the system"
131msgctxt "Button: Power off the system"
126msgid "Power off"
132msgid "Power off"
127−msgstr ""
133+msgstr "Vypnutí"
128
134
129#: qml/Components/Dialogs.qml:164
135#: qml/Components/Dialogs.qml:164
130msgctxt "Button: Restart the system"
136msgctxt "Button: Restart the system"
131msgid "Restart"
137msgid "Restart"
132−msgstr ""
138+msgstr "Reboot"
133
139
134#: qml/Components/Lockscreen.qml:245
140#: qml/Components/Lockscreen.qml:245
135msgid "Return to Call"
141msgid "Return to Call"
136−msgstr ""
142+msgstr "Vrátit se k hovoru"
137
143
138#: qml/Components/Lockscreen.qml:245
144#: qml/Components/Lockscreen.qml:245
139msgid "Emergency Call"
145msgid "Emergency Call"
@@ -141,51 +147,51 @@ msgstr "Tísňové volání"
141
147
142#: qml/Components/Lockscreen.qml:277
148#: qml/Components/Lockscreen.qml:277
143msgid "OK"
149msgid "OK"
144−msgstr ""
150+msgstr "OK"
145
151
146#: qml/Dash/GenericScopeView.qml:532 qml/Dash/GenericScopeView.qml:690
152#: qml/Dash/GenericScopeView.qml:532 qml/Dash/GenericScopeView.qml:690
147msgid "See less"
153msgid "See less"
148−msgstr ""
154+msgstr "Zobrazit méně"
149
155
150#: qml/Dash/GenericScopeView.qml:532
156#: qml/Dash/GenericScopeView.qml:532
151msgid "See all"
157msgid "See all"
152−msgstr ""
158+msgstr "Zobrazit vše"
153
159
154#: qml/Dash/GenericScopeView.qml:594
160#: qml/Dash/GenericScopeView.qml:594
155msgctxt "Label: Hint for dash search line edit"
161msgctxt "Label: Hint for dash search line edit"
156msgid "Search"
162msgid "Search"
157−msgstr ""
163+msgstr "Hledat"
158
164
159#: qml/Dash/PageHeader.qml:269
165#: qml/Dash/PageHeader.qml:269
160msgctxt "Button: Open the Ubuntu Store"
166msgctxt "Button: Open the Ubuntu Store"
161msgid "Store"
167msgid "Store"
162−msgstr ""
168+msgstr "Obchod"
163
169
164#: qml/Dash/PageHeader.qml:276
170#: qml/Dash/PageHeader.qml:276
165msgctxt "Button: Start a search in the current dash scope"
171msgctxt "Button: Start a search in the current dash scope"
166msgid "Search"
172msgid "Search"
167−msgstr ""
173+msgstr "Hledat"
168
174
169#: qml/Dash/PageHeader.qml:286
175#: qml/Dash/PageHeader.qml:286
170msgctxt "Button: Show the current dash scope settings"
176msgctxt "Button: Show the current dash scope settings"
171msgid "Settings"
177msgid "Settings"
172−msgstr ""
178+msgstr "Nastavení"
173
179
174#: qml/Dash/PageHeader.qml:293
180#: qml/Dash/PageHeader.qml:293
175msgid "Remove from Favorites"
181msgid "Remove from Favorites"
176−msgstr ""
182+msgstr "Odstranit z oblíbených"
177
183
178#: qml/Dash/PageHeader.qml:293
184#: qml/Dash/PageHeader.qml:293
179msgid "Add to Favorites"
185msgid "Add to Favorites"
180−msgstr ""
186+msgstr "Přidat do oblíbených"
181
187
182#: qml/Dash/Previews/PreviewActionCombo.qml:35
188#: qml/Dash/Previews/PreviewActionCombo.qml:35
183msgid "More..."
189msgid "More..."
184−msgstr ""
190+msgstr "Více..."
185
191
186#: qml/Dash/Previews/PreviewActionCombo.qml:35
192#: qml/Dash/Previews/PreviewActionCombo.qml:35
187msgid "Less..."
193msgid "Less..."
188−msgstr ""
194+msgstr "Méně..."
189
195
190#: qml/Dash/Previews/PreviewRatingInput.qml:81
196#: qml/Dash/Previews/PreviewRatingInput.qml:81
191msgid "Rate this"
197msgid "Rate this"
@@ -201,93 +207,97 @@ msgstr "Odeslat"
201
207
202#: qml/Dash/PullToRefreshScopeStyle.qml:55
208#: qml/Dash/PullToRefreshScopeStyle.qml:55
203msgid "Pull to refresh…"
209msgid "Pull to refresh…"
204−msgstr ""
210+msgstr "Vytáhněte pro obnovení..."
205
211
206#: qml/Dash/PullToRefreshScopeStyle.qml:60
212#: qml/Dash/PullToRefreshScopeStyle.qml:60
207msgid "Release to refresh…"
213msgid "Release to refresh…"
208−msgstr ""
214+msgstr "Pusťte pro obnovení..."
209
215
210#: qml/Dash/ScopeSettings/ScopeSettingBoolean.qml:43
216#: qml/Dash/ScopeSettings/ScopeSettingBoolean.qml:43
211msgid "Enable location data"
217msgid "Enable location data"
212−msgstr ""
218+msgstr "Povolit údaje umístění"
213
219
214#: qml/Dash/ScopesList.qml:66
220#: qml/Dash/ScopesList.qml:66
215msgid "Manage"
221msgid "Manage"
216−msgstr ""
222+msgstr "Spravovat"
217
223
218#: qml/Dash/ScopesList.qml:112
224#: qml/Dash/ScopesList.qml:112
219msgid "Home"
225msgid "Home"
220−msgstr ""
226+msgstr "Domů"
221
227
222#: qml/Dash/ScopesList.qml:113
228#: qml/Dash/ScopesList.qml:113
223msgid "Also installed"
229msgid "Also installed"
224−msgstr ""
230+msgstr "Také nainstalováno"
225
231
226#: qml/Greeter/CoverPage.qml:107
232#: qml/Greeter/CoverPage.qml:107
227msgid "Unlock"
233msgid "Unlock"
228−msgstr ""
234+msgstr "Odemknout"
229
235
230#: qml/Greeter/LoginList.qml:236
236#: qml/Greeter/LoginList.qml:236
231msgid "Retry"
237msgid "Retry"
232−msgstr ""
238+msgstr "Znovu"
233
239
234#: qml/Greeter/LoginList.qml:237
240#: qml/Greeter/LoginList.qml:237
235msgid "Tap to unlock"
241msgid "Tap to unlock"
236−msgstr ""
242+msgstr "Klepnout pro odemčení"
237
243
238#: qml/Greeter/NarrowView.qml:53 qml/Wizard/Pages/passwd-confirm.qml:53
244#: qml/Greeter/NarrowView.qml:53 qml/Wizard/Pages/passwd-confirm.qml:53
239msgid "Sorry, incorrect passphrase."
245msgid "Sorry, incorrect passphrase."
240−msgstr ""
246+msgstr "Zadali jste špatné heslo."
241
247
242#: qml/Greeter/NarrowView.qml:54 qml/Wizard/Pages/passwd-confirm.qml:54
248#: qml/Greeter/NarrowView.qml:54 qml/Wizard/Pages/passwd-confirm.qml:54
243msgid "Sorry, incorrect passcode."
249msgid "Sorry, incorrect passcode."
244−msgstr ""
250+msgstr "Zadali jste špatné heslo."
245
251
246#: qml/Greeter/NarrowView.qml:55
252#: qml/Greeter/NarrowView.qml:55
247msgid "This will be your last attempt."
253msgid "This will be your last attempt."
248−msgstr ""
254+msgstr "Toto je váš poslední pokus."
249
255
250#: qml/Greeter/NarrowView.qml:57
256#: qml/Greeter/NarrowView.qml:57
251msgid ""
257msgid ""
252"If passphrase is entered incorrectly, your phone will conduct a factory "
258"If passphrase is entered incorrectly, your phone will conduct a factory "
253"reset and all personal data will be deleted."
259"reset and all personal data will be deleted."
254msgstr ""
260msgstr ""
261+"Pokud bude heslo zadáno nesprávně, bude telefon obnoven do továrního "
262+"nastavení a všechna osobní data budou smazána."
255
263
256#: qml/Greeter/NarrowView.qml:58
264#: qml/Greeter/NarrowView.qml:58
257msgid ""
265msgid ""
258"If passcode is entered incorrectly, your phone will conduct a factory reset "
266"If passcode is entered incorrectly, your phone will conduct a factory reset "
259"and all personal data will be deleted."
267"and all personal data will be deleted."
260msgstr ""
268msgstr ""
269+"Pokud bude heslo zadáno nesprávně, bude telefon obnoven do továrního "
270+"nastavení a všechna osobní data budou smazána."
261
271
262#: qml/Greeter/NarrowView.qml:115
272#: qml/Greeter/NarrowView.qml:115
263#, qt-format
273#, qt-format
264msgid "Enter %1"
274msgid "Enter %1"
265−msgstr ""
275+msgstr "Vložte %1"
266
276
267#: qml/Greeter/NarrowView.qml:116 qml/Wizard/Pages/passwd-set.qml:60
277#: qml/Greeter/NarrowView.qml:116 qml/Wizard/Pages/passwd-set.qml:60
268msgid "Enter passphrase"
278msgid "Enter passphrase"
269−msgstr ""
279+msgstr "Vložte heslo"
270
280
271#: qml/Greeter/NarrowView.qml:117
281#: qml/Greeter/NarrowView.qml:117
272msgid "Enter passcode"
282msgid "Enter passcode"
273−msgstr ""
283+msgstr "Vložte heslo"
274
284
275#: qml/Greeter/NarrowView.qml:118
285#: qml/Greeter/NarrowView.qml:118
276#, qt-format
286#, qt-format
277msgid "Sorry, incorrect %1"
287msgid "Sorry, incorrect %1"
278−msgstr ""
288+msgstr "Špatné %1"
279
289
280#: qml/Greeter/NarrowView.qml:119
290#: qml/Greeter/NarrowView.qml:119
281msgid "Sorry, incorrect passphrase"
291msgid "Sorry, incorrect passphrase"
282−msgstr ""
292+msgstr "Špatné heslo"
283
293
284#: qml/Greeter/NarrowView.qml:120
294#: qml/Greeter/NarrowView.qml:120
285msgid "Please re-enter"
295msgid "Please re-enter"
286−msgstr ""
296+msgstr "Vložte znovu"
287
297
288#: qml/Greeter/NarrowView.qml:121
298#: qml/Greeter/NarrowView.qml:121
289msgid "Sorry, incorrect passcode"
299msgid "Sorry, incorrect passcode"
290−msgstr ""
300+msgstr "Špatné heslo"
291
301
292#: qml/Notifications/NotificationMenuItemFactory.qml:128
302#: qml/Notifications/NotificationMenuItemFactory.qml:128
293msgid "Show password"
303msgid "Show password"
@@ -295,211 +305,211 @@ msgstr "Zobrazit heslo"
295
305
296#: qml/Panel/ActiveCallHint.qml:79
306#: qml/Panel/ActiveCallHint.qml:79
297msgid "Tap to return to call..."
307msgid "Tap to return to call..."
298−msgstr ""
308+msgstr "Klepnutím se vrátíte k hovoru..."
299
309
300#: qml/Panel/ActiveCallHint.qml:92
310#: qml/Panel/ActiveCallHint.qml:92
301msgid "Conference"
311msgid "Conference"
302−msgstr ""
312+msgstr "Konferenční hovor"
303
313
304#: qml/Panel/Indicators/MenuItemFactory.qml:639
314#: qml/Panel/Indicators/MenuItemFactory.qml:639
305msgid "Nothing is playing"
315msgid "Nothing is playing"
306−msgstr ""
316+msgstr "Nic se nepřehrává"
307
317
308#: qml/Panel/Indicators/MenuItemFactory.qml:787
318#: qml/Panel/Indicators/MenuItemFactory.qml:787
309msgid "In queue…"
319msgid "In queue…"
310−msgstr ""
320+msgstr "Ve frontě..."
311
321
312#: qml/Panel/Indicators/MenuItemFactory.qml:791
322#: qml/Panel/Indicators/MenuItemFactory.qml:791
313msgid "Downloading"
323msgid "Downloading"
314−msgstr ""
324+msgstr "Stahování"
315
325
316#: qml/Panel/Indicators/MenuItemFactory.qml:793
326#: qml/Panel/Indicators/MenuItemFactory.qml:793
317msgid "Paused, tap to resume"
327msgid "Paused, tap to resume"
318−msgstr ""
328+msgstr "Pauza, pro pokračování klepněte"
319
329
320#: qml/Panel/Indicators/MenuItemFactory.qml:795
330#: qml/Panel/Indicators/MenuItemFactory.qml:795
321msgid "Canceled"
331msgid "Canceled"
322−msgstr ""
332+msgstr "Zrušeno"
323
333
324#: qml/Panel/Indicators/MenuItemFactory.qml:797
334#: qml/Panel/Indicators/MenuItemFactory.qml:797
325msgid "Finished"
335msgid "Finished"
326−msgstr ""
336+msgstr "Dokončeno"
327
337
328#: qml/Panel/Indicators/MenuItemFactory.qml:799
338#: qml/Panel/Indicators/MenuItemFactory.qml:799
329msgid "Failed, tap to retry"
339msgid "Failed, tap to retry"
330−msgstr ""
340+msgstr "Nezdařilo se, opakujte klepnutím"
331
341
332#: qml/Panel/Indicators/MessageMenuItemFactory.qml:149
342#: qml/Panel/Indicators/MessageMenuItemFactory.qml:149
333msgctxt "Label: Hint in message indicator line edit"
343msgctxt "Label: Hint in message indicator line edit"
334msgid "Reply"
344msgid "Reply"
335−msgstr ""
345+msgstr "Odpovědět"
336
346
337#: qml/Panel/Indicators/ModemInfoItem.qml:105
347#: qml/Panel/Indicators/ModemInfoItem.qml:105
338msgid "Unlock SIM"
348msgid "Unlock SIM"
339−msgstr ""
349+msgstr "Odemknout SIM"
340
350
341#: qml/Panel/Indicators/RoamingIndication.qml:27
351#: qml/Panel/Indicators/RoamingIndication.qml:27
342msgid "Roaming"
352msgid "Roaming"
343−msgstr ""
353+msgstr "Roaming"
344
354
345#: qml/Tutorial/TutorialBottomFinish.qml:24
355#: qml/Tutorial/TutorialBottomFinish.qml:24
346msgid "This action does different things for different apps"
356msgid "This action does different things for different apps"
347−msgstr ""
357+msgstr "Tato akce vyvolá různé reakce v rozdílných aplikacích"
348
358
349#: qml/Tutorial/TutorialBottomFinish.qml:25
359#: qml/Tutorial/TutorialBottomFinish.qml:25
350msgid "Tap here to finish."
360msgid "Tap here to finish."
351−msgstr ""
361+msgstr "Klepněte zde pro dokončení."
352
362
353#: qml/Tutorial/TutorialBottom.qml:28
363#: qml/Tutorial/TutorialBottom.qml:28
354msgid "Open special menus"
364msgid "Open special menus"
355−msgstr ""
365+msgstr "Otevřít speciální menu"
356
366
357#: qml/Tutorial/TutorialBottom.qml:29
367#: qml/Tutorial/TutorialBottom.qml:29
358msgid "Swipe up from the bottom edge."
368msgid "Swipe up from the bottom edge."
359−msgstr ""
369+msgstr "Potáhněte prstem z dola nahoru."
360
370
361#: qml/Tutorial/TutorialContent.qml:81 qml/Tutorial/TutorialLeftFinish.qml:25
371#: qml/Tutorial/TutorialContent.qml:81 qml/Tutorial/TutorialLeftFinish.qml:25
362#: qml/Tutorial/TutorialRight.qml:144
372#: qml/Tutorial/TutorialRight.qml:144
363msgid "Tap here to continue."
373msgid "Tap here to continue."
364−msgstr ""
374+msgstr "Klepněte zde pro pokračování."
365
375
366#: qml/Tutorial/TutorialContent.qml:81
376#: qml/Tutorial/TutorialContent.qml:81
367msgid "Click here to finish."
377msgid "Click here to finish."
368−msgstr ""
378+msgstr "Klikněte zde pro dokončení."
369
379
370#: qml/Tutorial/TutorialLeftFinish.qml:24
380#: qml/Tutorial/TutorialLeftFinish.qml:24
371msgid "These are the shortcuts to favorite apps"
381msgid "These are the shortcuts to favorite apps"
372−msgstr ""
382+msgstr "Zde jsou odkazy na vaše oblíbené aplikace"
373
383
374#: qml/Tutorial/TutorialLeft.qml:26
384#: qml/Tutorial/TutorialLeft.qml:26
375msgid "Open the launcher"
385msgid "Open the launcher"
376−msgstr ""
386+msgstr "Otevřete launcher"
377
387
378#: qml/Tutorial/TutorialLeft.qml:27
388#: qml/Tutorial/TutorialLeft.qml:27
379msgid "Short swipe from the left edge."
389msgid "Short swipe from the left edge."
380−msgstr ""
390+msgstr "Potáhněte krátce z levého okraje."
381
391
382#: qml/Tutorial/TutorialPage.qml:178
392#: qml/Tutorial/TutorialPage.qml:178
383msgid "You almost got it!"
393msgid "You almost got it!"
384−msgstr ""
394+msgstr "Už to skoro máte!"
385
395
386#: qml/Tutorial/TutorialPage.qml:195
396#: qml/Tutorial/TutorialPage.qml:195
387msgid "Try again."
397msgid "Try again."
388−msgstr ""
398+msgstr "Zkuste to znovu."
389
399
390#: qml/Tutorial/TutorialRight.qml:31
400#: qml/Tutorial/TutorialRight.qml:31
391msgid "To view open apps"
401msgid "To view open apps"
392−msgstr ""
402+msgstr "K zobrazení otevřených aplikací"
393
403
394#: qml/Tutorial/TutorialRight.qml:32
404#: qml/Tutorial/TutorialRight.qml:32
395msgid "Long swipe from the right edge."
405msgid "Long swipe from the right edge."
396−msgstr ""
406+msgstr "Potáhněte dlouho z pravého okraje."
397
407
398#: qml/Tutorial/TutorialRight.qml:122
408#: qml/Tutorial/TutorialRight.qml:122
399msgid "View all your running tasks."
409msgid "View all your running tasks."
400−msgstr ""
410+msgstr "Zobrazíte všechny běžící procesy."
401
411
402#: qml/Wizard/Page.qml:89
412#: qml/Wizard/Page.qml:89
403msgctxt "Button: Go back one page in the Wizard"
413msgctxt "Button: Go back one page in the Wizard"
404msgid "Back"
414msgid "Back"
405−msgstr ""
415+msgstr "Zpět"
406
416
407#: qml/Wizard/Pages/10-welcome.qml:27
417#: qml/Wizard/Pages/10-welcome.qml:27
408msgid "Hi!"
418msgid "Hi!"
409−msgstr ""
419+msgstr "Ahoj!"
410
420
411#: qml/Wizard/Pages/10-welcome.qml:44
421#: qml/Wizard/Pages/10-welcome.qml:44
412msgid "Welcome to your Ubuntu phone."
422msgid "Welcome to your Ubuntu phone."
413−msgstr ""
423+msgstr "Vítejte ve vašem Ubuntu telefonu."
414
424
415#: qml/Wizard/Pages/10-welcome.qml:52
425#: qml/Wizard/Pages/10-welcome.qml:52
416msgid "Let’s get started."
426msgid "Let’s get started."
417−msgstr ""
427+msgstr "Začněme."
418
428
419#: qml/Wizard/Pages/10-welcome.qml:88 qml/Wizard/Pages/30-passwd-type.qml:128
429#: qml/Wizard/Pages/10-welcome.qml:88 qml/Wizard/Pages/30-passwd-type.qml:128
420#: qml/Wizard/Pages/40-wifi.qml:215 qml/Wizard/Pages/50-location.qml:131
430#: qml/Wizard/Pages/40-wifi.qml:215 qml/Wizard/Pages/50-location.qml:131
421#: qml/Wizard/Pages/60-reporting.qml:50 qml/Wizard/Pages/passwd-confirm.qml:82
431#: qml/Wizard/Pages/60-reporting.qml:50 qml/Wizard/Pages/passwd-confirm.qml:82
422#: qml/Wizard/Pages/passwd-set.qml:90
432#: qml/Wizard/Pages/passwd-set.qml:90
423msgid "Continue"
433msgid "Continue"
424−msgstr ""
434+msgstr "Pokračovat"
425
435
426#: qml/Wizard/Pages/20-sim.qml:25
436#: qml/Wizard/Pages/20-sim.qml:25
427msgid "Add a SIM card and restart your device"
437msgid "Add a SIM card and restart your device"
428−msgstr ""
438+msgstr "Vložte SIM kartu a restartujte své zařízení"
429
439
430#: qml/Wizard/Pages/20-sim.qml:59
440#: qml/Wizard/Pages/20-sim.qml:59
431msgid "Without it, you won’t be able to make calls or use text messaging."
441msgid "Without it, you won’t be able to make calls or use text messaging."
432−msgstr ""
442+msgstr "Bez ni nebudete moci telefonovat nebo posílat textové zprávy."
433
443
434#: qml/Wizard/Pages/20-sim.qml:73 qml/Wizard/Pages/40-wifi.qml:215
444#: qml/Wizard/Pages/20-sim.qml:73 qml/Wizard/Pages/40-wifi.qml:215
435msgid "Skip"
445msgid "Skip"
436−msgstr ""
446+msgstr "Přeskočit"
437
447
438#: qml/Wizard/Pages/30-passwd-type.qml:39
448#: qml/Wizard/Pages/30-passwd-type.qml:39
439msgid "Lock security"
449msgid "Lock security"
440−msgstr ""
450+msgstr "Bezpečnostní uzamčení"
441
451
442#: qml/Wizard/Pages/30-passwd-type.qml:74
452#: qml/Wizard/Pages/30-passwd-type.qml:74
443msgid "Please select how you’d like to unlock your phone."
453msgid "Please select how you’d like to unlock your phone."
444−msgstr ""
454+msgstr "Zvolte, prosím, jak chcete svůj telefon odemykat."
445
455
446#: qml/Wizard/Pages/30-passwd-type.qml:97
456#: qml/Wizard/Pages/30-passwd-type.qml:97
447msgctxt "Label: Type of security method"
457msgctxt "Label: Type of security method"
448msgid "Swipe"
458msgid "Swipe"
449−msgstr ""
459+msgstr "Potažením prstu"
450
460
451#: qml/Wizard/Pages/30-passwd-type.qml:98
461#: qml/Wizard/Pages/30-passwd-type.qml:98
452msgctxt "Label: Description of security method"
462msgctxt "Label: Description of security method"
453msgid "No security"
463msgid "No security"
454−msgstr ""
464+msgstr "Bez zabezpečení"
455
465
456#: qml/Wizard/Pages/30-passwd-type.qml:100
466#: qml/Wizard/Pages/30-passwd-type.qml:100
457msgctxt "Label: Type of security method"
467msgctxt "Label: Type of security method"
458msgid "Passcode"
468msgid "Passcode"
459−msgstr ""
469+msgstr "Číselné heslo"
460
470
461#: qml/Wizard/Pages/30-passwd-type.qml:101
471#: qml/Wizard/Pages/30-passwd-type.qml:101
462msgctxt "Label: Description of security method"
472msgctxt "Label: Description of security method"
463msgid "4 digits only"
473msgid "4 digits only"
464−msgstr ""
474+msgstr "Pouze 4 čísla"
465
475
466#: qml/Wizard/Pages/30-passwd-type.qml:103
476#: qml/Wizard/Pages/30-passwd-type.qml:103
467msgctxt "Label: Type of security method"
477msgctxt "Label: Type of security method"
468msgid "Passphrase"
478msgid "Passphrase"
469−msgstr ""
479+msgstr "Heslo"
470
480
471#: qml/Wizard/Pages/30-passwd-type.qml:104
481#: qml/Wizard/Pages/30-passwd-type.qml:104
472msgctxt "Label: Description of security method"
482msgctxt "Label: Description of security method"
473msgid "Numbers and letters"
483msgid "Numbers and letters"
474−msgstr ""
484+msgstr "Čísla a písmena"
475
485
476#: qml/Wizard/Pages/40-wifi.qml:29
486#: qml/Wizard/Pages/40-wifi.qml:29
477msgid "Connect to Wi‑Fi"
487msgid "Connect to Wi‑Fi"
478−msgstr ""
488+msgstr "Připojte se k Wi-Fi"
479
489
480#: qml/Wizard/Pages/40-wifi.qml:168
490#: qml/Wizard/Pages/40-wifi.qml:168
481msgid "Available networks…"
491msgid "Available networks…"
482−msgstr ""
492+msgstr "Dostupné sítě..."
483
493
484#: qml/Wizard/Pages/40-wifi.qml:169
494#: qml/Wizard/Pages/40-wifi.qml:169
485msgid "No available networks."
495msgid "No available networks."
486−msgstr ""
496+msgstr "Žádná dostupná síť."
487
497
488#: qml/Wizard/Pages/50-location.qml:27
498#: qml/Wizard/Pages/50-location.qml:27
489msgid "Location"
499msgid "Location"
490−msgstr ""
500+msgstr "Umístění"
491
501
492#: qml/Wizard/Pages/50-location.qml:62
502#: qml/Wizard/Pages/50-location.qml:62
493msgid "Let the phone detect your location:"
503msgid "Let the phone detect your location:"
494−msgstr ""
504+msgstr "Povolte telefonu zjistit, kde se zrovna nacházíte:"
495
505
496#: qml/Wizard/Pages/50-location.qml:69
506#: qml/Wizard/Pages/50-location.qml:69
497msgid "Using GPS only (less accurate)"
507msgid "Using GPS only (less accurate)"
498−msgstr ""
508+msgstr "Používat pouze GPS (méně přesné)"
499
509
500#: qml/Wizard/Pages/50-location.qml:86
510#: qml/Wizard/Pages/50-location.qml:86
501msgid "Using GPS, anonymized Wi-Fi and cellular network info (recommended)"
511msgid "Using GPS, anonymized Wi-Fi and cellular network info (recommended)"
502−msgstr ""
512+msgstr "Používat GPS, anonymní Wi-Fi a datovou síť (doporučeno)"
503
513
504#. TRANSLATORS: HERE is a trademark for Nokia's location service, you probably shouldn't translate it
514#. TRANSLATORS: HERE is a trademark for Nokia's location service, you probably shouldn't translate it
505#: qml/Wizard/Pages/50-location.qml:103
515#: qml/Wizard/Pages/50-location.qml:103
@@ -507,81 +517,88 @@ msgid ""
507"By selecting this option you agree to the Nokia HERE <a href='#'>terms and "
517"By selecting this option you agree to the Nokia HERE <a href='#'>terms and "
508"conditions</a>."
518"conditions</a>."
509msgstr ""
519msgstr ""
520+"Zvolením této možnosti souhlasíte s <a href='#'>pravidly a podmínkami</a> "
521+"Nokia HERE."
510
522
511#: qml/Wizard/Pages/50-location.qml:112
523#: qml/Wizard/Pages/50-location.qml:112
512msgid "Not at all"
524msgid "Not at all"
513−msgstr ""
525+msgstr "V žádném případě"
514
526
515#: qml/Wizard/Pages/50-location.qml:124
527#: qml/Wizard/Pages/50-location.qml:124
516msgid "You can change your mind later in <b>System Settings</b>."
528msgid "You can change your mind later in <b>System Settings</b>."
517msgstr ""
529msgstr ""
530+"Pokud změníte názor, můžete nastavení změnit v <b>Nastavení systému</b>."
518
531
519#: qml/Wizard/Pages/60-reporting.qml:24
532#: qml/Wizard/Pages/60-reporting.qml:24
520msgid "Improving your experience"
533msgid "Improving your experience"
521−msgstr ""
534+msgstr "Zlepšete své zkušenosti"
522
535
523#: qml/Wizard/Pages/60-reporting.qml:36
536#: qml/Wizard/Pages/60-reporting.qml:36
524msgid ""
537msgid ""
525"Your phone is set up to automatically report errors to Canonical and its "
538"Your phone is set up to automatically report errors to Canonical and its "
526"partners, the makers of the operating system."
539"partners, the makers of the operating system."
527msgstr ""
540msgstr ""
541+"Váš telefon je nastaven tak, aby automaticky odesílal informace o chybách "
542+"společnosti Canonical a partnerům, kteří stvořili tento operační systém."
528
543
529#: qml/Wizard/Pages/60-reporting.qml:43
544#: qml/Wizard/Pages/60-reporting.qml:43
530msgid ""
545msgid ""
531"This can be disabled in <b>System Settings</b> under <b>Security &amp; "
546"This can be disabled in <b>System Settings</b> under <b>Security &amp; "
532"Privacy</b>"
547"Privacy</b>"
533msgstr ""
548msgstr ""
549+"To může být vypnuto v <b>Nastavení systému</b> v <b>Zabezpečení a "
550+"soukromí</b>"
534
551
535#: qml/Wizard/Pages/80-finished.qml:24
552#: qml/Wizard/Pages/80-finished.qml:24
536msgid "All done"
553msgid "All done"
537−msgstr ""
554+msgstr "Vše je hotovo"
538
555
539#: qml/Wizard/Pages/80-finished.qml:39
556#: qml/Wizard/Pages/80-finished.qml:39
540msgid "Nice work!"
557msgid "Nice work!"
541−msgstr ""
558+msgstr "Skvělá práce!"
542
559
543#: qml/Wizard/Pages/80-finished.qml:46
560#: qml/Wizard/Pages/80-finished.qml:46
544msgid "Your phone is now ready to use."
561msgid "Your phone is now ready to use."
545−msgstr ""
562+msgstr "Váš telefon je nyní připraven k použití."
546
563
547#: qml/Wizard/Pages/80-finished.qml:53
564#: qml/Wizard/Pages/80-finished.qml:53
548msgid "Finish"
565msgid "Finish"
549−msgstr ""
566+msgstr "Dokončit"
550
567
551#: qml/Wizard/Pages/here-terms.qml:27
568#: qml/Wizard/Pages/here-terms.qml:27
552msgid "Terms & Conditions"
569msgid "Terms & Conditions"
553−msgstr ""
570+msgstr "Pravidla a podmínky"
554
571
555#: qml/Wizard/Pages/passwd-confirm.qml:49
572#: qml/Wizard/Pages/passwd-confirm.qml:49
556msgid "Confirm passphrase"
573msgid "Confirm passphrase"
557−msgstr ""
574+msgstr "Potvrdit heslo"
558
575
559#: qml/Wizard/Pages/passwd-confirm.qml:50
576#: qml/Wizard/Pages/passwd-confirm.qml:50
560msgid "Confirm passcode"
577msgid "Confirm passcode"
561−msgstr ""
578+msgstr "Potvrdit číselné heslo"
562
579
563#: qml/Wizard/Pages/passwd-confirm.qml:53
580#: qml/Wizard/Pages/passwd-confirm.qml:53
564#: qml/Wizard/Pages/passwd-confirm.qml:54
581#: qml/Wizard/Pages/passwd-confirm.qml:54
565msgid "Please try again."
582msgid "Please try again."
566−msgstr ""
583+msgstr "Zkuste to, prosím, znovu."
567
584
568#: qml/Wizard/Pages/passwd-set.qml:61
585#: qml/Wizard/Pages/passwd-set.qml:61
569msgid "Choose your passcode"
586msgid "Choose your passcode"
570−msgstr ""
587+msgstr "Zvolte své heslo"
571
588
572#: qml/Wizard/Pages/passwd-set.qml:68
589#: qml/Wizard/Pages/passwd-set.qml:68
573msgid "Passphrase must be 4 characters long"
590msgid "Passphrase must be 4 characters long"
574−msgstr ""
591+msgstr "Heslo musí být alespoň 4 znaky dlouhé"
575
592
576#: qml/Wizard/StackButton.qml:39
593#: qml/Wizard/StackButton.qml:39
577#, qt-format
594#, qt-format
578msgid "〈 %1"
595msgid "〈 %1"
579−msgstr ""
596+msgstr "〈 %1"
580
597
581#: qml/Wizard/StackButton.qml:42
598#: qml/Wizard/StackButton.qml:42
582#, qt-format
599#, qt-format
583msgid "%1 〉"
600msgid "%1 〉"
584−msgstr ""
601+msgstr "%1 〉"
585
602
586#~ msgid "Try swiping from the right edge to unlock the phone"
603#~ msgid "Try swiping from the right edge to unlock the phone"
587#~ msgstr "Pokuste se odemknout telefon potažením prstu z pravého okraje."
604#~ msgstr "Pokuste se odemknout telefon potažením prstu z pravého okraje."
po/de.po+30−30
@@ -8,15 +8,15 @@ 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: 2015-04-14 16:13+0200\n"
10"POT-Creation-Date: 2015-04-14 16:13+0200\n"
11−"PO-Revision-Date: 2015-03-06 14:24+0000\n"
11+"PO-Revision-Date: 2015-05-14 15:49+0000\n"
12−"Last-Translator: Niklas Wenzel <nikwen.developer@gmail.com>\n"
12+"Last-Translator: Tobias Bannert <Unknown>\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"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-04-23 06:48+0000\n"
18+"X-Launchpad-Export-Date: 2015-05-15 05:31+0000\n"
19−"X-Generator: Launchpad (build 17430)\n"
19+"X-Generator: Launchpad (build 17493)\n"
20
20
21#: plugins/LightDM/Greeter.cpp:112
21#: plugins/LightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
@@ -51,13 +51,13 @@ msgstr ""
51#, qt-format
51#, qt-format
52msgid "Please wait %1 minute and then try again…"
52msgid "Please wait %1 minute and then try again…"
53msgid_plural "Please wait %1 minutes and then try again…"
53msgid_plural "Please wait %1 minutes and then try again…"
54−msgstr[0] "Bitte warten Sie %1 Minute und versuchen Sie es dann erneut..."
54+msgstr[0] "Bitte %1 Minute warten und es dann erneut versuchen …"
55−msgstr[1] "Bitte warten Sie %1 Minuten und versuchen Sie es dann erneut..."
55+msgstr[1] "Bitte %1 Minuten warten und es dann erneut versuchen …"
56
56
57#: qml/Components/Dialogs.qml:69
57#: qml/Components/Dialogs.qml:69
58msgctxt "Title: Lock/Log out dialog"
58msgctxt "Title: Lock/Log out dialog"
59msgid "Log out"
59msgid "Log out"
60−msgstr ""
60+msgstr "Abmelden"
61
61
62#: qml/Components/Dialogs.qml:70
62#: qml/Components/Dialogs.qml:70
63msgid "Are you sure you want to log out?"
63msgid "Are you sure you want to log out?"
@@ -66,12 +66,12 @@ msgstr "Sind Sie sicher, dass Sie sich abmelden wollen?"
66#: qml/Components/Dialogs.qml:72
66#: qml/Components/Dialogs.qml:72
67msgctxt "Button: Lock the system"
67msgctxt "Button: Lock the system"
68msgid "Lock"
68msgid "Lock"
69−msgstr ""
69+msgstr "Sperren"
70
70
71#: qml/Components/Dialogs.qml:79
71#: qml/Components/Dialogs.qml:79
72msgctxt "Button: Log out from the system"
72msgctxt "Button: Log out from the system"
73msgid "Log Out"
73msgid "Log Out"
74−msgstr ""
74+msgstr "Abmelden"
75
75
76#: qml/Components/Dialogs.qml:86 qml/Components/Dialogs.qml:117
76#: qml/Components/Dialogs.qml:86 qml/Components/Dialogs.qml:117
77#: qml/Components/Dialogs.qml:173
77#: qml/Components/Dialogs.qml:173
@@ -81,7 +81,7 @@ msgstr "Abbrechen"
81#: qml/Components/Dialogs.qml:98
81#: qml/Components/Dialogs.qml:98
82msgctxt "Title: Reboot/Shut down dialog"
82msgctxt "Title: Reboot/Shut down dialog"
83msgid "Shut down"
83msgid "Shut down"
84−msgstr ""
84+msgstr "Ausschalten"
85
85
86#: qml/Components/Dialogs.qml:99
86#: qml/Components/Dialogs.qml:99
87msgid "Are you sure you want to shut down?"
87msgid "Are you sure you want to shut down?"
@@ -90,17 +90,17 @@ msgstr "Sind Sie sicher, dass Sie herunterfahren wollen?"
90#: qml/Components/Dialogs.qml:101
90#: qml/Components/Dialogs.qml:101
91msgctxt "Button: Reboot the system"
91msgctxt "Button: Reboot the system"
92msgid "Reboot"
92msgid "Reboot"
93−msgstr ""
93+msgstr "Neustarten"
94
94
95#: qml/Components/Dialogs.qml:109
95#: qml/Components/Dialogs.qml:109
96msgctxt "Button: Shut down the system"
96msgctxt "Button: Shut down the system"
97msgid "Shut down"
97msgid "Shut down"
98−msgstr ""
98+msgstr "Ausschalten"
99
99
100#: qml/Components/Dialogs.qml:129
100#: qml/Components/Dialogs.qml:129
101msgctxt "Title: Reboot dialog"
101msgctxt "Title: Reboot dialog"
102msgid "Reboot"
102msgid "Reboot"
103−msgstr ""
103+msgstr "Neustarten"
104
104
105#: qml/Components/Dialogs.qml:130
105#: qml/Components/Dialogs.qml:130
106msgid "Are you sure you want to reboot?"
106msgid "Are you sure you want to reboot?"
@@ -117,7 +117,7 @@ msgstr "Ja"
117#: qml/Components/Dialogs.qml:152
117#: qml/Components/Dialogs.qml:152
118msgctxt "Title: Power off/Restart dialog"
118msgctxt "Title: Power off/Restart dialog"
119msgid "Power"
119msgid "Power"
120−msgstr ""
120+msgstr "Leistung"
121
121
122#: qml/Components/Dialogs.qml:153
122#: qml/Components/Dialogs.qml:153
123msgid ""
123msgid ""
@@ -130,12 +130,12 @@ msgstr ""
130#: qml/Components/Dialogs.qml:155
130#: qml/Components/Dialogs.qml:155
131msgctxt "Button: Power off the system"
131msgctxt "Button: Power off the system"
132msgid "Power off"
132msgid "Power off"
133−msgstr ""
133+msgstr "Ausschalten"
134
134
135#: qml/Components/Dialogs.qml:164
135#: qml/Components/Dialogs.qml:164
136msgctxt "Button: Restart the system"
136msgctxt "Button: Restart the system"
137msgid "Restart"
137msgid "Restart"
138−msgstr ""
138+msgstr "Neustarten"
139
139
140#: qml/Components/Lockscreen.qml:245
140#: qml/Components/Lockscreen.qml:245
141msgid "Return to Call"
141msgid "Return to Call"
@@ -160,22 +160,22 @@ msgstr "Alle anzeigen"
160#: qml/Dash/GenericScopeView.qml:594
160#: qml/Dash/GenericScopeView.qml:594
161msgctxt "Label: Hint for dash search line edit"
161msgctxt "Label: Hint for dash search line edit"
162msgid "Search"
162msgid "Search"
163−msgstr ""
163+msgstr "Suchen"
164
164
165#: qml/Dash/PageHeader.qml:269
165#: qml/Dash/PageHeader.qml:269
166msgctxt "Button: Open the Ubuntu Store"
166msgctxt "Button: Open the Ubuntu Store"
167msgid "Store"
167msgid "Store"
168−msgstr ""
168+msgstr "Speichern"
169
169
170#: qml/Dash/PageHeader.qml:276
170#: qml/Dash/PageHeader.qml:276
171msgctxt "Button: Start a search in the current dash scope"
171msgctxt "Button: Start a search in the current dash scope"
172msgid "Search"
172msgid "Search"
173−msgstr ""
173+msgstr "Suchen"
174
174
175#: qml/Dash/PageHeader.qml:286
175#: qml/Dash/PageHeader.qml:286
176msgctxt "Button: Show the current dash scope settings"
176msgctxt "Button: Show the current dash scope settings"
177msgid "Settings"
177msgid "Settings"
178−msgstr ""
178+msgstr "Einstellungen"
179
179
180#: qml/Dash/PageHeader.qml:293
180#: qml/Dash/PageHeader.qml:293
181msgid "Remove from Favorites"
181msgid "Remove from Favorites"
@@ -305,7 +305,7 @@ msgstr "Passwort anzeigen"
305
305
306#: qml/Panel/ActiveCallHint.qml:79
306#: qml/Panel/ActiveCallHint.qml:79
307msgid "Tap to return to call..."
307msgid "Tap to return to call..."
308−msgstr "Tippen um zum Anruf zurückzugehen"
308+msgstr "Tippen, um zum Anruf zurückzugehen …"
309
309
310#: qml/Panel/ActiveCallHint.qml:92
310#: qml/Panel/ActiveCallHint.qml:92
311msgid "Conference"
311msgid "Conference"
@@ -342,7 +342,7 @@ msgstr "Fehlgeschlagen, tippen Sie zum Wiederholen"
342#: qml/Panel/Indicators/MessageMenuItemFactory.qml:149
342#: qml/Panel/Indicators/MessageMenuItemFactory.qml:149
343msgctxt "Label: Hint in message indicator line edit"
343msgctxt "Label: Hint in message indicator line edit"
344msgid "Reply"
344msgid "Reply"
345−msgstr ""
345+msgstr "Antworten"
346
346
347#: qml/Panel/Indicators/ModemInfoItem.qml:105
347#: qml/Panel/Indicators/ModemInfoItem.qml:105
348msgid "Unlock SIM"
348msgid "Unlock SIM"
@@ -376,7 +376,7 @@ msgstr "Zum Fortfahren hier tippen."
376
376
377#: qml/Tutorial/TutorialContent.qml:81
377#: qml/Tutorial/TutorialContent.qml:81
378msgid "Click here to finish."
378msgid "Click here to finish."
379−msgstr ""
379+msgstr "Zum Abschließen bitte hier klicken."
380
380
381#: qml/Tutorial/TutorialLeftFinish.qml:24
381#: qml/Tutorial/TutorialLeftFinish.qml:24
382msgid "These are the shortcuts to favorite apps"
382msgid "These are the shortcuts to favorite apps"
@@ -413,7 +413,7 @@ msgstr "Sehen Sie alle Ihre laufenden Anwendungen."
413#: qml/Wizard/Page.qml:89
413#: qml/Wizard/Page.qml:89
414msgctxt "Button: Go back one page in the Wizard"
414msgctxt "Button: Go back one page in the Wizard"
415msgid "Back"
415msgid "Back"
416−msgstr ""
416+msgstr "Zurück"
417
417
418#: qml/Wizard/Pages/10-welcome.qml:27
418#: qml/Wizard/Pages/10-welcome.qml:27
419msgid "Hi!"
419msgid "Hi!"
@@ -457,32 +457,32 @@ msgstr "Bitte wählen Sie aus, wie Sie Ihr Telefon entsperren wollen."
457#: qml/Wizard/Pages/30-passwd-type.qml:97
457#: qml/Wizard/Pages/30-passwd-type.qml:97
458msgctxt "Label: Type of security method"
458msgctxt "Label: Type of security method"
459msgid "Swipe"
459msgid "Swipe"
460−msgstr ""
460+msgstr "Wischen"
461
461
462#: qml/Wizard/Pages/30-passwd-type.qml:98
462#: qml/Wizard/Pages/30-passwd-type.qml:98
463msgctxt "Label: Description of security method"
463msgctxt "Label: Description of security method"
464msgid "No security"
464msgid "No security"
465−msgstr ""
465+msgstr "Keine Sicherheitssperre"
466
466
467#: qml/Wizard/Pages/30-passwd-type.qml:100
467#: qml/Wizard/Pages/30-passwd-type.qml:100
468msgctxt "Label: Type of security method"
468msgctxt "Label: Type of security method"
469msgid "Passcode"
469msgid "Passcode"
470−msgstr ""
470+msgstr "PIN"
471
471
472#: qml/Wizard/Pages/30-passwd-type.qml:101
472#: qml/Wizard/Pages/30-passwd-type.qml:101
473msgctxt "Label: Description of security method"
473msgctxt "Label: Description of security method"
474msgid "4 digits only"
474msgid "4 digits only"
475−msgstr ""
475+msgstr "nur vier Ziffern"
476
476
477#: qml/Wizard/Pages/30-passwd-type.qml:103
477#: qml/Wizard/Pages/30-passwd-type.qml:103
478msgctxt "Label: Type of security method"
478msgctxt "Label: Type of security method"
479msgid "Passphrase"
479msgid "Passphrase"
480−msgstr ""
480+msgstr "Kennwort"
481
481
482#: qml/Wizard/Pages/30-passwd-type.qml:104
482#: qml/Wizard/Pages/30-passwd-type.qml:104
483msgctxt "Label: Description of security method"
483msgctxt "Label: Description of security method"
484msgid "Numbers and letters"
484msgid "Numbers and letters"
485−msgstr ""
485+msgstr "Ziffern und Buchstaben"
486
486
487#: qml/Wizard/Pages/40-wifi.qml:29
487#: qml/Wizard/Pages/40-wifi.qml:29
488msgid "Connect to Wi‑Fi"
488msgid "Connect to Wi‑Fi"
po/eo.po+6−6
@@ -8,15 +8,15 @@ 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: 2015-04-14 16:13+0200\n"
10"POT-Creation-Date: 2015-04-14 16:13+0200\n"
11−"PO-Revision-Date: 2013-06-26 22:35+0000\n"
11+"PO-Revision-Date: 2015-06-06 23:37+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
12+"Last-Translator: Eliovir <Unknown>\n"
13"Language-Team: Esperanto <eo@li.org>\n"
13"Language-Team: Esperanto <eo@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"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-04-23 06:48+0000\n"
18+"X-Launchpad-Export-Date: 2015-06-08 05:26+0000\n"
19−"X-Generator: Launchpad (build 17430)\n"
19+"X-Generator: Launchpad (build 17540)\n"
20
20
21#: plugins/LightDM/Greeter.cpp:112
21#: plugins/LightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
@@ -197,7 +197,7 @@ msgstr ""
197
197
198#: qml/Dash/Previews/PreviewRatingInput.qml:166
198#: qml/Dash/Previews/PreviewRatingInput.qml:166
199msgid "Send"
199msgid "Send"
200−msgstr ""
200+msgstr "Sendi"
201
201
202#: qml/Dash/PullToRefreshScopeStyle.qml:55
202#: qml/Dash/PullToRefreshScopeStyle.qml:55
203msgid "Pull to refresh…"
203msgid "Pull to refresh…"
@@ -291,7 +291,7 @@ msgstr ""
291
291
292#: qml/Notifications/NotificationMenuItemFactory.qml:128
292#: qml/Notifications/NotificationMenuItemFactory.qml:128
293msgid "Show password"
293msgid "Show password"
294−msgstr ""
294+msgstr "Montri pasvorton"
295
295
296#: qml/Panel/ActiveCallHint.qml:79
296#: qml/Panel/ActiveCallHint.qml:79
297msgid "Tap to return to call..."
297msgid "Tap to return to call..."
po/fi.po+4−4
@@ -8,15 +8,15 @@ 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: 2015-04-14 16:13+0200\n"
10"POT-Creation-Date: 2015-04-14 16:13+0200\n"
11−"PO-Revision-Date: 2015-03-25 07:55+0000\n"
11+"PO-Revision-Date: 2015-05-19 09:14+0000\n"
12"Last-Translator: Jiri Grönroos <Unknown>\n"
12"Last-Translator: Jiri Grönroos <Unknown>\n"
13"Language-Team: Finnish <fi@li.org>\n"
13"Language-Team: Finnish <fi@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"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-04-23 06:48+0000\n"
18+"X-Launchpad-Export-Date: 2015-05-22 05:09+0000\n"
19−"X-Generator: Launchpad (build 17430)\n"
19+"X-Generator: Launchpad (build 17514)\n"
20
20
21#: plugins/LightDM/Greeter.cpp:112
21#: plugins/LightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
@@ -373,7 +373,7 @@ msgstr "Napauta tästä jatkaaksesi."
373
373
374#: qml/Tutorial/TutorialContent.qml:81
374#: qml/Tutorial/TutorialContent.qml:81
375msgid "Click here to finish."
375msgid "Click here to finish."
376−msgstr ""
376+msgstr "Viimeistele napsauttamalla tästä."
377
377
378#: qml/Tutorial/TutorialLeftFinish.qml:24
378#: qml/Tutorial/TutorialLeftFinish.qml:24
379msgid "These are the shortcuts to favorite apps"
379msgid "These are the shortcuts to favorite apps"
po/ia.po+94−83
@@ -8,15 +8,15 @@ 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: 2015-04-14 16:13+0200\n"
10"POT-Creation-Date: 2015-04-14 16:13+0200\n"
11−"PO-Revision-Date: 2015-04-27 10:07+0000\n"
11+"PO-Revision-Date: 2015-06-08 18:58+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
12+"Last-Translator: karm <melo@carmu.com>\n"
13"Language-Team: Interlingua <ia@li.org>\n"
13"Language-Team: Interlingua <ia@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"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-04-28 05:33+0000\n"
18+"X-Launchpad-Export-Date: 2015-06-09 05:42+0000\n"
19−"X-Generator: Launchpad (build 17453)\n"
19+"X-Generator: Launchpad (build 17549)\n"
20
20
21#: plugins/LightDM/Greeter.cpp:112
21#: plugins/LightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
@@ -29,7 +29,7 @@ msgstr "Via-breve a pin"
29
29
30#: plugins/Unity/Launcher/launcheritem.cpp:100
30#: plugins/Unity/Launcher/launcheritem.cpp:100
31msgid "Unpin shortcut"
31msgid "Unpin shortcut"
32−msgstr "Via-breve levar pin"
32+msgstr "Via-breve a levar pin"
33
33
34#: qml/Components/DelayedLockscreen.qml:49
34#: qml/Components/DelayedLockscreen.qml:49
35msgid "Device Locked"
35msgid "Device Locked"
@@ -49,13 +49,13 @@ msgstr ""
49#, qt-format
49#, qt-format
50msgid "Please wait %1 minute and then try again…"
50msgid "Please wait %1 minute and then try again…"
51msgid_plural "Please wait %1 minutes and then try again…"
51msgid_plural "Please wait %1 minutes and then try again…"
52−msgstr[0] "Per favor attende %1 minuta e postea tentar de nove"
52+msgstr[0] "Per favor attende %1 minuta e postea tenta de nove"
53msgstr[1] "Per favor attende %1 minutas e postea tentar de nove"
53msgstr[1] "Per favor attende %1 minutas e postea tentar de nove"
54
54
55#: qml/Components/Dialogs.qml:69
55#: qml/Components/Dialogs.qml:69
56msgctxt "Title: Lock/Log out dialog"
56msgctxt "Title: Lock/Log out dialog"
57msgid "Log out"
57msgid "Log out"
58−msgstr ""
58+msgstr "Clauder de session"
59
59
60#: qml/Components/Dialogs.qml:70
60#: qml/Components/Dialogs.qml:70
61msgid "Are you sure you want to log out?"
61msgid "Are you sure you want to log out?"
@@ -64,12 +64,12 @@ msgstr "Desira tu vermente Clauder le Session"
64#: qml/Components/Dialogs.qml:72
64#: qml/Components/Dialogs.qml:72
65msgctxt "Button: Lock the system"
65msgctxt "Button: Lock the system"
66msgid "Lock"
66msgid "Lock"
67−msgstr ""
67+msgstr "Blocar"
68
68
69#: qml/Components/Dialogs.qml:79
69#: qml/Components/Dialogs.qml:79
70msgctxt "Button: Log out from the system"
70msgctxt "Button: Log out from the system"
71msgid "Log Out"
71msgid "Log Out"
72−msgstr ""
72+msgstr "Claude session"
73
73
74#: qml/Components/Dialogs.qml:86 qml/Components/Dialogs.qml:117
74#: qml/Components/Dialogs.qml:86 qml/Components/Dialogs.qml:117
75#: qml/Components/Dialogs.qml:173
75#: qml/Components/Dialogs.qml:173
@@ -79,7 +79,7 @@ msgstr "Cancellar"
79#: qml/Components/Dialogs.qml:98
79#: qml/Components/Dialogs.qml:98
80msgctxt "Title: Reboot/Shut down dialog"
80msgctxt "Title: Reboot/Shut down dialog"
81msgid "Shut down"
81msgid "Shut down"
82−msgstr ""
82+msgstr "Stoppar"
83
83
84#: qml/Components/Dialogs.qml:99
84#: qml/Components/Dialogs.qml:99
85msgid "Are you sure you want to shut down?"
85msgid "Are you sure you want to shut down?"
@@ -88,21 +88,21 @@ msgstr "Desira tu vermente Stoppar"
88#: qml/Components/Dialogs.qml:101
88#: qml/Components/Dialogs.qml:101
89msgctxt "Button: Reboot the system"
89msgctxt "Button: Reboot the system"
90msgid "Reboot"
90msgid "Reboot"
91−msgstr ""
91+msgstr "Reinitiar"
92
92
93#: qml/Components/Dialogs.qml:109
93#: qml/Components/Dialogs.qml:109
94msgctxt "Button: Shut down the system"
94msgctxt "Button: Shut down the system"
95msgid "Shut down"
95msgid "Shut down"
96−msgstr ""
96+msgstr "Stoppar"
97
97
98#: qml/Components/Dialogs.qml:129
98#: qml/Components/Dialogs.qml:129
99msgctxt "Title: Reboot dialog"
99msgctxt "Title: Reboot dialog"
100msgid "Reboot"
100msgid "Reboot"
101−msgstr ""
101+msgstr "Reinitiar"
102
102
103#: qml/Components/Dialogs.qml:130
103#: qml/Components/Dialogs.qml:130
104msgid "Are you sure you want to reboot?"
104msgid "Are you sure you want to reboot?"
105−msgstr "Desira tu vermente Reinitiar"
105+msgstr "Desira tu vermente reinitiar"
106
106
107#: qml/Components/Dialogs.qml:132
107#: qml/Components/Dialogs.qml:132
108msgid "No"
108msgid "No"
@@ -115,7 +115,7 @@ msgstr "Si"
115#: qml/Components/Dialogs.qml:152
115#: qml/Components/Dialogs.qml:152
116msgctxt "Title: Power off/Restart dialog"
116msgctxt "Title: Power off/Restart dialog"
117msgid "Power"
117msgid "Power"
118−msgstr ""
118+msgstr "Energia"
119
119
120#: qml/Components/Dialogs.qml:153
120#: qml/Components/Dialogs.qml:153
121msgid ""
121msgid ""
@@ -123,17 +123,17 @@ msgid ""
123"to power off?"
123"to power off?"
124msgstr ""
124msgstr ""
125"Desira tu vermente \n"
125"Desira tu vermente \n"
126−"Stoppar le energia?"
126+"stoppar le energia?"
127
127
128#: qml/Components/Dialogs.qml:155
128#: qml/Components/Dialogs.qml:155
129msgctxt "Button: Power off the system"
129msgctxt "Button: Power off the system"
130msgid "Power off"
130msgid "Power off"
131−msgstr ""
131+msgstr "Stoppar le energia"
132
132
133#: qml/Components/Dialogs.qml:164
133#: qml/Components/Dialogs.qml:164
134msgctxt "Button: Restart the system"
134msgctxt "Button: Restart the system"
135msgid "Restart"
135msgid "Restart"
136−msgstr ""
136+msgstr "Reinitiar"
137
137
138#: qml/Components/Lockscreen.qml:245
138#: qml/Components/Lockscreen.qml:245
139msgid "Return to Call"
139msgid "Return to Call"
@@ -158,22 +158,22 @@ msgstr "Vider toto"
158#: qml/Dash/GenericScopeView.qml:594
158#: qml/Dash/GenericScopeView.qml:594
159msgctxt "Label: Hint for dash search line edit"
159msgctxt "Label: Hint for dash search line edit"
160msgid "Search"
160msgid "Search"
161−msgstr ""
161+msgstr "Cerca"
162
162
163#: qml/Dash/PageHeader.qml:269
163#: qml/Dash/PageHeader.qml:269
164msgctxt "Button: Open the Ubuntu Store"
164msgctxt "Button: Open the Ubuntu Store"
165msgid "Store"
165msgid "Store"
166−msgstr ""
166+msgstr "Salva"
167
167
168#: qml/Dash/PageHeader.qml:276
168#: qml/Dash/PageHeader.qml:276
169msgctxt "Button: Start a search in the current dash scope"
169msgctxt "Button: Start a search in the current dash scope"
170msgid "Search"
170msgid "Search"
171−msgstr ""
171+msgstr "Cerca"
172
172
173#: qml/Dash/PageHeader.qml:286
173#: qml/Dash/PageHeader.qml:286
174msgctxt "Button: Show the current dash scope settings"
174msgctxt "Button: Show the current dash scope settings"
175msgid "Settings"
175msgid "Settings"
176−msgstr ""
176+msgstr "Configurationes"
177
177
178#: qml/Dash/PageHeader.qml:293
178#: qml/Dash/PageHeader.qml:293
179msgid "Remove from Favorites"
179msgid "Remove from Favorites"
@@ -213,7 +213,7 @@ msgstr "Relaxar pro renovar…"
213
213
214#: qml/Dash/ScopeSettings/ScopeSettingBoolean.qml:43
214#: qml/Dash/ScopeSettings/ScopeSettingBoolean.qml:43
215msgid "Enable location data"
215msgid "Enable location data"
216−msgstr ""
216+msgstr "Habilita le datos del location"
217
217
218#: qml/Dash/ScopesList.qml:66
218#: qml/Dash/ScopesList.qml:66
219msgid "Manage"
219msgid "Manage"
@@ -233,11 +233,11 @@ msgstr "Liberar"
233
233
234#: qml/Greeter/LoginList.qml:236
234#: qml/Greeter/LoginList.qml:236
235msgid "Retry"
235msgid "Retry"
236−msgstr ""
236+msgstr "Re-provar"
237
237
238#: qml/Greeter/LoginList.qml:237
238#: qml/Greeter/LoginList.qml:237
239msgid "Tap to unlock"
239msgid "Tap to unlock"
240−msgstr ""
240+msgstr "Pulsa pro liberar"
241
241
242#: qml/Greeter/NarrowView.qml:53 qml/Wizard/Pages/passwd-confirm.qml:53
242#: qml/Greeter/NarrowView.qml:53 qml/Wizard/Pages/passwd-confirm.qml:53
243msgid "Sorry, incorrect passphrase."
243msgid "Sorry, incorrect passphrase."
@@ -299,7 +299,7 @@ msgstr "Displacente, codice-contrasigno incorrecte"
299
299
300#: qml/Notifications/NotificationMenuItemFactory.qml:128
300#: qml/Notifications/NotificationMenuItemFactory.qml:128
301msgid "Show password"
301msgid "Show password"
302−msgstr "Monstra le contrasigno"
302+msgstr "Monstrar le contrasigno"
303
303
304#: qml/Panel/ActiveCallHint.qml:79
304#: qml/Panel/ActiveCallHint.qml:79
305msgid "Tap to return to call..."
305msgid "Tap to return to call..."
@@ -340,7 +340,7 @@ msgstr "Fallite, colpar pro re-provar"
340#: qml/Panel/Indicators/MessageMenuItemFactory.qml:149
340#: qml/Panel/Indicators/MessageMenuItemFactory.qml:149
341msgctxt "Label: Hint in message indicator line edit"
341msgctxt "Label: Hint in message indicator line edit"
342msgid "Reply"
342msgid "Reply"
343−msgstr ""
343+msgstr "Responde"
344
344
345#: qml/Panel/Indicators/ModemInfoItem.qml:105
345#: qml/Panel/Indicators/ModemInfoItem.qml:105
346msgid "Unlock SIM"
346msgid "Unlock SIM"
@@ -352,162 +352,165 @@ msgstr "Roaming"
352
352
353#: qml/Tutorial/TutorialBottomFinish.qml:24
353#: qml/Tutorial/TutorialBottomFinish.qml:24
354msgid "This action does different things for different apps"
354msgid "This action does different things for different apps"
355−msgstr ""
355+msgstr "Iste action ha effectos differente pro applicationes differente"
356
356
357#: qml/Tutorial/TutorialBottomFinish.qml:25
357#: qml/Tutorial/TutorialBottomFinish.qml:25
358msgid "Tap here to finish."
358msgid "Tap here to finish."
359−msgstr ""
359+msgstr "Pulsa ci pro finir"
360
360
361#: qml/Tutorial/TutorialBottom.qml:28
361#: qml/Tutorial/TutorialBottom.qml:28
362msgid "Open special menus"
362msgid "Open special menus"
363−msgstr ""
363+msgstr "Aperi le menus special"
364
364
365#: qml/Tutorial/TutorialBottom.qml:29
365#: qml/Tutorial/TutorialBottom.qml:29
366msgid "Swipe up from the bottom edge."
366msgid "Swipe up from the bottom edge."
367−msgstr ""
367+msgstr "Stria in alto ex le bordo basse."
368
368
369#: qml/Tutorial/TutorialContent.qml:81 qml/Tutorial/TutorialLeftFinish.qml:25
369#: qml/Tutorial/TutorialContent.qml:81 qml/Tutorial/TutorialLeftFinish.qml:25
370#: qml/Tutorial/TutorialRight.qml:144
370#: qml/Tutorial/TutorialRight.qml:144
371msgid "Tap here to continue."
371msgid "Tap here to continue."
372−msgstr ""
372+msgstr "Pulsa ci pro continuar"
373
373
374#: qml/Tutorial/TutorialContent.qml:81
374#: qml/Tutorial/TutorialContent.qml:81
375msgid "Click here to finish."
375msgid "Click here to finish."
376−msgstr ""
376+msgstr "Clicca ci pro finir"
377
377
378#: qml/Tutorial/TutorialLeftFinish.qml:24
378#: qml/Tutorial/TutorialLeftFinish.qml:24
379msgid "These are the shortcuts to favorite apps"
379msgid "These are the shortcuts to favorite apps"
380−msgstr ""
380+msgstr "Iste es le vias breve al applicationes favorite"
381
381
382#: qml/Tutorial/TutorialLeft.qml:26
382#: qml/Tutorial/TutorialLeft.qml:26
383msgid "Open the launcher"
383msgid "Open the launcher"
384−msgstr ""
384+msgstr "Aperi le lanceator"
385
385
386#: qml/Tutorial/TutorialLeft.qml:27
386#: qml/Tutorial/TutorialLeft.qml:27
387msgid "Short swipe from the left edge."
387msgid "Short swipe from the left edge."
388−msgstr ""
388+msgstr "Stria curte ex le bordo sinistre."
389
389
390#: qml/Tutorial/TutorialPage.qml:178
390#: qml/Tutorial/TutorialPage.qml:178
391msgid "You almost got it!"
391msgid "You almost got it!"
392−msgstr ""
392+msgstr "Tu ha quasi obtenite lo!"
393
393
394#: qml/Tutorial/TutorialPage.qml:195
394#: qml/Tutorial/TutorialPage.qml:195
395msgid "Try again."
395msgid "Try again."
396−msgstr ""
396+msgstr "Prova de novo"
397
397
398#: qml/Tutorial/TutorialRight.qml:31
398#: qml/Tutorial/TutorialRight.qml:31
399msgid "To view open apps"
399msgid "To view open apps"
400−msgstr ""
400+msgstr "Aperi le applicationes pro vider"
401
401
402#: qml/Tutorial/TutorialRight.qml:32
402#: qml/Tutorial/TutorialRight.qml:32
403msgid "Long swipe from the right edge."
403msgid "Long swipe from the right edge."
404−msgstr ""
404+msgstr "Stria longemente ex le bordo dextre."
405
405
406#: qml/Tutorial/TutorialRight.qml:122
406#: qml/Tutorial/TutorialRight.qml:122
407msgid "View all your running tasks."
407msgid "View all your running tasks."
408−msgstr ""
408+msgstr "Vide tote tu tasks fluente"
409
409
410#: qml/Wizard/Page.qml:89
410#: qml/Wizard/Page.qml:89
411msgctxt "Button: Go back one page in the Wizard"
411msgctxt "Button: Go back one page in the Wizard"
412msgid "Back"
412msgid "Back"
413−msgstr ""
413+msgstr "Retro"
414
414
415#: qml/Wizard/Pages/10-welcome.qml:27
415#: qml/Wizard/Pages/10-welcome.qml:27
416msgid "Hi!"
416msgid "Hi!"
417−msgstr ""
417+msgstr "Salute!"
418
418
419#: qml/Wizard/Pages/10-welcome.qml:44
419#: qml/Wizard/Pages/10-welcome.qml:44
420msgid "Welcome to your Ubuntu phone."
420msgid "Welcome to your Ubuntu phone."
421−msgstr ""
421+msgstr "Benvenite a tu telephono Ubuntu."
422
422
423#: qml/Wizard/Pages/10-welcome.qml:52
423#: qml/Wizard/Pages/10-welcome.qml:52
424msgid "Let’s get started."
424msgid "Let’s get started."
425−msgstr ""
425+msgstr "Que nos initia."
426
426
427#: qml/Wizard/Pages/10-welcome.qml:88 qml/Wizard/Pages/30-passwd-type.qml:128
427#: qml/Wizard/Pages/10-welcome.qml:88 qml/Wizard/Pages/30-passwd-type.qml:128
428#: qml/Wizard/Pages/40-wifi.qml:215 qml/Wizard/Pages/50-location.qml:131
428#: qml/Wizard/Pages/40-wifi.qml:215 qml/Wizard/Pages/50-location.qml:131
429#: qml/Wizard/Pages/60-reporting.qml:50 qml/Wizard/Pages/passwd-confirm.qml:82
429#: qml/Wizard/Pages/60-reporting.qml:50 qml/Wizard/Pages/passwd-confirm.qml:82
430#: qml/Wizard/Pages/passwd-set.qml:90
430#: qml/Wizard/Pages/passwd-set.qml:90
431msgid "Continue"
431msgid "Continue"
432−msgstr ""
432+msgstr "Continua"
433
433
434#: qml/Wizard/Pages/20-sim.qml:25
434#: qml/Wizard/Pages/20-sim.qml:25
435msgid "Add a SIM card and restart your device"
435msgid "Add a SIM card and restart your device"
436−msgstr ""
436+msgstr "Adde un carta SIM e reinitia tu dispositivo"
437
437
438#: qml/Wizard/Pages/20-sim.qml:59
438#: qml/Wizard/Pages/20-sim.qml:59
439msgid "Without it, you won’t be able to make calls or use text messaging."
439msgid "Without it, you won’t be able to make calls or use text messaging."
440msgstr ""
440msgstr ""
441+"Sin illo, tu non es habile a facer appellos o usar le messages de texto."
441
442
442#: qml/Wizard/Pages/20-sim.qml:73 qml/Wizard/Pages/40-wifi.qml:215
443#: qml/Wizard/Pages/20-sim.qml:73 qml/Wizard/Pages/40-wifi.qml:215
443msgid "Skip"
444msgid "Skip"
444−msgstr ""
445+msgstr "Salta"
445
446
446#: qml/Wizard/Pages/30-passwd-type.qml:39
447#: qml/Wizard/Pages/30-passwd-type.qml:39
447msgid "Lock security"
448msgid "Lock security"
448−msgstr ""
449+msgstr "Bloco de securitate"
449
450
450#: qml/Wizard/Pages/30-passwd-type.qml:74
451#: qml/Wizard/Pages/30-passwd-type.qml:74
451msgid "Please select how you’d like to unlock your phone."
452msgid "Please select how you’d like to unlock your phone."
452−msgstr ""
453+msgstr "Per favor selige in qual maniera disblocar tu telephono."
453
454
454#: qml/Wizard/Pages/30-passwd-type.qml:97
455#: qml/Wizard/Pages/30-passwd-type.qml:97
455msgctxt "Label: Type of security method"
456msgctxt "Label: Type of security method"
456msgid "Swipe"
457msgid "Swipe"
457−msgstr ""
458+msgstr "Striar"
458
459
459#: qml/Wizard/Pages/30-passwd-type.qml:98
460#: qml/Wizard/Pages/30-passwd-type.qml:98
460msgctxt "Label: Description of security method"
461msgctxt "Label: Description of security method"
461msgid "No security"
462msgid "No security"
462−msgstr ""
463+msgstr "Nulle securitate"
463
464
464#: qml/Wizard/Pages/30-passwd-type.qml:100
465#: qml/Wizard/Pages/30-passwd-type.qml:100
465msgctxt "Label: Type of security method"
466msgctxt "Label: Type of security method"
466msgid "Passcode"
467msgid "Passcode"
467−msgstr ""
468+msgstr "Codice-contrasigno"
468
469
469#: qml/Wizard/Pages/30-passwd-type.qml:101
470#: qml/Wizard/Pages/30-passwd-type.qml:101
470msgctxt "Label: Description of security method"
471msgctxt "Label: Description of security method"
471msgid "4 digits only"
472msgid "4 digits only"
472−msgstr ""
473+msgstr "4 cifras sol"
473
474
474#: qml/Wizard/Pages/30-passwd-type.qml:103
475#: qml/Wizard/Pages/30-passwd-type.qml:103
475msgctxt "Label: Type of security method"
476msgctxt "Label: Type of security method"
476msgid "Passphrase"
477msgid "Passphrase"
477−msgstr ""
478+msgstr "Phrase-contrasigno"
478
479
479#: qml/Wizard/Pages/30-passwd-type.qml:104
480#: qml/Wizard/Pages/30-passwd-type.qml:104
480msgctxt "Label: Description of security method"
481msgctxt "Label: Description of security method"
481msgid "Numbers and letters"
482msgid "Numbers and letters"
482−msgstr ""
483+msgstr "Numeros e litteras"
483
484
484#: qml/Wizard/Pages/40-wifi.qml:29
485#: qml/Wizard/Pages/40-wifi.qml:29
485msgid "Connect to Wi‑Fi"
486msgid "Connect to Wi‑Fi"
486−msgstr ""
487+msgstr "Connecter al Wi‑Fi"
487
488
488#: qml/Wizard/Pages/40-wifi.qml:168
489#: qml/Wizard/Pages/40-wifi.qml:168
489msgid "Available networks…"
490msgid "Available networks…"
490−msgstr ""
491+msgstr "Retes disponibile..."
491
492
492#: qml/Wizard/Pages/40-wifi.qml:169
493#: qml/Wizard/Pages/40-wifi.qml:169
493msgid "No available networks."
494msgid "No available networks."
494−msgstr ""
495+msgstr "Nulle rete disponibile."
495
496
496#: qml/Wizard/Pages/50-location.qml:27
497#: qml/Wizard/Pages/50-location.qml:27
497msgid "Location"
498msgid "Location"
498−msgstr ""
499+msgstr "Location"
499
500
500#: qml/Wizard/Pages/50-location.qml:62
501#: qml/Wizard/Pages/50-location.qml:62
501msgid "Let the phone detect your location:"
502msgid "Let the phone detect your location:"
502−msgstr ""
503+msgstr "Lassar le telephono disvelar tu position:"
503
504
504#: qml/Wizard/Pages/50-location.qml:69
505#: qml/Wizard/Pages/50-location.qml:69
505msgid "Using GPS only (less accurate)"
506msgid "Using GPS only (less accurate)"
506−msgstr ""
507+msgstr "Usar sol le GPS (minus accurate)"
507
508
508#: qml/Wizard/Pages/50-location.qml:86
509#: qml/Wizard/Pages/50-location.qml:86
509msgid "Using GPS, anonymized Wi-Fi and cellular network info (recommended)"
510msgid "Using GPS, anonymized Wi-Fi and cellular network info (recommended)"
510msgstr ""
511msgstr ""
512+"Usar le GPS, le Wi-Fi in modo anonyme e le informationes del rete cellular "
513+"(recommendate)"
511
514
512#. TRANSLATORS: HERE is a trademark for Nokia's location service, you probably shouldn't translate it
515#. TRANSLATORS: HERE is a trademark for Nokia's location service, you probably shouldn't translate it
513#: qml/Wizard/Pages/50-location.qml:103
516#: qml/Wizard/Pages/50-location.qml:103
@@ -515,81 +518,89 @@ msgid ""
515"By selecting this option you agree to the Nokia HERE <a href='#'>terms and "
518"By selecting this option you agree to the Nokia HERE <a href='#'>terms and "
516"conditions</a>."
519"conditions</a>."
517msgstr ""
520msgstr ""
521+"Per le selection de iste option tu esser de accordo con le Nokia HERE <a "
522+"href='#'>terminos e conditiones</a>."
518
523
519#: qml/Wizard/Pages/50-location.qml:112
524#: qml/Wizard/Pages/50-location.qml:112
520msgid "Not at all"
525msgid "Not at all"
521−msgstr ""
526+msgstr "No, del toto"
522
527
523#: qml/Wizard/Pages/50-location.qml:124
528#: qml/Wizard/Pages/50-location.qml:124
524msgid "You can change your mind later in <b>System Settings</b>."
529msgid "You can change your mind later in <b>System Settings</b>."
525msgstr ""
530msgstr ""
531+"Tu pote cambiar tu desiderata plus tarde in <b>Configurationes del "
532+"systema</b>."
526
533
527#: qml/Wizard/Pages/60-reporting.qml:24
534#: qml/Wizard/Pages/60-reporting.qml:24
528msgid "Improving your experience"
535msgid "Improving your experience"
529−msgstr ""
536+msgstr "Affinamento de tu experientia"
530
537
531#: qml/Wizard/Pages/60-reporting.qml:36
538#: qml/Wizard/Pages/60-reporting.qml:36
532msgid ""
539msgid ""
533"Your phone is set up to automatically report errors to Canonical and its "
540"Your phone is set up to automatically report errors to Canonical and its "
534"partners, the makers of the operating system."
541"partners, the makers of the operating system."
535msgstr ""
542msgstr ""
543+"Tu telephono es configurate a reportar automaticamente le errores a "
544+"Canonical e su socios, le fabricantes del systema operative."
536
545
537#: qml/Wizard/Pages/60-reporting.qml:43
546#: qml/Wizard/Pages/60-reporting.qml:43
538msgid ""
547msgid ""
539"This can be disabled in <b>System Settings</b> under <b>Security &amp; "
548"This can be disabled in <b>System Settings</b> under <b>Security &amp; "
540"Privacy</b>"
549"Privacy</b>"
541msgstr ""
550msgstr ""
551+"Isto pote esser impedite in <b>Preparationes del systema</b> sub "
552+"<b>Securitate &amp; Confidentialitate</b>"
542
553
543#: qml/Wizard/Pages/80-finished.qml:24
554#: qml/Wizard/Pages/80-finished.qml:24
544msgid "All done"
555msgid "All done"
545−msgstr ""
556+msgstr "Toto preste"
546
557
547#: qml/Wizard/Pages/80-finished.qml:39
558#: qml/Wizard/Pages/80-finished.qml:39
548msgid "Nice work!"
559msgid "Nice work!"
549−msgstr ""
560+msgstr "Belle obra!"
550
561
551#: qml/Wizard/Pages/80-finished.qml:46
562#: qml/Wizard/Pages/80-finished.qml:46
552msgid "Your phone is now ready to use."
563msgid "Your phone is now ready to use."
553−msgstr ""
564+msgstr "Tu telephono es ora preste al uso."
554
565
555#: qml/Wizard/Pages/80-finished.qml:53
566#: qml/Wizard/Pages/80-finished.qml:53
556msgid "Finish"
567msgid "Finish"
557−msgstr ""
568+msgstr "Fin"
558
569
559#: qml/Wizard/Pages/here-terms.qml:27
570#: qml/Wizard/Pages/here-terms.qml:27
560msgid "Terms & Conditions"
571msgid "Terms & Conditions"
561−msgstr ""
572+msgstr "Terminos & Conditiones"
562
573
563#: qml/Wizard/Pages/passwd-confirm.qml:49
574#: qml/Wizard/Pages/passwd-confirm.qml:49
564msgid "Confirm passphrase"
575msgid "Confirm passphrase"
565−msgstr ""
576+msgstr "Confirma le phrase-contrasigno"
566
577
567#: qml/Wizard/Pages/passwd-confirm.qml:50
578#: qml/Wizard/Pages/passwd-confirm.qml:50
568msgid "Confirm passcode"
579msgid "Confirm passcode"
569−msgstr ""
580+msgstr "Confirma le codice-contrasigno"
570
581
571#: qml/Wizard/Pages/passwd-confirm.qml:53
582#: qml/Wizard/Pages/passwd-confirm.qml:53
572#: qml/Wizard/Pages/passwd-confirm.qml:54
583#: qml/Wizard/Pages/passwd-confirm.qml:54
573msgid "Please try again."
584msgid "Please try again."
574−msgstr ""
585+msgstr "Reproba per favor."
575
586
576#: qml/Wizard/Pages/passwd-set.qml:61
587#: qml/Wizard/Pages/passwd-set.qml:61
577msgid "Choose your passcode"
588msgid "Choose your passcode"
578−msgstr ""
589+msgstr "Selige tu codice-contrasigno"
579
590
580#: qml/Wizard/Pages/passwd-set.qml:68
591#: qml/Wizard/Pages/passwd-set.qml:68
581msgid "Passphrase must be 4 characters long"
592msgid "Passphrase must be 4 characters long"
582−msgstr ""
593+msgstr "Le phrase-contrasigno debe esser longe 4 characteres"
583
594
584#: qml/Wizard/StackButton.qml:39
595#: qml/Wizard/StackButton.qml:39
585#, qt-format
596#, qt-format
586msgid "〈 %1"
597msgid "〈 %1"
587−msgstr ""
598+msgstr "〈 %1"
588
599
589#: qml/Wizard/StackButton.qml:42
600#: qml/Wizard/StackButton.qml:42
590#, qt-format
601#, qt-format
591msgid "%1 〉"
602msgid "%1 〉"
592−msgstr ""
603+msgstr "%1 〉"
593
604
594#~ msgid "Log out"
605#~ msgid "Log out"
595#~ msgstr "Clauder le Session"
606#~ msgstr "Clauder le Session"
@@ -641,13 +652,6 @@ msgstr ""
641#~ msgid "Well done"
652#~ msgid "Well done"
642#~ msgstr "Ben!"
653#~ msgstr "Ben!"
643
654
644−#~ msgid ""
645−#~ "You have now mastered the edge gestures and can start using the "
646−#~ "phone<br><br>Tap on the screen to start"
647−#~ msgstr ""
648−#~ "Tu ha ora maestrate le gestos del bordo e pote initiar usar le "
649−#~ "telephono<br><br>colpar sur le schermo pro initiar"
650−
651#~ msgid "Search"
655#~ msgid "Search"
652#~ msgstr "Cercar"
656#~ msgstr "Cercar"
653
657
@@ -671,3 +675,10 @@ msgstr ""
671
675
672#~ msgid "Speaking..."
676#~ msgid "Speaking..."
673#~ msgstr "Parlante..."
677#~ msgstr "Parlante..."
678+
679+#~ msgid ""
680+#~ "You have now mastered the edge gestures and can start using the "
681+#~ "phone<br><br>Tap on the screen to start"
682+#~ msgstr ""
683+#~ "Tu es ora maestrate le gestos del bordo e pote initiar usar le "
684+#~ "telephono<br><br>colpar sur le schermo pro initiar"
po/nb.po+8−8
@@ -8,15 +8,15 @@ 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: 2015-04-14 16:13+0200\n"
10"POT-Creation-Date: 2015-04-14 16:13+0200\n"
11−"PO-Revision-Date: 2015-03-20 14:03+0000\n"
11+"PO-Revision-Date: 2015-06-03 02:43+0000\n"
12−"Last-Translator: Åka Sikrom <Unknown>\n"
12+"Last-Translator: Eirik Garatun <eikknud@gmail.com>\n"
13"Language-Team: Norwegian Bokmal <nb@li.org>\n"
13"Language-Team: Norwegian Bokmal <nb@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"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-04-23 06:48+0000\n"
18+"X-Launchpad-Export-Date: 2015-06-05 05:58+0000\n"
19−"X-Generator: Launchpad (build 17430)\n"
19+"X-Generator: Launchpad (build 17540)\n"
20
20
21#: plugins/LightDM/Greeter.cpp:112
21#: plugins/LightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
@@ -163,17 +163,17 @@ msgstr "Søk"
163#: qml/Dash/PageHeader.qml:269
163#: qml/Dash/PageHeader.qml:269
164msgctxt "Button: Open the Ubuntu Store"
164msgctxt "Button: Open the Ubuntu Store"
165msgid "Store"
165msgid "Store"
166−msgstr ""
166+msgstr "Butikk"
167
167
168#: qml/Dash/PageHeader.qml:276
168#: qml/Dash/PageHeader.qml:276
169msgctxt "Button: Start a search in the current dash scope"
169msgctxt "Button: Start a search in the current dash scope"
170msgid "Search"
170msgid "Search"
171−msgstr ""
171+msgstr "Søk"
172
172
173#: qml/Dash/PageHeader.qml:286
173#: qml/Dash/PageHeader.qml:286
174msgctxt "Button: Show the current dash scope settings"
174msgctxt "Button: Show the current dash scope settings"
175msgid "Settings"
175msgid "Settings"
176−msgstr ""
176+msgstr "Innstillinger"
177
177
178#: qml/Dash/PageHeader.qml:293
178#: qml/Dash/PageHeader.qml:293
179msgid "Remove from Favorites"
179msgid "Remove from Favorites"
@@ -373,7 +373,7 @@ msgstr "Trykk her for å fortsette."
373
373
374#: qml/Tutorial/TutorialContent.qml:81
374#: qml/Tutorial/TutorialContent.qml:81
375msgid "Click here to finish."
375msgid "Click here to finish."
376−msgstr ""
376+msgstr "Trykk her for å fullføre."
377
377
378#: qml/Tutorial/TutorialLeftFinish.qml:24
378#: qml/Tutorial/TutorialLeftFinish.qml:24
379msgid "These are the shortcuts to favorite apps"
379msgid "These are the shortcuts to favorite apps"
po/nn.ponew file+584
@@ -0,0 +1,584 @@
1+# Norwegian Nynorsk translation for unity8
2+# Copyright (c) 2015 Rosetta Contributors and Canonical Ltd 2015
3+# This file is distributed under the same license as the unity8 package.
4+# FIRST AUTHOR <EMAIL@ADDRESS>, 2015.
5+#
6+msgid ""
7+msgstr ""
8+"Project-Id-Version: unity8\n"
9+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10+"POT-Creation-Date: 2015-04-14 16:13+0200\n"
11+"PO-Revision-Date: 2015-05-12 11:32+0000\n"
12+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13+"Language-Team: Norwegian Nynorsk <nn@li.org>\n"
14+"MIME-Version: 1.0\n"
15+"Content-Type: text/plain; charset=UTF-8\n"
16+"Content-Transfer-Encoding: 8bit\n"
17+"Plural-Forms: nplurals=2; plural=n != 1;\n"
18+"X-Launchpad-Export-Date: 2015-05-13 05:31+0000\n"
19+"X-Generator: Launchpad (build 17493)\n"
20+
21+#: plugins/LightDM/Greeter.cpp:112
22+msgid "Password: "
23+msgstr ""
24+
25+#: plugins/Unity/Launcher/launcheritem.cpp:45
26+#: plugins/Unity/Launcher/launcheritem.cpp:100
27+msgid "Pin shortcut"
28+msgstr ""
29+
30+#: plugins/Unity/Launcher/launcheritem.cpp:100
31+msgid "Unpin shortcut"
32+msgstr ""
33+
34+#: qml/Components/DelayedLockscreen.qml:49
35+msgid "Device Locked"
36+msgstr ""
37+
38+#: qml/Components/DelayedLockscreen.qml:64
39+msgid "You have been locked out due to too many failed passphrase attempts."
40+msgstr ""
41+
42+#: qml/Components/DelayedLockscreen.qml:65
43+msgid "You have been locked out due to too many failed passcode attempts."
44+msgstr ""
45+
46+#: qml/Components/DelayedLockscreen.qml:74
47+#, qt-format
48+msgid "Please wait %1 minute and then try again…"
49+msgid_plural "Please wait %1 minutes and then try again…"
50+msgstr[0] ""
51+msgstr[1] ""
52+
53+#: qml/Components/Dialogs.qml:69
54+msgctxt "Title: Lock/Log out dialog"
55+msgid "Log out"
56+msgstr ""
57+
58+#: qml/Components/Dialogs.qml:70
59+msgid "Are you sure you want to log out?"
60+msgstr ""
61+
62+#: qml/Components/Dialogs.qml:72
63+msgctxt "Button: Lock the system"
64+msgid "Lock"
65+msgstr ""
66+
67+#: qml/Components/Dialogs.qml:79
68+msgctxt "Button: Log out from the system"
69+msgid "Log Out"
70+msgstr ""
71+
72+#: qml/Components/Dialogs.qml:86 qml/Components/Dialogs.qml:117
73+#: qml/Components/Dialogs.qml:173
74+msgid "Cancel"
75+msgstr ""
76+
77+#: qml/Components/Dialogs.qml:98
78+msgctxt "Title: Reboot/Shut down dialog"
79+msgid "Shut down"
80+msgstr ""
81+
82+#: qml/Components/Dialogs.qml:99
83+msgid "Are you sure you want to shut down?"
84+msgstr ""
85+
86+#: qml/Components/Dialogs.qml:101
87+msgctxt "Button: Reboot the system"
88+msgid "Reboot"
89+msgstr ""
90+
91+#: qml/Components/Dialogs.qml:109
92+msgctxt "Button: Shut down the system"
93+msgid "Shut down"
94+msgstr ""
95+
96+#: qml/Components/Dialogs.qml:129
97+msgctxt "Title: Reboot dialog"
98+msgid "Reboot"
99+msgstr ""
100+
101+#: qml/Components/Dialogs.qml:130
102+msgid "Are you sure you want to reboot?"
103+msgstr ""
104+
105+#: qml/Components/Dialogs.qml:132
106+msgid "No"
107+msgstr ""
108+
109+#: qml/Components/Dialogs.qml:138
110+msgid "Yes"
111+msgstr ""
112+
113+#: qml/Components/Dialogs.qml:152
114+msgctxt "Title: Power off/Restart dialog"
115+msgid "Power"
116+msgstr ""
117+
118+#: qml/Components/Dialogs.qml:153
119+msgid ""
120+"Are you sure you would like\n"
121+"to power off?"
122+msgstr ""
123+
124+#: qml/Components/Dialogs.qml:155
125+msgctxt "Button: Power off the system"
126+msgid "Power off"
127+msgstr ""
128+
129+#: qml/Components/Dialogs.qml:164
130+msgctxt "Button: Restart the system"
131+msgid "Restart"
132+msgstr ""
133+
134+#: qml/Components/Lockscreen.qml:245
135+msgid "Return to Call"
136+msgstr ""
137+
138+#: qml/Components/Lockscreen.qml:245
139+msgid "Emergency Call"
140+msgstr ""
141+
142+#: qml/Components/Lockscreen.qml:277
143+msgid "OK"
144+msgstr ""
145+
146+#: qml/Dash/GenericScopeView.qml:532 qml/Dash/GenericScopeView.qml:690
147+msgid "See less"
148+msgstr ""
149+
150+#: qml/Dash/GenericScopeView.qml:532
151+msgid "See all"
152+msgstr ""
153+
154+#: qml/Dash/GenericScopeView.qml:594
155+msgctxt "Label: Hint for dash search line edit"
156+msgid "Search"
157+msgstr ""
158+
159+#: qml/Dash/PageHeader.qml:269
160+msgctxt "Button: Open the Ubuntu Store"
161+msgid "Store"
162+msgstr ""
163+
164+#: qml/Dash/PageHeader.qml:276
165+msgctxt "Button: Start a search in the current dash scope"
166+msgid "Search"
167+msgstr ""
168+
169+#: qml/Dash/PageHeader.qml:286
170+msgctxt "Button: Show the current dash scope settings"
171+msgid "Settings"
172+msgstr ""
173+
174+#: qml/Dash/PageHeader.qml:293
175+msgid "Remove from Favorites"
176+msgstr ""
177+
178+#: qml/Dash/PageHeader.qml:293
179+msgid "Add to Favorites"
180+msgstr ""
181+
182+#: qml/Dash/Previews/PreviewActionCombo.qml:35
183+msgid "More..."
184+msgstr ""
185+
186+#: qml/Dash/Previews/PreviewActionCombo.qml:35
187+msgid "Less..."
188+msgstr ""
189+
190+#: qml/Dash/Previews/PreviewRatingInput.qml:81
191+msgid "Rate this"
192+msgstr ""
193+
194+#: qml/Dash/Previews/PreviewRatingInput.qml:126
195+msgid "Add a review"
196+msgstr ""
197+
198+#: qml/Dash/Previews/PreviewRatingInput.qml:166
199+msgid "Send"
200+msgstr ""
201+
202+#: qml/Dash/PullToRefreshScopeStyle.qml:55
203+msgid "Pull to refresh…"
204+msgstr ""
205+
206+#: qml/Dash/PullToRefreshScopeStyle.qml:60
207+msgid "Release to refresh…"
208+msgstr ""
209+
210+#: qml/Dash/ScopeSettings/ScopeSettingBoolean.qml:43
211+msgid "Enable location data"
212+msgstr ""
213+
214+#: qml/Dash/ScopesList.qml:66
215+msgid "Manage"
216+msgstr ""
217+
218+#: qml/Dash/ScopesList.qml:112
219+msgid "Home"
220+msgstr ""
221+
222+#: qml/Dash/ScopesList.qml:113
223+msgid "Also installed"
224+msgstr ""
225+
226+#: qml/Greeter/CoverPage.qml:107
227+msgid "Unlock"
228+msgstr ""
229+
230+#: qml/Greeter/LoginList.qml:236
231+msgid "Retry"
232+msgstr ""
233+
234+#: qml/Greeter/LoginList.qml:237
235+msgid "Tap to unlock"
236+msgstr ""
237+
238+#: qml/Greeter/NarrowView.qml:53 qml/Wizard/Pages/passwd-confirm.qml:53
239+msgid "Sorry, incorrect passphrase."
240+msgstr ""
241+
242+#: qml/Greeter/NarrowView.qml:54 qml/Wizard/Pages/passwd-confirm.qml:54
243+msgid "Sorry, incorrect passcode."
244+msgstr ""
245+
246+#: qml/Greeter/NarrowView.qml:55
247+msgid "This will be your last attempt."
248+msgstr ""
249+
250+#: qml/Greeter/NarrowView.qml:57
251+msgid ""
252+"If passphrase is entered incorrectly, your phone will conduct a factory "
253+"reset and all personal data will be deleted."
254+msgstr ""
255+
256+#: qml/Greeter/NarrowView.qml:58
257+msgid ""
258+"If passcode is entered incorrectly, your phone will conduct a factory reset "
259+"and all personal data will be deleted."
260+msgstr ""
261+
262+#: qml/Greeter/NarrowView.qml:115
263+#, qt-format
264+msgid "Enter %1"
265+msgstr ""
266+
267+#: qml/Greeter/NarrowView.qml:116 qml/Wizard/Pages/passwd-set.qml:60
268+msgid "Enter passphrase"
269+msgstr ""
270+
271+#: qml/Greeter/NarrowView.qml:117
272+msgid "Enter passcode"
273+msgstr ""
274+
275+#: qml/Greeter/NarrowView.qml:118
276+#, qt-format
277+msgid "Sorry, incorrect %1"
278+msgstr ""
279+
280+#: qml/Greeter/NarrowView.qml:119
281+msgid "Sorry, incorrect passphrase"
282+msgstr ""
283+
284+#: qml/Greeter/NarrowView.qml:120
285+msgid "Please re-enter"
286+msgstr ""
287+
288+#: qml/Greeter/NarrowView.qml:121
289+msgid "Sorry, incorrect passcode"
290+msgstr ""
291+
292+#: qml/Notifications/NotificationMenuItemFactory.qml:128
293+msgid "Show password"
294+msgstr ""
295+
296+#: qml/Panel/ActiveCallHint.qml:79
297+msgid "Tap to return to call..."
298+msgstr ""
299+
300+#: qml/Panel/ActiveCallHint.qml:92
301+msgid "Conference"
302+msgstr ""
303+
304+#: qml/Panel/Indicators/MenuItemFactory.qml:639
305+msgid "Nothing is playing"
306+msgstr ""
307+
308+#: qml/Panel/Indicators/MenuItemFactory.qml:787
309+msgid "In queue…"
310+msgstr ""
311+
312+#: qml/Panel/Indicators/MenuItemFactory.qml:791
313+msgid "Downloading"
314+msgstr ""
315+
316+#: qml/Panel/Indicators/MenuItemFactory.qml:793
317+msgid "Paused, tap to resume"
318+msgstr ""
319+
320+#: qml/Panel/Indicators/MenuItemFactory.qml:795
321+msgid "Canceled"
322+msgstr ""
323+
324+#: qml/Panel/Indicators/MenuItemFactory.qml:797
325+msgid "Finished"
326+msgstr ""
327+
328+#: qml/Panel/Indicators/MenuItemFactory.qml:799
329+msgid "Failed, tap to retry"
330+msgstr ""
331+
332+#: qml/Panel/Indicators/MessageMenuItemFactory.qml:149
333+msgctxt "Label: Hint in message indicator line edit"
334+msgid "Reply"
335+msgstr ""
336+
337+#: qml/Panel/Indicators/ModemInfoItem.qml:105
338+msgid "Unlock SIM"
339+msgstr ""
340+
341+#: qml/Panel/Indicators/RoamingIndication.qml:27
342+msgid "Roaming"
343+msgstr ""
344+
345+#: qml/Tutorial/TutorialBottomFinish.qml:24
346+msgid "This action does different things for different apps"
347+msgstr ""
348+
349+#: qml/Tutorial/TutorialBottomFinish.qml:25
350+msgid "Tap here to finish."
351+msgstr ""
352+
353+#: qml/Tutorial/TutorialBottom.qml:28
354+msgid "Open special menus"
355+msgstr ""
356+
357+#: qml/Tutorial/TutorialBottom.qml:29
358+msgid "Swipe up from the bottom edge."
359+msgstr ""
360+
361+#: qml/Tutorial/TutorialContent.qml:81 qml/Tutorial/TutorialLeftFinish.qml:25
362+#: qml/Tutorial/TutorialRight.qml:144
363+msgid "Tap here to continue."
364+msgstr ""
365+
366+#: qml/Tutorial/TutorialContent.qml:81
367+msgid "Click here to finish."
368+msgstr ""
369+
370+#: qml/Tutorial/TutorialLeftFinish.qml:24
371+msgid "These are the shortcuts to favorite apps"
372+msgstr ""
373+
374+#: qml/Tutorial/TutorialLeft.qml:26
375+msgid "Open the launcher"
376+msgstr ""
377+
378+#: qml/Tutorial/TutorialLeft.qml:27
379+msgid "Short swipe from the left edge."
380+msgstr ""
381+
382+#: qml/Tutorial/TutorialPage.qml:178
383+msgid "You almost got it!"
384+msgstr ""
385+
386+#: qml/Tutorial/TutorialPage.qml:195
387+msgid "Try again."
388+msgstr ""
389+
390+#: qml/Tutorial/TutorialRight.qml:31
391+msgid "To view open apps"
392+msgstr ""
393+
394+#: qml/Tutorial/TutorialRight.qml:32
395+msgid "Long swipe from the right edge."
396+msgstr ""
397+
398+#: qml/Tutorial/TutorialRight.qml:122
399+msgid "View all your running tasks."
400+msgstr ""
401+
402+#: qml/Wizard/Page.qml:89
403+msgctxt "Button: Go back one page in the Wizard"
404+msgid "Back"
405+msgstr ""
406+
407+#: qml/Wizard/Pages/10-welcome.qml:27
408+msgid "Hi!"
409+msgstr ""
410+
411+#: qml/Wizard/Pages/10-welcome.qml:44
412+msgid "Welcome to your Ubuntu phone."
413+msgstr ""
414+
415+#: qml/Wizard/Pages/10-welcome.qml:52
416+msgid "Let’s get started."
417+msgstr ""
418+
419+#: qml/Wizard/Pages/10-welcome.qml:88 qml/Wizard/Pages/30-passwd-type.qml:128
420+#: qml/Wizard/Pages/40-wifi.qml:215 qml/Wizard/Pages/50-location.qml:131
421+#: qml/Wizard/Pages/60-reporting.qml:50 qml/Wizard/Pages/passwd-confirm.qml:82
422+#: qml/Wizard/Pages/passwd-set.qml:90
423+msgid "Continue"
424+msgstr ""
425+
426+#: qml/Wizard/Pages/20-sim.qml:25
427+msgid "Add a SIM card and restart your device"
428+msgstr ""
429+
430+#: qml/Wizard/Pages/20-sim.qml:59
431+msgid "Without it, you won’t be able to make calls or use text messaging."
432+msgstr ""
433+
434+#: qml/Wizard/Pages/20-sim.qml:73 qml/Wizard/Pages/40-wifi.qml:215
435+msgid "Skip"
436+msgstr ""
437+
438+#: qml/Wizard/Pages/30-passwd-type.qml:39
439+msgid "Lock security"
440+msgstr ""
441+
442+#: qml/Wizard/Pages/30-passwd-type.qml:74
443+msgid "Please select how you’d like to unlock your phone."
444+msgstr ""
445+
446+#: qml/Wizard/Pages/30-passwd-type.qml:97
447+msgctxt "Label: Type of security method"
448+msgid "Swipe"
449+msgstr ""
450+
451+#: qml/Wizard/Pages/30-passwd-type.qml:98
452+msgctxt "Label: Description of security method"
453+msgid "No security"
454+msgstr ""
455+
456+#: qml/Wizard/Pages/30-passwd-type.qml:100
457+msgctxt "Label: Type of security method"
458+msgid "Passcode"
459+msgstr ""
460+
461+#: qml/Wizard/Pages/30-passwd-type.qml:101
462+msgctxt "Label: Description of security method"
463+msgid "4 digits only"
464+msgstr ""
465+
466+#: qml/Wizard/Pages/30-passwd-type.qml:103
467+msgctxt "Label: Type of security method"
468+msgid "Passphrase"
469+msgstr ""
470+
471+#: qml/Wizard/Pages/30-passwd-type.qml:104
472+msgctxt "Label: Description of security method"
473+msgid "Numbers and letters"
474+msgstr ""
475+
476+#: qml/Wizard/Pages/40-wifi.qml:29
477+msgid "Connect to Wi‑Fi"
478+msgstr ""
479+
480+#: qml/Wizard/Pages/40-wifi.qml:168
481+msgid "Available networks…"
482+msgstr ""
483+
484+#: qml/Wizard/Pages/40-wifi.qml:169
485+msgid "No available networks."
486+msgstr ""
487+
488+#: qml/Wizard/Pages/50-location.qml:27
489+msgid "Location"
490+msgstr ""
491+
492+#: qml/Wizard/Pages/50-location.qml:62
493+msgid "Let the phone detect your location:"
494+msgstr ""
495+
496+#: qml/Wizard/Pages/50-location.qml:69
497+msgid "Using GPS only (less accurate)"
498+msgstr ""
499+
500+#: qml/Wizard/Pages/50-location.qml:86
501+msgid "Using GPS, anonymized Wi-Fi and cellular network info (recommended)"
502+msgstr ""
503+
504+#. TRANSLATORS: HERE is a trademark for Nokia's location service, you probably shouldn't translate it
505+#: qml/Wizard/Pages/50-location.qml:103
506+msgid ""
507+"By selecting this option you agree to the Nokia HERE <a href='#'>terms and "
508+"conditions</a>."
509+msgstr ""
510+
511+#: qml/Wizard/Pages/50-location.qml:112
512+msgid "Not at all"
513+msgstr ""
514+
515+#: qml/Wizard/Pages/50-location.qml:124
516+msgid "You can change your mind later in <b>System Settings</b>."
517+msgstr ""
518+
519+#: qml/Wizard/Pages/60-reporting.qml:24
520+msgid "Improving your experience"
521+msgstr ""
522+
523+#: qml/Wizard/Pages/60-reporting.qml:36
524+msgid ""
525+"Your phone is set up to automatically report errors to Canonical and its "
526+"partners, the makers of the operating system."
527+msgstr ""
528+
529+#: qml/Wizard/Pages/60-reporting.qml:43
530+msgid ""
531+"This can be disabled in <b>System Settings</b> under <b>Security &amp; "
532+"Privacy</b>"
533+msgstr ""
534+
535+#: qml/Wizard/Pages/80-finished.qml:24
536+msgid "All done"
537+msgstr ""
538+
539+#: qml/Wizard/Pages/80-finished.qml:39
540+msgid "Nice work!"
541+msgstr ""
542+
543+#: qml/Wizard/Pages/80-finished.qml:46
544+msgid "Your phone is now ready to use."
545+msgstr ""
546+
547+#: qml/Wizard/Pages/80-finished.qml:53
548+msgid "Finish"
549+msgstr ""
550+
551+#: qml/Wizard/Pages/here-terms.qml:27
552+msgid "Terms & Conditions"
553+msgstr ""
554+
555+#: qml/Wizard/Pages/passwd-confirm.qml:49
556+msgid "Confirm passphrase"
557+msgstr ""
558+
559+#: qml/Wizard/Pages/passwd-confirm.qml:50
560+msgid "Confirm passcode"
561+msgstr ""
562+
563+#: qml/Wizard/Pages/passwd-confirm.qml:53
564+#: qml/Wizard/Pages/passwd-confirm.qml:54
565+msgid "Please try again."
566+msgstr ""
567+
568+#: qml/Wizard/Pages/passwd-set.qml:61
569+msgid "Choose your passcode"
570+msgstr ""
571+
572+#: qml/Wizard/Pages/passwd-set.qml:68
573+msgid "Passphrase must be 4 characters long"
574+msgstr ""
575+
576+#: qml/Wizard/StackButton.qml:39
577+#, qt-format
578+msgid "〈 %1"
579+msgstr ""
580+
581+#: qml/Wizard/StackButton.qml:42
582+#, qt-format
583+msgid "%1 〉"
584+msgstr ""
po/pt.po+7−7
@@ -8,15 +8,15 @@ 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: 2015-04-14 16:13+0200\n"
10"POT-Creation-Date: 2015-04-14 16:13+0200\n"
11−"PO-Revision-Date: 2015-04-18 02:15+0000\n"
11+"PO-Revision-Date: 2015-05-19 03:42+0000\n"
12"Last-Translator: António Miranda <Unknown>\n"
12"Last-Translator: António Miranda <Unknown>\n"
13"Language-Team: Portuguese <pt@li.org>\n"
13"Language-Team: Portuguese <pt@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"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-04-23 06:48+0000\n"
18+"X-Launchpad-Export-Date: 2015-05-22 05:09+0000\n"
19−"X-Generator: Launchpad (build 17430)\n"
19+"X-Generator: Launchpad (build 17514)\n"
20
20
21#: plugins/LightDM/Greeter.cpp:112
21#: plugins/LightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
@@ -262,7 +262,7 @@ msgid ""
262"If passcode is entered incorrectly, your phone will conduct a factory reset "
262"If passcode is entered incorrectly, your phone will conduct a factory reset "
263"and all personal data will be deleted."
263"and all personal data will be deleted."
264msgstr ""
264msgstr ""
265−"Se o código seja introduzido incorretamente, todos os dados pessoais do seu "
265+"Se o código não for introduzido corretamente, todos os dados pessoais do seu "
266"telemóvel serão apagados."
266"telemóvel serão apagados."
267
267
268#: qml/Greeter/NarrowView.qml:115
268#: qml/Greeter/NarrowView.qml:115
@@ -276,7 +276,7 @@ msgstr "Indique a palavra-passe"
276
276
277#: qml/Greeter/NarrowView.qml:117
277#: qml/Greeter/NarrowView.qml:117
278msgid "Enter passcode"
278msgid "Enter passcode"
279−msgstr "Introduza código"
279+msgstr "Introduza o código"
280
280
281#: qml/Greeter/NarrowView.qml:118
281#: qml/Greeter/NarrowView.qml:118
282#, qt-format
282#, qt-format
@@ -293,7 +293,7 @@ msgstr "Por favor, volte a introduzir"
293
293
294#: qml/Greeter/NarrowView.qml:121
294#: qml/Greeter/NarrowView.qml:121
295msgid "Sorry, incorrect passcode"
295msgid "Sorry, incorrect passcode"
296−msgstr "Código incorreta"
296+msgstr "Código incorreto"
297
297
298#: qml/Notifications/NotificationMenuItemFactory.qml:128
298#: qml/Notifications/NotificationMenuItemFactory.qml:128
299msgid "Show password"
299msgid "Show password"
@@ -371,7 +371,7 @@ msgstr "Toque aqui para continuar."
371
371
372#: qml/Tutorial/TutorialContent.qml:81
372#: qml/Tutorial/TutorialContent.qml:81
373msgid "Click here to finish."
373msgid "Click here to finish."
374−msgstr ""
374+msgstr "Clique aqui para finalizar."
375
375
376#: qml/Tutorial/TutorialLeftFinish.qml:24
376#: qml/Tutorial/TutorialLeftFinish.qml:24
377msgid "These are the shortcuts to favorite apps"
377msgid "These are the shortcuts to favorite apps"
po/sl.po+8−8
@@ -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: 2015-04-14 16:13+0200\n"
10"POT-Creation-Date: 2015-04-14 16:13+0200\n"
11−"PO-Revision-Date: 2015-03-23 07:24+0000\n"
11+"PO-Revision-Date: 2015-06-05 06:39+0000\n"
12−"Last-Translator: Damir Jerovšek <Unknown>\n"
12+"Last-Translator: Martin Srebotnjak <miles@filmsi.net>\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"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || "
17"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || "
18"n%100==4 ? 3 : 0);\n"
18"n%100==4 ? 3 : 0);\n"
19−"X-Launchpad-Export-Date: 2015-04-23 06:48+0000\n"
19+"X-Launchpad-Export-Date: 2015-06-06 05:31+0000\n"
20−"X-Generator: Launchpad (build 17430)\n"
20+"X-Generator: Launchpad (build 17540)\n"
21
21
22#: plugins/LightDM/Greeter.cpp:112
22#: plugins/LightDM/Greeter.cpp:112
23msgid "Password: "
23msgid "Password: "
@@ -164,17 +164,17 @@ msgstr "Iskanje"
164#: qml/Dash/PageHeader.qml:269
164#: qml/Dash/PageHeader.qml:269
165msgctxt "Button: Open the Ubuntu Store"
165msgctxt "Button: Open the Ubuntu Store"
166msgid "Store"
166msgid "Store"
167−msgstr ""
167+msgstr "Trgovina"
168
168
169#: qml/Dash/PageHeader.qml:276
169#: qml/Dash/PageHeader.qml:276
170msgctxt "Button: Start a search in the current dash scope"
170msgctxt "Button: Start a search in the current dash scope"
171msgid "Search"
171msgid "Search"
172−msgstr ""
172+msgstr "Iskanje"
173
173
174#: qml/Dash/PageHeader.qml:286
174#: qml/Dash/PageHeader.qml:286
175msgctxt "Button: Show the current dash scope settings"
175msgctxt "Button: Show the current dash scope settings"
176msgid "Settings"
176msgid "Settings"
177−msgstr ""
177+msgstr "Nastavitve"
178
178
179#: qml/Dash/PageHeader.qml:293
179#: qml/Dash/PageHeader.qml:293
180msgid "Remove from Favorites"
180msgid "Remove from Favorites"
@@ -374,7 +374,7 @@ msgstr "Tapnite tukaj za nadaljevanje."
374
374
375#: qml/Tutorial/TutorialContent.qml:81
375#: qml/Tutorial/TutorialContent.qml:81
376msgid "Click here to finish."
376msgid "Click here to finish."
377−msgstr ""
377+msgstr "Kliknite tu za zaključek."
378
378
379#: qml/Tutorial/TutorialLeftFinish.qml:24
379#: qml/Tutorial/TutorialLeftFinish.qml:24
380msgid "These are the shortcuts to favorite apps"
380msgid "These are the shortcuts to favorite apps"
qml/CMakeLists.txt+1
@@ -13,6 +13,7 @@ set(QML_DIRS
13 Notifications
13 Notifications
14 Panel
14 Panel
15 Stages
15 Stages
16+ Rotation
16 Tutorial
17 Tutorial
17 Wizard
18 Wizard
18 )
19 )
qml/Components/WindowScreenshot.qmlnew file+35
@@ -0,0 +1,35 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.2
18+
19+Item {
20+ id: root
21+
22+ function take() {
23+ var timeNow = new Date().getTime();
24+ image.source = "image://window/" + timeNow;
25+ }
26+
27+ // Unload the image to free up memory
28+ function discard() {
29+ image.source = "";
30+ }
31+
32+ Image {
33+ id: image
34+ }
35+}
qml/Dash/DashApplication.qml+3−3
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2014 Canonical, Ltd.
2+ * Copyright (C) 2014,2015 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
@@ -19,8 +19,8 @@ import Ubuntu.Components 1.0
19import Ubuntu.Thumbnailer 0.1 // Register support for image://thumbnailer/ and image://albumart/
19import Ubuntu.Thumbnailer 0.1 // Register support for image://thumbnailer/ and image://albumart/
20
20
21MainView {
21MainView {
22− width: applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
22+ implicitWidth: units.gu(40)
23− height: applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(68)
23+ implicitHeight: units.gu(68)
24
24
25 useDeprecatedToolbar: false
25 useDeprecatedToolbar: false
26
26
qml/Dash/GenericScopeView.qml+6−6
@@ -67,8 +67,8 @@ FocusScope {
67 subPageLoader.closeSubPage()
67 subPageLoader.closeSubPage()
68 }
68 }
69
69
70− function itemClicked(index, result, item, itemModel, resultsModel, limitedCategoryItemCount) {
70+ function itemClicked(index, result, item, itemModel, resultsModel, limitedCategoryItemCount, categoryId) {
71− if (itemModel.uri.indexOf("scope://") === 0 || scope.id === "clickscope") {
71+ if (itemModel.uri.indexOf("scope://") === 0 || scope.id === "clickscope" || (scope.id === "videoaggregator" && categoryId === "myvideos-getstarted")) {
72 // TODO Technically it is possible that calling activate() will make the scope emit
72 // TODO Technically it is possible that calling activate() will make the scope emit
73 // previewRequested so that we show a preview but there's no scope that does that yet
73 // previewRequested so that we show a preview but there's no scope that does that yet
74 // so it's not implemented
74 // so it's not implemented
@@ -80,8 +80,8 @@ FocusScope {
80 }
80 }
81 }
81 }
82
82
83− function itemPressedAndHeld(index, result, itemModel, resultsModel, limitedCategoryItemCount) {
83+ function itemPressedAndHeld(index, result, itemModel, resultsModel, limitedCategoryItemCount, categoryId) {
84− if (itemModel.uri.indexOf("scope://") !== 0) {
84+ if (itemModel.uri.indexOf("scope://") !== 0 && !(scope.id === "videoaggregator" && categoryId === "myvideos-getstarted")) {
85 if (scope.preview(result)) {
85 if (scope.preview(result)) {
86 openPreview(index, resultsModel, limitedCategoryItemCount);
86 openPreview(index, resultsModel, limitedCategoryItemCount);
87 }
87 }
@@ -346,11 +346,11 @@ FocusScope {
346 Connections {
346 Connections {
347 target: rendererLoader.item
347 target: rendererLoader.item
348 onClicked: {
348 onClicked: {
349− scopeView.itemClicked(index, result, item, itemModel, target.model, categoryItemCount());
349+ scopeView.itemClicked(index, result, item, itemModel, target.model, categoryItemCount(), baseItem.category);
350 }
350 }
351
351
352 onPressAndHold: {
352 onPressAndHold: {
353− scopeView.itemPressedAndHeld(index, result, itemModel, target.model, categoryItemCount());
353+ scopeView.itemPressedAndHeld(index, result, itemModel, target.model, categoryItemCount(), baseItem.category);
354 }
354 }
355
355
356 function categoryItemCount() {
356 function categoryItemCount() {
qml/Dash/Previews/PreviewRatingDisplay.qml+9−44
@@ -49,53 +49,18 @@ PreviewWidget {
49 objectName: "reviewsRepeater"
49 objectName: "reviewsRepeater"
50 model: root.widgetData["reviews"]
50 model: root.widgetData["reviews"]
51
51
52− delegate: Column {
52+ delegate: PreviewRatingSingleDisplay {
53− id: reviewItem
54 objectName: "reviewItem" + index
53 objectName: "reviewItem" + index
55− anchors { left: parent.left; right: parent.right;}
56− spacing: units.gu(1)
57
54
58− Rating {
55+ anchors { left: parent.left; right: parent.right; }
59− id: rating
60− objectName: "rating"
61− size: 5
62− value: modelData["rating"] || -1
63− visible: value >= 0
64− interactive: false
65
56
57+ rating: modelData["rating"] || -1
58+ author: modelData["author"] || ""
59+ review: modelData["review"] || ""
66− property var urlIconEmpty: widgetData["rating-icon-empty"]
60+ urlIconEmpty: widgetData["rating-icon-empty"]
67− property var urlIconFull: widgetData["rating-icon-full"]
61+ urlIconFull: widgetData["rating-icon-full"]
68− property var urlIconHalf: widgetData["rating-icon-half"]
62+ urlIconHalf: widgetData["rating-icon-half"]
69− }
70−
71− Label {
72− id: authorLabel
73− objectName: "authorLabel"
74− anchors { left: parent.left; right: parent.right }
75− color: scopeStyle ? scopeStyle.foreground : Theme.palette.normal.baseText
76− opacity: .8
77− text: modelData["author"] || ""
78− visible: text !== ""
79− wrapMode: Text.Wrap
80− }
81−
82− Label {
83− id: reviewLabel
84− objectName: "reviewLabel"
85− anchors { left: parent.left; right: parent.right }
86− color: scopeStyle ? scopeStyle.foreground : Theme.palette.normal.baseText
63+ labelColor: scopeStyle ? scopeStyle.foreground : Theme.palette.normal.baseText
87− opacity: .8
88− text: modelData["review"] || ""
89− visible: text !== ""
90− wrapMode: Text.Wrap
91− }
92−
93− Item {
94− id: spacing
95− anchors { left: parent.left; right: parent.right }
96− height: units.gu(2)
97− visible: rating.visible || authorLabel.visible || reviewLabel.visible
98− }
99 }
64 }
100 }
65 }
101 }
66 }
qml/Dash/Previews/PreviewRatingEdit.qmlnew file+80
@@ -0,0 +1,80 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+import Ubuntu.Components 0.1
19+import "../../Components"
20+
21+/*! \brief Preview widget for editable rating.
22+
23+ Shows a single display rating that can be switched by the user to edit mode
24+ and then behaves as a rating display widget
25+
26+ The display part uses widgetData["author"], widgetData["review"] and widgetData["rating"].
27+
28+ The edit part uses the same fields as the "rating-input" widget
29+*/
30+
31+PreviewWidget {
32+ id: root
33+ implicitHeight: display.visible ? display.implicitHeight : input.implicitHeight
34+
35+ Button {
36+ id: editIcon
37+ objectName: "editButton"
38+
39+ iconName: "edit"
40+ width: height
41+ anchors.right: parent.right
42+ visible: display.visible
43+ onClicked: display.visible = false
44+ }
45+
46+ PreviewRatingSingleDisplay {
47+ id: display
48+ objectName: "display"
49+
50+ anchors.left: parent.left
51+ anchors.right: editIcon.left
52+
53+ rating: widgetData["rating"] || -1
54+ author: widgetData["author"] || ""
55+ review: widgetData["review"] || ""
56+ urlIconEmpty: widgetData["rating-icon-empty"]
57+ urlIconFull: widgetData["rating-icon-full"]
58+ urlIconHalf: widgetData["rating-icon-half"]
59+ labelColor: scopeStyle ? scopeStyle.foreground : Theme.palette.normal.baseText
60+ }
61+
62+ PreviewRatingInput {
63+ id: input
64+ objectName: "input"
65+
66+ visible: !display.visible
67+ width: parent.width
68+
69+ widgetId: root.widgetId
70+ widgetData: root.widgetData
71+ isCurrentPreview: root.isCurrentPreview
72+ scopeStyle: root.scopeStyle
73+
74+ ratingValue: widgetData["rating"]
75+ reviewText: widgetData["review"]
76+
77+ onTriggered: root.triggered(widgetId, actionId, data);
78+ }
79+
80+}
qml/Dash/Previews/PreviewRatingInput.qml+3
@@ -48,6 +48,9 @@ PreviewWidget {
48 }
48 }
49 }
49 }
50
50
51+ property alias ratingValue: rating.value
52+ property alias reviewText: reviewTextArea.text
53+
51 function submit() {
54 function submit() {
52 // checks rating-input requirements
55 // checks rating-input requirements
53 if (((widgetData["required"] === "both" ||
56 if (((widgetData["required"] === "both" ||
qml/Dash/Previews/PreviewRatingSingleDisplay.qmlnew file+70
@@ -0,0 +1,70 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+import Ubuntu.Components 0.1
19+import "../../Components"
20+
21+Column {
22+ id: reviewItem
23+ spacing: units.gu(1)
24+
25+ property alias rating: ratingItem.value
26+ property alias author: authorLabel.text
27+ property alias review: reviewLabel.text
28+ property alias urlIconEmpty: ratingItem.urlIconEmpty
29+ property alias urlIconFull: ratingItem.urlIconFull
30+ property alias urlIconHalf: ratingItem.urlIconHalf
31+ property alias labelColor: authorLabel.color
32+
33+ Rating {
34+ id: ratingItem
35+ objectName: "rating"
36+ size: 5
37+ visible: value >= 0
38+ interactive: false
39+
40+ property var urlIconEmpty
41+ property var urlIconFull
42+ property var urlIconHalf
43+ }
44+
45+ Label {
46+ id: authorLabel
47+ objectName: "authorLabel"
48+ anchors { left: parent.left; right: parent.right }
49+ opacity: .8
50+ visible: text !== ""
51+ wrapMode: Text.Wrap
52+ }
53+
54+ Label {
55+ id: reviewLabel
56+ objectName: "reviewLabel"
57+ anchors { left: parent.left; right: parent.right }
58+ color: authorLabel.color
59+ opacity: .8
60+ visible: text !== ""
61+ wrapMode: Text.Wrap
62+ }
63+
64+ Item {
65+ id: spacing
66+ anchors { left: parent.left; right: parent.right }
67+ height: units.gu(2)
68+ visible: rating.visible || authorLabel.visible || reviewLabel.visible
69+ }
70+}
qml/Dash/Previews/PreviewWidgetFactory.qml+1
@@ -57,6 +57,7 @@ Loader {
57 case "progress": return "PreviewProgress.qml";
57 case "progress": return "PreviewProgress.qml";
58 case "payments": return "PreviewPayments.qml";
58 case "payments": return "PreviewPayments.qml";
59 case "rating-input": return "PreviewRatingInput.qml";
59 case "rating-input": return "PreviewRatingInput.qml";
60+ case "rating-edit": return "PreviewRatingEdit.qml";
60 case "reviews": return "PreviewRatingDisplay.qml";
61 case "reviews": return "PreviewRatingDisplay.qml";
61 case "table": return "PreviewTable.qml";
62 case "table": return "PreviewTable.qml";
62 case "text": return "PreviewTextSummary.qml";
63 case "text": return "PreviewTextSummary.qml";
qml/Dash/graphics/phone/screenshots/gmail-webapp.svgnew file+343
@@ -0,0 +1,343 @@
1+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2+<!-- Created with Inkscape (http://www.inkscape.org/) -->
3+
4+<svg
5+ xmlns:dc="http://purl.org/dc/elements/1.1/"
6+ xmlns:cc="http://creativecommons.org/ns#"
7+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8+ xmlns:svg="http://www.w3.org/2000/svg"
9+ xmlns="http://www.w3.org/2000/svg"
10+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
11+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
12+ width="768"
13+ height="1280"
14+ id="svg2"
15+ version="1.1"
16+ inkscape:version="0.48.5 r10040"
17+ sodipodi:docname="gmail-webapp.svg">
18+ <defs
19+ id="defs4" />
20+ <sodipodi:namedview
21+ id="base"
22+ pagecolor="#ffffff"
23+ bordercolor="#666666"
24+ borderopacity="1.0"
25+ inkscape:pageopacity="0.0"
26+ inkscape:pageshadow="2"
27+ inkscape:zoom="0.49497475"
28+ inkscape:cx="117.33439"
29+ inkscape:cy="668.80479"
30+ inkscape:document-units="px"
31+ inkscape:current-layer="layer1"
32+ showgrid="false"
33+ inkscape:window-width="1920"
34+ inkscape:window-height="1056"
35+ inkscape:window-x="0"
36+ inkscape:window-y="24"
37+ inkscape:window-maximized="1" />
38+ <metadata
39+ id="metadata7">
40+ <rdf:RDF>
41+ <cc:Work
42+ rdf:about="">
43+ <dc:format>image/svg+xml</dc:format>
44+ <dc:type
45+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
46+ <dc:title></dc:title>
47+ </cc:Work>
48+ </rdf:RDF>
49+ </metadata>
50+ <g
51+ inkscape:label="Layer 1"
52+ inkscape:groupmode="layer"
53+ id="layer1"
54+ transform="translate(0,227.63782)">
55+ <rect
56+ style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.69999999000000002;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
57+ id="rect2985"
58+ width="769.73627"
59+ height="1276.8328"
60+ x="-2.0203052"
61+ y="3.1671834"
62+ transform="translate(0,-227.63782)" />
63+ <rect
64+ style="fill:#e6e6e6;fill-opacity:1;stroke:none;stroke-width:4;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
65+ id="rect3797"
66+ width="773.77686"
67+ height="129.29953"
68+ x="-6.0609155"
69+ y="-0.87342685"
70+ transform="translate(0,-227.63782)" />
71+ <text
72+ xml:space="preserve"
73+ style="font-size:72px;font-style:normal;font-weight:500;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu Medium;font-stretch:normal;font-variant:normal"
74+ x="20.203053"
75+ y="-139.61781"
76+ id="text3755"
77+ sodipodi:linespacing="125%"><tspan
78+ sodipodi:role="line"
79+ id="tspan3757"
80+ x="20.203053"
81+ y="-139.61781">GMail</tspan></text>
82+ <text
83+ xml:space="preserve"
84+ style="font-size:72px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
85+ x="14.142137"
86+ y="-28.501045"
87+ id="text3759"
88+ sodipodi:linespacing="125%"><tspan
89+ sodipodi:role="line"
90+ id="tspan3761"
91+ x="14.142137"
92+ y="-28.501045">Inbox</tspan></text>
93+ <path
94+ sodipodi:type="arc"
95+ style="fill:#8effff;fill-opacity:1;stroke:#000000;stroke-width:0.69999999;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
96+ id="path3765"
97+ sodipodi:cx="107.07617"
98+ sodipodi:cy="337.52768"
99+ sodipodi:rx="64.649765"
100+ sodipodi:ry="61.619305"
101+ d="m 171.72594,337.52768 a 64.649765,61.619305 0 1 1 -129.299533,0 64.649765,61.619305 0 1 1 129.299533,0 z"
102+ transform="translate(-28.284271,-251.88148)" />
103+ <path
104+ style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
105+ d="m 14.142136,237.52257 729.330134,0"
106+ id="path3769"
107+ inkscape:connector-curvature="0"
108+ transform="translate(0,-227.63782)" />
109+ <text
110+ xml:space="preserve"
111+ style="font-size:64px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
112+ x="167.68533"
113+ y="78.575127"
114+ id="text3771"
115+ sodipodi:linespacing="125%"><tspan
116+ sodipodi:role="line"
117+ id="tspan3773"
118+ x="167.68533"
119+ y="78.575127">Lorem ipsum</tspan></text>
120+ <text
121+ xml:space="preserve"
122+ style="font-size:64px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
123+ x="167.68532"
124+ y="131.10306"
125+ id="text3775"
126+ sodipodi:linespacing="125%"><tspan
127+ sodipodi:role="line"
128+ id="tspan3777"
129+ x="167.68532"
130+ y="131.10306"
131+ style="font-size:48px;fill:#b3b3b3">bla bla bla bla bla bla bla ...</tspan></text>
132+ <path
133+ style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
134+ d="m 13.13199,165.44825 729.33013,0"
135+ id="path3769-2"
136+ inkscape:connector-curvature="0" />
137+ <path
138+ sodipodi:type="arc"
139+ style="fill:#8eff58;fill-opacity:1;stroke:#000000;stroke-width:0.69999999000000002;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
140+ id="path3765-3"
141+ sodipodi:cx="107.07617"
142+ sodipodi:cy="337.52768"
143+ sodipodi:rx="64.649765"
144+ sodipodi:ry="61.619305"
145+ d="m 171.72594,337.52768 a 64.649765,61.619305 0 1 1 -129.299533,0 64.649765,61.619305 0 1 1 129.299533,0 z"
146+ transform="translate(-26.263969,-93.102383)" />
147+ <text
148+ xml:space="preserve"
149+ style="font-size:64px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
150+ x="169.70564"
151+ y="237.35422"
152+ id="text3771-9"
153+ sodipodi:linespacing="125%"><tspan
154+ sodipodi:role="line"
155+ id="tspan3773-7"
156+ x="169.70564"
157+ y="237.35422">Lorem ipsum</tspan></text>
158+ <text
159+ xml:space="preserve"
160+ style="font-size:64px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
161+ x="169.70561"
162+ y="289.88217"
163+ id="text3775-1"
164+ sodipodi:linespacing="125%"><tspan
165+ sodipodi:role="line"
166+ id="tspan3777-1"
167+ x="169.70561"
168+ y="289.88217"
169+ style="font-size:48px;fill:#b3b3b3">bla bla bla bla bla bla bla ...</tspan></text>
170+ <path
171+ style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
172+ d="m 15.152292,324.22735 729.330128,0"
173+ id="path3769-2-6"
174+ inkscape:connector-curvature="0" />
175+ <path
176+ sodipodi:type="arc"
177+ style="fill:#8effff;fill-opacity:1;stroke:#000000;stroke-width:0.69999999;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
178+ id="path3765-7"
179+ sodipodi:cx="107.07617"
180+ sodipodi:cy="337.52768"
181+ sodipodi:rx="64.649765"
182+ sodipodi:ry="61.619305"
183+ d="m 171.72594,337.52768 a 64.649765,61.619305 0 1 1 -129.299533,0 64.649765,61.619305 0 1 1 129.299533,0 z"
184+ transform="translate(-28.284274,64.481414)" />
185+ <text
186+ xml:space="preserve"
187+ style="font-size:64px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
188+ x="167.68533"
189+ y="394.93799"
190+ id="text3771-92"
191+ sodipodi:linespacing="125%"><tspan
192+ sodipodi:role="line"
193+ id="tspan3773-0"
194+ x="167.68533"
195+ y="394.93799">Lorem ipsum</tspan></text>
196+ <text
197+ xml:space="preserve"
198+ style="font-size:64px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
199+ x="167.68532"
200+ y="447.46594"
201+ id="text3775-9"
202+ sodipodi:linespacing="125%"><tspan
203+ sodipodi:role="line"
204+ id="tspan3777-8"
205+ x="167.68532"
206+ y="447.46594"
207+ style="font-size:48px;fill:#b3b3b3">bla bla bla bla bla bla bla ...</tspan></text>
208+ <path
209+ style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
210+ d="m 13.131986,481.81114 729.330124,0"
211+ id="path3769-2-3"
212+ inkscape:connector-curvature="0" />
213+ <path
214+ sodipodi:type="arc"
215+ style="fill:#8ea2ff;fill-opacity:1;stroke:#000000;stroke-width:0.69999999000000002;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
216+ id="path3765-2"
217+ sodipodi:cx="107.07617"
218+ sodipodi:cy="337.52768"
219+ sodipodi:rx="64.649765"
220+ sodipodi:ry="61.619305"
221+ d="m 171.72594,337.52768 a 64.649765,61.619305 0 1 1 -129.299533,0 64.649765,61.619305 0 1 1 129.299533,0 z"
222+ transform="translate(-26.263969,226.10582)" />
223+ <text
224+ xml:space="preserve"
225+ style="font-size:64px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
226+ x="169.70564"
227+ y="556.56238"
228+ id="text3771-1"
229+ sodipodi:linespacing="125%"><tspan
230+ sodipodi:role="line"
231+ id="tspan3773-1"
232+ x="169.70564"
233+ y="556.56238">Lorem ipsum</tspan></text>
234+ <text
235+ xml:space="preserve"
236+ style="font-size:64px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
237+ x="169.70563"
238+ y="609.09033"
239+ id="text3775-8"
240+ sodipodi:linespacing="125%"><tspan
241+ sodipodi:role="line"
242+ id="tspan3777-85"
243+ x="169.70563"
244+ y="609.09033"
245+ style="font-size:48px;fill:#b3b3b3">bla bla bla bla bla bla bla ...</tspan></text>
246+ <path
247+ style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
248+ d="m 15.152292,643.43555 729.330128,0"
249+ id="path3769-2-1"
250+ inkscape:connector-curvature="0" />
251+ <path
252+ sodipodi:type="arc"
253+ style="fill:#8effff;fill-opacity:1;stroke:#000000;stroke-width:0.69999999;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
254+ id="path3765-8"
255+ sodipodi:cx="107.07617"
256+ sodipodi:cy="337.52768"
257+ sodipodi:rx="64.649765"
258+ sodipodi:ry="61.619305"
259+ d="m 171.72594,337.52768 a 64.649765,61.619305 0 1 1 -129.299533,0 64.649765,61.619305 0 1 1 129.299533,0 z"
260+ transform="translate(-24.243664,391.77084)" />
261+ <text
262+ xml:space="preserve"
263+ style="font-size:64px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
264+ x="171.72594"
265+ y="722.22742"
266+ id="text3771-7"
267+ sodipodi:linespacing="125%"><tspan
268+ sodipodi:role="line"
269+ id="tspan3773-6"
270+ x="171.72594"
271+ y="722.22742">Lorem ipsum</tspan></text>
272+ <text
273+ xml:space="preserve"
274+ style="font-size:64px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
275+ x="171.72592"
276+ y="774.75537"
277+ id="text3775-5"
278+ sodipodi:linespacing="125%"><tspan
279+ sodipodi:role="line"
280+ id="tspan3777-2"
281+ x="171.72592"
282+ y="774.75537"
283+ style="font-size:48px;fill:#b3b3b3">bla bla bla bla bla bla bla ...</tspan></text>
284+ <path
285+ style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
286+ d="m 17.172597,809.10057 729.330133,0"
287+ id="path3769-2-13"
288+ inkscape:connector-curvature="0" />
289+ <path
290+ sodipodi:type="arc"
291+ style="fill:#e44738;fill-opacity:1;stroke:#000000;stroke-width:0.69999999000000002;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
292+ id="path3765-9"
293+ sodipodi:cx="107.07617"
294+ sodipodi:cy="337.52768"
295+ sodipodi:rx="64.649765"
296+ sodipodi:ry="61.619305"
297+ d="m 171.72594,337.52768 a 64.649765,61.619305 0 1 1 -129.299533,0 64.649765,61.619305 0 1 1 129.299533,0 z"
298+ transform="translate(-24.243664,557.43585)" />
299+ <text
300+ xml:space="preserve"
301+ style="font-size:64px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
302+ x="171.72594"
303+ y="887.89246"
304+ id="text3771-2"
305+ sodipodi:linespacing="125%"><tspan
306+ sodipodi:role="line"
307+ id="tspan3773-8"
308+ x="171.72594"
309+ y="887.89246">Lorem ipsum</tspan></text>
310+ <text
311+ xml:space="preserve"
312+ style="font-size:64px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
313+ x="171.72592"
314+ y="940.42041"
315+ id="text3775-3"
316+ sodipodi:linespacing="125%"><tspan
317+ sodipodi:role="line"
318+ id="tspan3777-7"
319+ x="171.72592"
320+ y="940.42041"
321+ style="font-size:48px;fill:#b3b3b3">bla bla bla bla bla bla bla ...</tspan></text>
322+ <path
323+ style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
324+ d="m 17.172597,974.76558 729.330123,0"
325+ id="path3769-2-9"
326+ inkscape:connector-curvature="0" />
327+ <path
328+ sodipodi:type="arc"
329+ style="fill:none;stroke:#000000;stroke-width:8;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
330+ id="path3929"
331+ sodipodi:cx="590.93921"
332+ sodipodi:cy="-119.06127"
333+ sodipodi:rx="33.335033"
334+ sodipodi:ry="33.335033"
335+ d="m 624.27424,-119.06127 a 33.335033,33.335033 0 1 1 -66.67006,0 33.335033,33.335033 0 1 1 66.67006,0 z"
336+ transform="matrix(0.85096826,0,0,0.85096826,175.43863,-68.81729)" />
337+ <path
338+ style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:3.40387297;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
339+ d="m 692.92249,-145.20602 20.63059,24.06901 12.03451,-13.75372 -20.63059,-17.19215"
340+ id="path3931"
341+ inkscape:connector-curvature="0" />
342+ </g>
343+</svg>
qml/Dash/graphics/phone/screenshots/settings@12.pngdeleted

Binary file not shown.

qml/Dash/graphics/phone/screenshots/ubuntu-weather-app.svgnew file+201
@@ -0,0 +1,201 @@
1+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2+<!-- Created with Inkscape (http://www.inkscape.org/) -->
3+
4+<svg
5+ xmlns:dc="http://purl.org/dc/elements/1.1/"
6+ xmlns:cc="http://creativecommons.org/ns#"
7+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8+ xmlns:svg="http://www.w3.org/2000/svg"
9+ xmlns="http://www.w3.org/2000/svg"
10+ xmlns:xlink="http://www.w3.org/1999/xlink"
11+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
12+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
13+ width="829"
14+ height="480"
15+ id="svg2740"
16+ sodipodi:version="0.32"
17+ inkscape:version="0.48.5 r10040"
18+ version="1.0"
19+ sodipodi:docname="ubuntu-weather-app.svg"
20+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
21+ <defs
22+ id="defs2742">
23+ <linearGradient
24+ id="linearGradient3824">
25+ <stop
26+ style="stop-color:#e6e6e6;stop-opacity:1;"
27+ offset="0"
28+ id="stop3826" />
29+ <stop
30+ style="stop-color:#23abff;stop-opacity:1;"
31+ offset="1"
32+ id="stop3828" />
33+ </linearGradient>
34+ <linearGradient
35+ inkscape:collect="always"
36+ xlink:href="#linearGradient3824"
37+ id="linearGradient3830"
38+ x1="348.55862"
39+ y1="343.23914"
40+ x2="348.55862"
41+ y2="-17.422215"
42+ gradientUnits="userSpaceOnUse" />
43+ </defs>
44+ <sodipodi:namedview
45+ id="base"
46+ pagecolor="#ffffff"
47+ bordercolor="#666666"
48+ borderopacity="1.0"
49+ gridtolerance="10000"
50+ guidetolerance="10"
51+ objecttolerance="10"
52+ inkscape:pageopacity="0.0"
53+ inkscape:pageshadow="2"
54+ inkscape:zoom="0.82625984"
55+ inkscape:cx="331.28234"
56+ inkscape:cy="125.54212"
57+ inkscape:document-units="px"
58+ inkscape:current-layer="layer1"
59+ showgrid="false"
60+ inkscape:window-width="1145"
61+ inkscape:window-height="847"
62+ inkscape:window-x="268"
63+ inkscape:window-y="63"
64+ inkscape:window-maximized="0" />
65+ <metadata
66+ id="metadata2745">
67+ <rdf:RDF>
68+ <cc:Work
69+ rdf:about="">
70+ <dc:format>image/svg+xml</dc:format>
71+ <dc:type
72+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
73+ </cc:Work>
74+ </rdf:RDF>
75+ </metadata>
76+ <g
77+ inkscape:label="Layer 1"
78+ inkscape:groupmode="layer"
79+ id="layer1"
80+ transform="translate(-321.13452,-104.68346)">
81+ <rect
82+ style="fill:url(#linearGradient3830);fill-opacity:1;stroke:#000000;stroke-width:0.69999999000000002;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
83+ id="rect2990"
84+ width="832.66785"
85+ height="480.47839"
86+ x="-1.210273"
87+ y="0.73188055"
88+ transform="translate(321.13452,104.68346)" />
89+ <path
90+ d="m 310.66382,132.06057 c -1.82703,2.0443 -22.21039,-18.38308 -24.89334,-17.37811 -2.68295,1.00497 -6.73783,33.64192 -9.57527,34.01165 -2.83744,0.36973 -7.71546,-33.08881 -10.48084,-33.88783 -2.76539,-0.79903 -18.7793,19.34152 -21.17964,17.82892 -2.40034,-1.51259 5.69972,-26.09808 4.36486,-28.67057 -1.33487,-2.57249 -31.86305,-3.78032 -32.49182,-6.6501 -0.62876,-2.86978 27.66855,-10.399376 27.90248,-13.241764 0.23394,-2.842387 -18.99828,-18.90215 -17.89698,-21.393798 1.10131,-2.491647 26.85456,8.177399 28.59429,5.99159 1.73972,-2.185809 -3.39182,-29.683489 -0.75169,-30.507098 2.64013,-0.823608 18.50306,18.485327 21.32153,18.392972 2.81847,-0.09235 11.30312,-24.287685 14.18258,-23.722317 2.87947,0.565368 1.44329,25.667631 3.67226,27.34365 2.22897,1.676019 24.27161,-6.28288 25.90675,-4.004945 1.63514,2.277936 -12.63923,24.445025 -11.77955,27.07291 0.85968,2.627885 27.01183,5.1355 26.65457,7.852474 -0.35726,2.716973 -32.69913,3.875594 -34.04684,6.507203 -1.3477,2.631613 12.32368,32.410863 10.49665,34.455163 z"
91+ id="path11949"
92+ inkscape:flatsided="false"
93+ inkscape:randomized="-0.092"
94+ inkscape:rounded="0.1"
95+ sodipodi:arg1="0.79570711"
96+ sodipodi:arg2="1.144773"
97+ sodipodi:cx="275.15002"
98+ sodipodi:cy="88.090233"
99+ sodipodi:r1="57.019234"
100+ sodipodi:r2="32.818508"
101+ sodipodi:sides="9"
102+ sodipodi:type="star"
103+ style="fill:#f5ff12;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.2;marker:none;visibility:visible;display:inline;overflow:visible"
104+ transform="matrix(2.527571,0,0,2.527571,85.214779,60.619097)" />
105+ <path
106+ d="m 194.51692,77.283737 c 0,20.659371 -17.86424,37.407103 -39.90091,37.407103 -22.03666,0 -39.90091,-16.747732 -39.90091,-37.407103 0,-20.659371 17.86425,-37.4071 39.90091,-37.4071 22.03667,0 39.90091,16.747729 39.90091,37.4071 z"
107+ id="path11951"
108+ sodipodi:cx="154.61601"
109+ sodipodi:cy="77.283737"
110+ sodipodi:rx="39.900909"
111+ sodipodi:ry="37.407101"
112+ sodipodi:type="arc"
113+ style="fill:#f5ff12;fill-opacity:1;fill-rule:nonzero;stroke:#f5ff12;stroke-width:10.27388287;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0.5;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
114+ transform="matrix(2.4568175,0,0,2.1990879,404.91256,120.05076)" />
115+ <path
116+ transform="matrix(3.2663208,0,0,3.4016021,515.92101,-254.59331)"
117+ style="fill:#6798e9;fill-opacity:1;fill-rule:nonzero;stroke:#6798e9;stroke-width:7.30059433;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0.5;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
118+ sodipodi:type="inkscape:offset"
119+ inkscape:radius="0"
120+ inkscape:original="M 110.53125 144.96875 C 100.76599 144.96875 92.384060 150.03292 88.281250 157.34375 C 86.642607 156.42892 84.835190 155.87500 82.906250 155.87500 C 77.073071 155.87500 72.219030 160.56753 70.718750 166.93750 C 68.157973 165.92533 65.180470 165.31250 62.000000 165.31250 C 52.458571 165.31250 44.718750 170.53296 44.718750 176.96875 C 44.718749 182.77816 51.066430 187.55402 59.312500 188.43750 C 58.942922 189.06456 58.656250 189.68551 58.656250 190.34375 C 58.656248 196.50568 75.538140 201.53125 96.343750 201.53125 C 117.14936 201.53125 134.03126 196.50568 134.03125 190.34375 C 134.03125 189.92916 133.77393 189.55916 133.62500 189.15625 C 134.53629 189.38287 135.43860 189.62500 136.43750 189.62500 C 142.00333 189.62501 146.53125 185.84318 146.53125 181.18750 C 146.53125 176.53182 142.00332 172.75000 136.43750 172.75000 C 135.75542 172.75000 135.17544 172.98560 134.53125 173.09375 C 135.09454 171.23218 135.46875 169.33268 135.46875 167.31250 C 135.46875 154.98864 124.31330 144.96875 110.53125 144.96875 z "
121+ id="path11953"
122+ d="m 110.53125,144.96875 c -9.76526,0 -18.14719,5.06417 -22.25,12.375 -1.638643,-0.91483 -3.44606,-1.46875 -5.375,-1.46875 -5.833179,0 -10.68722,4.69253 -12.1875,11.0625 -2.560777,-1.01217 -5.53828,-1.625 -8.71875,-1.625 -9.541429,0 -17.28125,5.22046 -17.28125,11.65625 -10e-7,5.80941 6.34768,10.58527 14.59375,11.46875 -0.369578,0.62706 -0.65625,1.24801 -0.65625,1.90625 -2e-6,6.16193 16.88189,11.1875 37.6875,11.1875 20.80561,0 37.68751,-5.02557 37.6875,-11.1875 0,-0.41459 -0.25732,-0.78459 -0.40625,-1.1875 0.91129,0.22662 1.8136,0.46875 2.8125,0.46875 5.56583,1e-5 10.09375,-3.78182 10.09375,-8.4375 0,-4.65568 -4.52793,-8.4375 -10.09375,-8.4375 -0.68208,0 -1.26206,0.2356 -1.90625,0.34375 0.56329,-1.86157 0.9375,-3.76107 0.9375,-5.78125 0,-12.32386 -11.15545,-22.34375 -24.9375,-22.34375 z" />
123+ <path
124+ inkscape:connector-curvature="0"
125+ style="fill:#386195;fill-opacity:1;fill-rule:nonzero;stroke:#386195;stroke-width:24.07697487;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0.5;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
126+ id="path11963"
127+ d="m 975.70833,305.75079 c -17.87875,0 -33.1897,9.10731 -40.70137,22.18913 -3.00012,-1.63696 -6.34124,-2.6392 -9.87286,-2.6392 -10.67967,0 -19.5639,8.39604 -22.31073,19.7943 -4.6884,-1.81117 -10.09942,-2.93251 -15.92242,-2.93251 -17.46892,0 -31.65122,9.35352 -31.65122,20.86955 0,10.39528 11.61748,18.9466 26.71485,20.52749 -0.67665,1.12204 -1.20995,2.24338 -1.20995,3.42121 0,11.02604 30.92124,19.98985 69.01327,19.98985 38.09195,0 69.0132,-8.96381 69.0132,-19.98985 0,-0.74183 -0.5017,-1.42952 -0.7743,-2.15046 1.6684,0.40556 3.3496,0.83088 5.1784,0.83088 10.1902,0 18.439,-6.7716 18.439,-15.10234 0,-8.33078 -8.2488,-15.05348 -18.439,-15.05348 -1.2488,0 -2.3535,0.39297 -3.5329,0.58647 1.0312,-3.33102 1.7422,-6.7466 1.7422,-10.36143 0,-22.05212 -20.4533,-39.97961 -45.68617,-39.97961 z" />
128+ <path
129+ inkscape:connector-curvature="0"
130+ style="fill:#6798e9;fill-opacity:1;fill-rule:nonzero;stroke:#6798e9;stroke-width:15.64964962;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.20000005;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
131+ sodipodi:nodetypes="cccc"
132+ id="path11965"
133+ d="m 717.80594,482.73655 c -32.27924,28.4432 5.62151,52.69793 20.03284,13.63938 l 11.08203,-36.22961 -31.11487,22.59023 z" />
134+ <path
135+ inkscape:connector-curvature="0"
136+ style="fill:#6798e9;fill-opacity:1;fill-rule:nonzero;stroke:#6798e9;stroke-width:15.64964962;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.20000005;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
137+ sodipodi:nodetypes="cccc"
138+ id="path11967"
139+ d="m 799.47,485.76116 c -32.27925,28.4432 5.62151,52.69792 20.03284,13.63937 l 11.08202,-36.2296 -31.11486,22.59023 z" />
140+ <text
141+ xml:space="preserve"
142+ style="font-size:32px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold"
143+ x="68.985565"
144+ y="92.712631"
145+ id="text2992"
146+ sodipodi:linespacing="125%"
147+ transform="translate(321.13452,104.68346)"><tspan
148+ sodipodi:role="line"
149+ id="tspan2994"
150+ x="68.985565"
151+ y="92.712631" /></text>
152+ <text
153+ xml:space="preserve"
154+ style="font-size:10px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold"
155+ x="-202.1156"
156+ y="155.64684"
157+ id="text2996"
158+ sodipodi:linespacing="125%"
159+ transform="translate(321.13452,104.68346)"><tspan
160+ sodipodi:role="line"
161+ id="tspan2998"
162+ x="-202.1156"
163+ y="155.64684" /></text>
164+ <text
165+ xml:space="preserve"
166+ style="font-size:24px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold"
167+ x="342.91943"
168+ y="155.03653"
169+ id="text3000"
170+ sodipodi:linespacing="125%"><tspan
171+ sodipodi:role="line"
172+ id="tspan3002"
173+ x="342.91943"
174+ y="155.03653"
175+ style="font-size:32px;font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-family:Ubuntu;-inkscape-font-specification:Ubuntu Medium">Wheather App</tspan></text>
176+ <text
177+ xml:space="preserve"
178+ style="font-size:24px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ff0000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold"
179+ x="460.31592"
180+ y="358.3624"
181+ id="text3004"
182+ sodipodi:linespacing="125%"><tspan
183+ sodipodi:role="line"
184+ id="tspan3006"
185+ x="460.31592"
186+ y="358.3624"
187+ style="font-size:48px;fill:#ff0000;-inkscape-font-specification:Ubuntu;font-family:Ubuntu;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal">22C</tspan></text>
188+ <text
189+ xml:space="preserve"
190+ style="font-size:24px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#0000ff;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold"
191+ x="460.19751"
192+ y="412.14325"
193+ id="text3004-0"
194+ sodipodi:linespacing="125%"><tspan
195+ sodipodi:role="line"
196+ id="tspan3006-4"
197+ x="460.19751"
198+ y="412.14325"
199+ style="font-size:48px;fill:#0000ff;-inkscape-font-specification:Ubuntu Medium;font-family:Ubuntu;font-weight:500;font-style:normal;font-stretch:normal;font-variant:normal">14C</tspan></text>
200+ </g>
201+</svg>
qml/DeviceConfiguration.qmlnew file+81
@@ -0,0 +1,81 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+
19+StateGroup {
20+ id: root
21+
22+ readonly property int useNativeOrientation: -1
23+
24+ property int primaryOrientation: useNativeOrientation
25+
26+ property int supportedOrientations: Qt.PortraitOrientation
27+ | Qt.InvertedPortraitOrientation
28+ | Qt.LandscapeOrientation
29+ | Qt.InvertedLandscapeOrientation
30+
31+ // Supported values so far:
32+ // "phone", "tablet" or "desktop"
33+ property string category: "phone"
34+
35+
36+ property alias name: root.state
37+
38+ states: [
39+ State {
40+ name: "mako"
41+ PropertyChanges {
42+ target: root
43+ supportedOrientations: Qt.PortraitOrientation
44+ | Qt.LandscapeOrientation
45+ | Qt.InvertedLandscapeOrientation
46+ }
47+ },
48+ State {
49+ name: "krillin"
50+ PropertyChanges {
51+ target: root
52+ supportedOrientations: Qt.PortraitOrientation
53+ | Qt.LandscapeOrientation
54+ | Qt.InvertedLandscapeOrientation
55+ }
56+ },
57+ State {
58+ name: "manta"
59+ PropertyChanges {
60+ target: root
61+ category: "tablet"
62+ }
63+ },
64+ State {
65+ name: "flo"
66+ PropertyChanges {
67+ target: root
68+ primaryOrientation: Qt.InvertedLandscapeOrientation
69+ category: "tablet"
70+ }
71+ },
72+ State {
73+ name: "desktop"
74+ PropertyChanges {
75+ target: root
76+ category: "desktop"
77+ }
78+ }
79+ ]
80+
81+}
qml/Greeter/Greeter.qml+6−2
@@ -52,6 +52,8 @@ Showable {
52 property int failedLoginsDelayAttempts: 7 // number of failed logins
52 property int failedLoginsDelayAttempts: 7 // number of failed logins
53 property real failedLoginsDelayMinutes: 5 // minutes of forced waiting
53 property real failedLoginsDelayMinutes: 5 // minutes of forced waiting
54
54
55+ readonly property bool animating: loader.item ? loader.item.animating : false
56+
55 signal tease()
57 signal tease()
56 signal sessionStarted()
58 signal sessionStarted()
57 signal emergencyCall()
59 signal emergencyCall()
@@ -141,8 +143,10 @@ Showable {
141 enabled = false;
143 enabled = false;
142 if (LightDM.Greeter.startSessionSync()) {
144 if (LightDM.Greeter.startSessionSync()) {
143 sessionStarted();
145 sessionStarted();
146+ if (loader.item) {
144− loader.item.notifyAuthenticationSucceeded();
147+ loader.item.notifyAuthenticationSucceeded();
148+ }
145− } else {
149+ } else if (loader.item) {
146 loader.item.notifyAuthenticationFailed();
150 loader.item.notifyAuthenticationFailed();
147 }
151 }
148 enabled = true;
152 enabled = true;
qml/Greeter/NarrowView.qml+1
@@ -33,6 +33,7 @@ FocusScope {
33 property alias infographicModel: coverPage.infographicModel
33 property alias infographicModel: coverPage.infographicModel
34 readonly property bool fullyShown: coverPage.showProgress === 1 || lockscreen.shown
34 readonly property bool fullyShown: coverPage.showProgress === 1 || lockscreen.shown
35 readonly property bool required: coverPage.required || lockscreen.required
35 readonly property bool required: coverPage.required || lockscreen.required
36+ readonly property bool animating: coverPage.showAnimation.running || coverPage.hideAnimation.running
36
37
37 signal selected(int index) // unused
38 signal selected(int index) // unused
38 signal responded(string response)
39 signal responded(string response)
qml/Greeter/ShimGreeter.qmlnew file+45
@@ -0,0 +1,45 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.3
18+
19+/*
20+ * This is a shim greeter that is only used to provide a shell,
21+ * running without a greeter, the requisite information
22+ *
23+ */
24+
25+/* FIXME: this shuld be fine as a QtObject, but bug lp:1447391
26+ * dictates wrapping as an item instead
27+ */
28+Item {
29+ id: shimGreeter
30+
31+ readonly property bool active: false
32+ readonly property bool hasLockedApp: lockedApp !== ""
33+ readonly property bool locked: false
34+ readonly property bool shown: false
35+ readonly property bool waiting: false
36+
37+ property string lockedApp: ""
38+
39+ // Since ShimGreeter is never active, these can just return
40+ property var forceShow: (function() { return; })
41+ property var notifyAboutToFocusApp: (function(appId) { return; })
42+ property var notifyAppFocused: (function(appId) { return; })
43+ property var notifyShowingDashFromDrag: (function(appId) { return false; })
44+
45+}
qml/Greeter/WideView.qml+1
@@ -32,6 +32,7 @@ FocusScope {
32 property alias infographicModel: coverPage.infographicModel
32 property alias infographicModel: coverPage.infographicModel
33 readonly property bool fullyShown: coverPage.showProgress === 1
33 readonly property bool fullyShown: coverPage.showProgress === 1
34 readonly property bool required: coverPage.required
34 readonly property bool required: coverPage.required
35+ readonly property bool animating: coverPage.showAnimation.running || coverPage.hideAnimation.running
35
36
36 // so that it can be replaced in tests with a mock object
37 // so that it can be replaced in tests with a mock object
37 property var inputMethod: Qt.inputMethod
38 property var inputMethod: Qt.inputMethod
qml/OrientedShell.qmlnew file+185
@@ -0,0 +1,185 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import QtQuick.Window 2.0
19+import Unity.Session 0.1
20+import GSettings 1.0
21+import "Components"
22+import "Rotation"
23+
24+Rectangle {
25+ id: root
26+ color: "black"
27+
28+ implicitWidth: units.gu(40)
29+ implicitHeight: units.gu(71)
30+
31+ // NB: native and primary orientations here don't map exactly to their QScreen counterparts
32+ readonly property int nativeOrientation: width > height ? Qt.LandscapeOrientation : Qt.PortraitOrientation
33+
34+ readonly property int primaryOrientation:
35+ deviceConfiguration.primaryOrientation == deviceConfiguration.useNativeOrientation
36+ ? nativeOrientation : deviceConfiguration.primaryOrientation
37+
38+ DeviceConfiguration {
39+ id: deviceConfiguration
40+ name: applicationArguments.deviceName
41+ }
42+
43+ // to be overwritten by tests
44+ property var usageModeSettings: GSettings { schema.id: "com.canonical.Unity8" }
45+ property int physicalOrientation: Screen.orientation
46+ property bool orientationLocked: OrientationLock.enabled
47+ property var orientationLock: OrientationLock
48+
49+ property int orientation
50+ onPhysicalOrientationChanged: {
51+ if (!orientationLocked) {
52+ orientation = physicalOrientation;
53+ }
54+ }
55+ onOrientationLockedChanged: {
56+ if (orientationLocked) {
57+ orientationLock.savedOrientation = physicalOrientation;
58+ } else {
59+ orientation = physicalOrientation;
60+ }
61+ }
62+ Component.onCompleted: {
63+ if (orientationLocked) {
64+ orientation = orientationLock.savedOrientation;
65+ }
66+ }
67+
68+ readonly property int supportedOrientations: shell.supportedOrientations
69+ & deviceConfiguration.supportedOrientations
70+ property int acceptedOrientationAngle: {
71+ if (orientation & supportedOrientations) {
72+ return Screen.angleBetween(nativeOrientation, orientation);
73+ } else if (shell.orientation & supportedOrientations) {
74+ // stay where we are
75+ return shell.orientationAngle;
76+ } else if (angleToOrientation(shell.mainAppWindowOrientationAngle) & supportedOrientations) {
77+ return shell.mainAppWindowOrientationAngle;
78+ } else {
79+ // rotate to some supported orientation as we can't stay where we currently are
80+ // TODO: Choose the closest to the current one
81+ if (supportedOrientations & Qt.PortraitOrientation) {
82+ return Screen.angleBetween(nativeOrientation, Qt.PortraitOrientation);
83+ } else if (supportedOrientations & Qt.LandcscapeOrientation) {
84+ return Screen.angleBetween(nativeOrientation, Qt.LandscapeOrientation);
85+ } else if (supportedOrientations & Qt.InvertedPortraitOrientation) {
86+ return Screen.angleBetween(nativeOrientation, Qt.InvertedPortraitOrientation);
87+ } else if (supportedOrientations & Qt.InvertedLandscapeOrientation) {
88+ return Screen.angleBetween(nativeOrientation, Qt.InvertedLandscapeOrientation);
89+ } else {
90+ // if all fails, fallback to primary orientation
91+ return Screen.angleBetween(nativeOrientation, primaryOrientation);
92+ }
93+ }
94+ }
95+
96+ function angleToOrientation(angle) {
97+ switch (angle) {
98+ case 0:
99+ return nativeOrientation;
100+ break;
101+ case 90:
102+ return nativeOrientation === Qt.PortraitOrientation ? Qt.InvertedLandscapeOrientation
103+ : Qt.PortraitOrientation;
104+ break;
105+ case 180:
106+ return nativeOrientation === Qt.PortraitOrientation ? Qt.InvertedPortraitOrientation
107+ : Qt.InvertedLandscapeOrientation;
108+ break;
109+ case 270:
110+ return nativeOrientation === Qt.PortraitOrientation ? Qt.LandscapeOrientation
111+ : Qt.InvertedPortraitOrientation;
112+ break;
113+ default:
114+ console.warn("angleToOrientation: Invalid orientation angle: " + angle);
115+ return primaryOrientation;
116+ }
117+ }
118+
119+ RotationStates {
120+ id: rotationStates
121+ objectName: "rotationStates"
122+ orientedShell: root
123+ shell: shell
124+ shellCover: shellCover
125+ windowScreenshot: windowScreenshot
126+ }
127+
128+ Shell {
129+ id: shell
130+ objectName: "shell"
131+ width: root.width
132+ height: root.height
133+ orientation: root.angleToOrientation(orientationAngle)
134+ primaryOrientation: root.primaryOrientation
135+ nativeOrientation: root.nativeOrientation
136+ nativeWidth: root.width
137+ nativeHeight: root.height
138+
139+ // TODO: Factor in the connected input devices (eg: physical keyboard, mouse, touchscreen),
140+ // what's the output device (eg: big TV, desktop monitor, phone display), etc.
141+ usageScenario: {
142+ if (root.usageModeSettings.usageMode === "Windowed") {
143+ return "desktop";
144+ } else if (root.usageModeSettings.usageMode === "Staged"
145+ && deviceConfiguration.category === "desktop") {
146+ return "tablet";
147+ } else {
148+ return deviceConfiguration.category;
149+ }
150+ }
151+
152+ property real transformRotationAngle
153+ property real transformOriginX
154+ property real transformOriginY
155+
156+ transform: Rotation {
157+ origin.x: shell.transformOriginX; origin.y: shell.transformOriginY; axis { x: 0; y: 0; z: 1 }
158+ angle: shell.transformRotationAngle
159+ }
160+ }
161+
162+ Rectangle {
163+ id: shellCover
164+ color: "black"
165+ anchors.fill: parent
166+ visible: false
167+ }
168+
169+ WindowScreenshot {
170+ id: windowScreenshot
171+ visible: false
172+ width: root.width
173+ height: root.height
174+
175+ property real transformRotationAngle
176+ property real transformOriginX
177+ property real transformOriginY
178+
179+ transform: Rotation {
180+ origin.x: windowScreenshot.transformOriginX; origin.y: windowScreenshot.transformOriginY;
181+ axis { x: 0; y: 0; z: 1 }
182+ angle: windowScreenshot.transformRotationAngle
183+ }
184+ }
185+}
qml/Panel/Indicators/IndicatorsLight.qml+8
@@ -26,6 +26,8 @@ import Unity.Indicators 0.1 as Indicators
26QtObject {
26QtObject {
27 id: root
27 id: root
28
28
29+ property color color: "darkgreen"
30+
29 property var _actionGroup: QMenuModel.QDBusActionGroup {
31 property var _actionGroup: QMenuModel.QDBusActionGroup {
30 busType: 1
32 busType: 1
31 busName: "com.canonical.indicator.messages"
33 busName: "com.canonical.indicator.messages"
@@ -50,4 +52,10 @@ QtObject {
50 return (Powerd.status === Powerd.Off && _rootState.hasMessages) ? Lights.On : Lights.Off
52 return (Powerd.status === Powerd.Off && _rootState.hasMessages) ? Lights.On : Lights.Off
51 }
53 }
52 }
54 }
55+
56+ property var _colorBinding: Binding {
57+ target: Lights
58+ property: "color"
59+ value: root.color
60+ }
53}
61}
qml/Panel/Panel.qml+9
@@ -27,6 +27,9 @@ Item {
27 property alias indicators: __indicators
27 property alias indicators: __indicators
28 property alias callHint: __callHint
28 property alias callHint: __callHint
29 property bool fullscreenMode: false
29 property bool fullscreenMode: false
30+ property real indicatorAreaShowProgress: 1.0
31+
32+ opacity: fullscreenMode && indicators.fullyClosed ? 0.0 : 1.0
30
33
31 Rectangle {
34 Rectangle {
32 id: darkenedArea
35 id: darkenedArea
@@ -58,6 +61,12 @@ Item {
58 NumberAnimation { duration: UbuntuAnimation.FastDuration; easing: UbuntuAnimation.StandardEasing }
61 NumberAnimation { duration: UbuntuAnimation.FastDuration; easing: UbuntuAnimation.StandardEasing }
59 }
62 }
60
63
64+ transform: Translate {
65+ y: indicators.state === "initial"
66+ ? (1.0 - indicatorAreaShowProgress) * -d.indicatorHeight
67+ : 0
68+ }
69+
61 BorderImage {
70 BorderImage {
62 id: dropShadow
71 id: dropShadow
63 anchors {
72 anchors {
qml/Rotation/HalfLoopRotationAnimation.qmlnew file+46
@@ -0,0 +1,46 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.3
18+
19+SequentialAnimation {
20+ id: root
21+
22+ // set from outside
23+ property int fromAngle
24+ property int toAngle
25+ property var info
26+ property var shell
27+
28+ readonly property bool flipShellDimensions: toAngle == 90 || toAngle == 270
29+
30+ ScriptAction { script: {
31+ info.transitioning = true;
32+ shell.orientationAngle = root.toAngle;
33+ shell.x = (orientedShell.width - shell.width) / 2
34+ shell.y = (orientedShell.height - shell.height) / 2;
35+ shell.transformOriginX = shell.width / 2;
36+ shell.transformOriginY = shell.height / 2;
37+ shell.updateFocusedAppOrientation();
38+ } }
39+ NumberAnimation {
40+ target: shell
41+ property: "transformRotationAngle"
42+ from: root.fromAngle; to: root.toAngle
43+ duration: rotationDuration; easing.type: rotationEasing
44+ }
45+ ScriptAction { script: { info.transitioning = false; } }
46+}
qml/Rotation/ImmediateRotationAction.qmlnew file+45
@@ -0,0 +1,45 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.3
18+
19+ScriptAction {
20+ property var info
21+ property var shell
22+
23+ script: {
24+ info.transitioning = true;
25+ shell.orientationAngle = info.requestedOrientationAngle;
26+ shell.transformRotationAngle = info.requestedOrientationAngle;
27+
28+ // Making bindings as orientedShell's dimensions might wiggle during startup.
29+ if (info.requestedOrientationAngle === 90 || info.requestedOrientationAngle === 270) {
30+ shell.width = Qt.binding(function() { return orientedShell.height; });
31+ shell.height = Qt.binding(function() { return orientedShell.width; });
32+ } else {
33+ shell.width = Qt.binding(function() { return orientedShell.width; });
34+ shell.height = Qt.binding(function() { return orientedShell.height; });
35+ }
36+
37+ shell.x = Qt.binding(function() { return (orientedShell.width - shell.width) / 2; });
38+ shell.y = Qt.binding(function() { return (orientedShell.height - shell.height) / 2; });
39+ shell.transformOriginX = Qt.binding(function() { return shell.width / 2; });
40+ shell.transformOriginY = Qt.binding(function() { return shell.height / 2; });
41+
42+ shell.updateFocusedAppOrientation();
43+ info.transitioning = false;
44+ }
45+}
qml/Rotation/NinetyRotationAnimation.qmlnew file+90
@@ -0,0 +1,90 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.3
18+
19+SequentialAnimation {
20+ id: root
21+
22+ property int fromAngle
23+ property int toAngle
24+ property var info
25+ property var shell
26+
27+ readonly property real fromY: fromAngle === 0 || fromAngle === 90 ? 0 : orientedShell.height - orientedShell.width;
28+ readonly property real toY: toAngle === 0 || toAngle === 90 ? 0 : orientedShell.height - orientedShell.width;
29+ readonly property bool flipShellDimensions: toAngle == 90 || toAngle == 270
30+
31+ ScriptAction { script: {
32+ info.transitioning = true;
33+ windowScreenshot.take();
34+ windowScreenshot.visible = true;
35+ shell.orientationAngle = root.toAngle;
36+ shell.x = 0;
37+ shell.width = flipShellDimensions ? orientedShell.height : orientedShell.width;
38+ shell.height = flipShellDimensions ? orientedShell.width : orientedShell.height;
39+ shell.transformOriginX = orientedShell.width / 2;
40+ shell.transformOriginY = orientedShell.width / 2;
41+ shell.updateFocusedAppOrientation();
42+ shellCover.visible = true;
43+
44+ windowScreenshot.transformOriginX = orientedShell.width / 2;
45+ if (fromAngle == 180 || fromAngle == 270) {
46+ windowScreenshot.transformOriginY = orientedShell.height - (orientedShell.width / 2);
47+ } else {
48+ windowScreenshot.transformOriginY = orientedShell.width / 2;
49+ }
50+ } }
51+ ParallelAnimation {
52+ NumberAnimation {
53+ target: shellCover; property: "opacity"; from: 1; to: 0;
54+ duration: rotationDuration; easing.type: rotationEasing
55+ }
56+ RotationAnimation {
57+ target: shell; property: "transformRotationAngle";
58+ from: root.fromAngle; to: root.toAngle
59+ direction: RotationAnimation.Shortest
60+ duration: rotationDuration; easing.type: rotationEasing
61+ }
62+ NumberAnimation {
63+ target: shell; property: "y"
64+ from: root.fromY; to: root.toY
65+ duration: rotationDuration; easing.type: rotationEasing
66+ }
67+
68+ NumberAnimation {
69+ target: windowScreenshot; property: "opacity"; from: 1; to: 0;
70+ duration: rotationDuration; easing.type: rotationEasing
71+ }
72+ RotationAnimation {
73+ target: windowScreenshot; property: "transformRotationAngle";
74+ from: 0; to: root.toAngle - root.fromAngle
75+ direction: RotationAnimation.Shortest
76+ duration: rotationDuration; easing.type: rotationEasing
77+ }
78+ NumberAnimation {
79+ target: windowScreenshot; property: "y"
80+ from: 0; to: root.toY - root.fromY
81+ duration: rotationDuration; easing.type: rotationEasing
82+ }
83+ }
84+ ScriptAction { script: {
85+ windowScreenshot.visible = false;
86+ windowScreenshot.discard();
87+ shellCover.visible = false;
88+ info.transitioning = false;
89+ } }
90+}
qml/Rotation/RotationStates.qmlnew file+278
@@ -0,0 +1,278 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import Ubuntu.Components 1.1
19+import Powerd 0.1
20+
21+// Why the state machine is done that way:
22+// We cannot use regular PropertyChanges{} inside the State elements as steps in the
23+// transition animations must take place in a well defined order.
24+// Which means that we also cannot jump to a new state in the middle of a transition
25+// as that would make hell brake loose.
26+StateGroup {
27+ id: root
28+
29+ // to be set from the outside
30+ property Item orientedShell
31+ property Item shell
32+ property Item shellCover
33+ property Item windowScreenshot
34+
35+ property int rotationDuration: 450
36+ property int rotationEasing: Easing.InOutCubic
37+ // Those values are good for debugging/development
38+ //property int rotationDuration: 3000
39+ //property int rotationEasing: Easing.Linear
40+
41+ state: "0"
42+ states: [
43+ State { name: "0" },
44+ State { name: "90" },
45+ State { name: "180" },
46+ State { name: "270" }
47+ ]
48+
49+ property QtObject d: QtObject {
50+ id: d
51+
52+ property bool startingUp: true
53+ property var finishStartUpTimer: Timer {
54+ interval: 500
55+ onTriggered: d.startingUp = false
56+ }
57+ Component.onCompleted: {
58+ finishStartUpTimer.start();
59+ }
60+
61+ property bool transitioning: false
62+ onTransitioningChanged: {
63+ d.tryUpdateState();
64+ }
65+
66+ readonly property int requestedOrientationAngle: root.orientedShell.acceptedOrientationAngle
67+
68+ // Avoiding a direct call to tryUpdateState() as the state change might trigger an immediate
69+ // change to Shell.orientationAngle which, in its turn, causes a reevaluation of
70+ // requestedOrientationAngle (ie., OrientedShell.acceptedOrientationAngle). A reentrant evaluation
71+ // of a binding is detected by QML as a binding loop and QML will deny the reevalutation, which
72+ // will leave us in a bogus state.
73+ //
74+ // To avoid this mess we update the state in the next event loop iteration, ensuring a clean
75+ // call stack.
76+ onRequestedOrientationAngleChanged: {
77+ stateUpdateTimer.start();
78+ }
79+ property Timer stateUpdateTimer: Timer {
80+ id: stateUpdateTimer
81+ interval: 1
82+ onTriggered: { d.tryUpdateState(); }
83+ }
84+
85+ function tryUpdateState() {
86+ if (d.transitioning || (!d.startingUp && !root.shell.orientationChangesEnabled)) {
87+ return;
88+ }
89+
90+ var requestedState = d.requestedOrientationAngle.toString();
91+ if (requestedState !== root.state) {
92+ d.resolveAnimationType();
93+ root.state = requestedState;
94+ }
95+ }
96+
97+ property Connections shellConnections: Connections {
98+ target: root.shell
99+ onOrientationChangesEnabledChanged: {
100+ d.tryUpdateState();
101+ }
102+ }
103+
104+ property var shellBeingResized: Binding {
105+ target: root.shell
106+ property: "beingResized"
107+ value: d.transitioning
108+ }
109+
110+ readonly property int fullAnimation: 0
111+ readonly property int indicatorsBarAnimation: 1
112+ readonly property int noAnimation: 2
113+
114+ property int animationType
115+
116+ // animationType update *must* take place *before* the state update.
117+ // If animationType and state were updated through bindings, as with normal qml code,
118+ // there would be no guarantee in the order of the binding updates, which could then
119+ // cause the wrong transitions to be chosen for the state changes.
120+ function resolveAnimationType() {
121+ if (d.startingUp) {
122+ // During start up, inital property values are still settling while we're still
123+ // to render the very first frame
124+ d.animationType = d.noAnimation;
125+ } else if (Powerd.status === Powerd.Off) {
126+ // There's no point in animating if the user can't see it (display is off).
127+ d.animationType = d.noAnimation;
128+ } else if (root.shell.showingGreeter) {
129+ // A rotating greeter looks weird.
130+ d.animationType = d.noAnimation;
131+ } else {
132+ if (!root.shell.mainApp) {
133+ // shouldn't happen but, anyway
134+ d.animationType = d.fullAnimation;
135+ return;
136+ }
137+
138+ if (root.shell.mainApp.rotatesWindowContents) {
139+ // The application will animate its own GUI, so we don't have to do anything ourselves.
140+ d.animationType = d.noAnimation;
141+ } else if (root.shell.mainAppWindowOrientationAngle == d.requestedOrientationAngle) {
142+ // The app window is already on its final orientation angle.
143+ // So we just animate the indicators bar
144+ // TODO: what if the app is fullscreen?
145+ d.animationType = d.indicatorsBarAnimation;
146+ } else {
147+ d.animationType = d.fullAnimation;
148+ }
149+ }
150+ }
151+
152+ // When an application switch takes place, d.requestedOrientationAngle and
153+ // root.shell.mainAppWindowOrientationAngle get updated separately, at different moments.
154+ // So, when one of those properties change, we shouldn't make a decision straight away
155+ // as the other might be stale and about to be changed. So let's give it a bit of time for
156+ // them to get properly updated.
157+ // This approach is indeed a bit hacky.
158+ property bool appWindowOrientationAngleNeedsUpdateUnstable:
159+ root.shell.orientationAngle === d.requestedOrientationAngle
160+ && root.shell.mainApp
161+ && root.shell.mainAppWindowOrientationAngle !== root.shell.orientationAngle
162+ && !d.transitioning
163+ onAppWindowOrientationAngleNeedsUpdateUnstableChanged: {
164+ stableTimer.restart();
165+ }
166+ property Timer stableTimer: Timer {
167+ interval: 200
168+ onTriggered: {
169+ if (d.appWindowOrientationAngleNeedsUpdateUnstable) {
170+ shell.updateFocusedAppOrientationAnimated();
171+ }
172+ }
173+ }
174+ }
175+
176+ transitions: [
177+ Transition {
178+ from: "90"; to: "0"
179+ enabled: d.animationType == d.fullAnimation
180+ NinetyRotationAnimation { fromAngle: 90; toAngle: 0
181+ info: d; shell: root.shell }
182+ },
183+ Transition {
184+ from: "0"; to: "90"
185+ enabled: d.animationType == d.fullAnimation
186+ NinetyRotationAnimation { fromAngle: 0; toAngle: 90
187+ info: d; shell: root.shell }
188+ },
189+ Transition {
190+ from: "0"; to: "270"
191+ enabled: d.animationType == d.fullAnimation
192+ NinetyRotationAnimation { fromAngle: 0; toAngle: 270
193+ info: d; shell: root.shell }
194+ },
195+ Transition {
196+ from: "270"; to: "0"
197+ enabled: d.animationType == d.fullAnimation
198+ NinetyRotationAnimation { fromAngle: 270; toAngle: 0
199+ info: d; shell: root.shell }
200+ },
201+ Transition {
202+ from: "90"; to: "180"
203+ enabled: d.animationType == d.fullAnimation
204+ NinetyRotationAnimation { fromAngle: 90; toAngle: 180
205+ info: d; shell: root.shell }
206+ },
207+ Transition {
208+ from: "180"; to: "90"
209+ enabled: d.animationType == d.fullAnimation
210+ NinetyRotationAnimation { fromAngle: 180; toAngle: 90
211+ info: d; shell: root.shell }
212+ },
213+ Transition {
214+ from: "180"; to: "270"
215+ enabled: d.animationType == d.fullAnimation
216+ NinetyRotationAnimation { fromAngle: 180; toAngle: 270
217+ info: d; shell: root.shell }
218+ },
219+ Transition {
220+ from: "270"; to: "180"
221+ enabled: d.animationType == d.fullAnimation
222+ NinetyRotationAnimation { fromAngle: 270; toAngle: 180
223+ info: d; shell: root.shell }
224+ },
225+ Transition {
226+ from: "0"; to: "180"
227+ enabled: d.animationType == d.fullAnimation
228+ HalfLoopRotationAnimation { fromAngle: 0; toAngle: 180
229+ info: d; shell: root.shell }
230+ },
231+ Transition {
232+ from: "180"; to: "0"
233+ enabled: d.animationType == d.fullAnimation
234+ HalfLoopRotationAnimation { fromAngle: 180; toAngle: 0
235+ info: d; shell: root.shell }
236+ },
237+ Transition {
238+ from: "90"; to: "270"
239+ enabled: d.animationType == d.fullAnimation
240+ HalfLoopRotationAnimation { fromAngle: 90; toAngle: 270
241+ info: d; shell: root.shell }
242+ },
243+ Transition {
244+ from: "270"; to: "90"
245+ enabled: d.animationType == d.fullAnimation
246+ HalfLoopRotationAnimation { fromAngle: 270; toAngle: 90
247+ info: d; shell: root.shell }
248+ },
249+ Transition {
250+ objectName: "immediateTransition"
251+ enabled: d.animationType == d.noAnimation
252+ ImmediateRotationAction { info: d; shell: root.shell }
253+ },
254+ Transition {
255+ enabled: d.animationType == d.indicatorsBarAnimation
256+ SequentialAnimation {
257+ ScriptAction { script: {
258+ d.transitioning = true;
259+ } }
260+ NumberAnimation {
261+ duration: UbuntuAnimation.FastDuration; easing: UbuntuAnimation.StandardEasing
262+ target: root.shell; property: "indicatorAreaShowProgress"
263+ from: 1.0; to: 0.0
264+ }
265+ ImmediateRotationAction { info: d; shell: root.shell }
266+ NumberAnimation {
267+ duration: UbuntuAnimation.FastDuration; easing: UbuntuAnimation.StandardEasing
268+ target: root.shell; property: "indicatorAreaShowProgress"
269+ from: 0.0; to: 1.0
270+ }
271+ ScriptAction { script: {
272+ d.transitioning = false;
273+ }}
274+ }
275+ }
276+ ]
277+
278+}
qml/Shell.qml+157−82
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2013 Canonical, Ltd.
2+ * Copyright (C) 2013-2015 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
@@ -45,47 +45,80 @@ import Unity.Indicators 0.1 as Indicators
45Item {
45Item {
46 id: shell
46 id: shell
47
47
48+ // to be set from outside
49+ property int orientationAngle: 0
50+ property int orientation
51+ property int primaryOrientation
52+ property int nativeOrientation
53+ property real nativeWidth
54+ property real nativeHeight
55+ property alias indicatorAreaShowProgress: panel.indicatorAreaShowProgress
56+ property bool beingResized
57+ property string usageScenario: "phone" // supported values: "phone", "tablet" or "desktop"
58+ function updateFocusedAppOrientation() {
59+ applicationsDisplayLoader.item.updateFocusedAppOrientation();
60+ }
61+ function updateFocusedAppOrientationAnimated() {
62+ applicationsDisplayLoader.item.updateFocusedAppOrientationAnimated();
63+ }
64+
65+ // to be read from outside
66+ readonly property int mainAppWindowOrientationAngle:
67+ applicationsDisplayLoader.item ? applicationsDisplayLoader.item.mainAppWindowOrientationAngle : 0
68+
69+ readonly property bool orientationChangesEnabled: panel.indicators.fullyClosed
70+ && (applicationsDisplayLoader.item && applicationsDisplayLoader.item.orientationChangesEnabled)
71+ && !greeter.animating
72+
73+ readonly property bool showingGreeter: greeter.shown
74+
75+ property bool startingUp: true
76+ Timer { id: finishStartUpTimer; interval: 500; onTriggered: startingUp = false }
77+
78+ property int supportedOrientations: {
79+ if (startingUp) {
80+ // Ensure we don't rotate during start up
81+ return Qt.PrimaryOrientation;
82+ } else if (greeter.shown) {
83+ return Qt.PrimaryOrientation;
84+ } else if (mainApp) {
85+ return mainApp.supportedOrientations;
86+ } else {
87+ // we just don't care
88+ return Qt.PortraitOrientation
89+ | Qt.LandscapeOrientation
90+ | Qt.InvertedPortraitOrientation
91+ | Qt.InvertedLandscapeOrientation;
92+ }
93+ }
94+
95+ // For autopilot consumption
96+ readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
97+
98+ // internal props from here onwards
99+ readonly property var mainApp:
100+ applicationsDisplayLoader.item ? applicationsDisplayLoader.item.mainApp : null
101+
48 // Disable everything while greeter is waiting, so that the user can't swipe
102 // Disable everything while greeter is waiting, so that the user can't swipe
49 // the greeter or launcher until we know whether the session is locked.
103 // the greeter or launcher until we know whether the session is locked.
50 enabled: !greeter.waiting
104 enabled: !greeter.waiting
51
105
52− // this is only here to select the width / height of the window if not running fullscreen
53− property bool tablet: false
54− width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
55− height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
56−
57 property real edgeSize: units.gu(2)
106 property real edgeSize: units.gu(2)
58 property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
107 property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
59 property url background: asImageTester.status == Image.Ready ? asImageTester.source
108 property url background: asImageTester.status == Image.Ready ? asImageTester.source
60 : gsImageTester.status == Image.Ready ? gsImageTester.source : defaultBackground
109 : gsImageTester.status == Image.Ready ? gsImageTester.source : defaultBackground
61
110
62− property bool sideStageEnabled: shell.width >= units.gu(100)
63− readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
64−
65− property int orientation
66− readonly property int deviceOrientationAngle: Screen.angleBetween(Screen.primaryOrientation, Screen.orientation)
67− onDeviceOrientationAngleChanged: {
68− if (!OrientationLock.enabled) {
69− orientation = Screen.orientation;
70− }
71− }
72− readonly property bool orientationLockEnabled: OrientationLock.enabled
73− onOrientationLockEnabledChanged: {
74− if (orientationLockEnabled) {
75− OrientationLock.savedOrientation = Screen.orientation;
76− } else {
77− orientation = Screen.orientation;
78− }
79− }
80−
81 // This is _only_ used to expose the property to autopilot tests
111 // This is _only_ used to expose the property to autopilot tests
82 readonly property string testShellMode: shellMode
112 readonly property string testShellMode: shellMode
83
113
114+ readonly property alias greeter: greeterLoader.item
115+
84 function activateApplication(appId) {
116 function activateApplication(appId) {
85 if (ApplicationManager.findApplication(appId)) {
117 if (ApplicationManager.findApplication(appId)) {
86 ApplicationManager.requestFocusApplication(appId);
118 ApplicationManager.requestFocusApplication(appId);
87 } else {
119 } else {
88− var execFlags = shell.sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;
120+ var execFlags = shell.usageScenario === "phone" ? ApplicationManager.ForceMainStage
121+ : ApplicationManager.NoFlag;
89 ApplicationManager.startApplication(appId, execFlags);
122 ApplicationManager.startApplication(appId, execFlags);
90 }
123 }
91 }
124 }
@@ -109,7 +142,6 @@ Item {
109
142
110 GSettings {
143 GSettings {
111 id: backgroundSettings
144 id: backgroundSettings
112− objectName: "backgroundSettings"
113 schema.id: "org.gnome.desktop.background"
145 schema.id: "org.gnome.desktop.background"
114 }
146 }
115
147
@@ -123,11 +155,6 @@ Item {
123 sourceSize.width: 0
155 sourceSize.width: 0
124 }
156 }
125
157
126− GSettings {
127− id: usageModeSettings
128− schema.id: "com.canonical.Unity8"
129− }
130−
131 Binding {
158 Binding {
132 target: LauncherModel
159 target: LauncherModel
133 property: "applicationManager"
160 property: "applicationManager"
@@ -139,9 +166,7 @@ Item {
139 if (ApplicationManager.count > 0) {
166 if (ApplicationManager.count > 0) {
140 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
167 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
141 }
168 }
142− if (orientationLockEnabled) {
169+ finishStartUpTimer.start();
143− orientation = OrientationLock.savedOrientation;
144− }
145 }
170 }
146
171
147 VolumeControl {
172 VolumeControl {
@@ -234,9 +259,21 @@ Item {
234 // theoretical attack where user enters lockedApp mode, then makes
259 // theoretical attack where user enters lockedApp mode, then makes
235 // the screen larger (maybe connects to monitor) and tries to enter
260 // the screen larger (maybe connects to monitor) and tries to enter
236 // tablet mode.
261 // tablet mode.
262+
237− property bool tabletMode: shell.sideStageEnabled && !greeter.hasLockedApp
263+ property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
264+ ? "phone"
265+ : shell.usageScenario
266+ source: {
267+ if(shellMode === "greeter") {
268+ return "Stages/ShimStage.qml"
269+ } else if (applicationsDisplayLoader.usageScenario === "phone") {
270+ return "Stages/PhoneStage.qml";
271+ } else if (applicationsDisplayLoader.usageScenario === "tablet") {
272+ return "Stages/TabletStage.qml";
273+ } else {
238− source: usageModeSettings.usageMode === "Windowed" ? "Stages/DesktopStage.qml"
274+ return "Stages/DesktopStage.qml";
239− : tabletMode ? "Stages/TabletStage.qml" : "Stages/PhoneStage.qml"
275+ }
276+ }
240
277
241 property bool interactive: tutorial.spreadEnabled
278 property bool interactive: tutorial.spreadEnabled
242 && !greeter.shown
279 && !greeter.shown
@@ -279,7 +316,12 @@ Item {
279 }
316 }
280 Binding {
317 Binding {
281 target: applicationsDisplayLoader.item
318 target: applicationsDisplayLoader.item
282− property: "orientation"
319+ property: "shellOrientationAngle"
320+ value: shell.orientationAngle
321+ }
322+ Binding {
323+ target: applicationsDisplayLoader.item
324+ property: "shellOrientation"
283 value: shell.orientation
325 value: shell.orientation
284 }
326 }
285 Binding {
327 Binding {
@@ -287,6 +329,31 @@ Item {
287 property: "background"
329 property: "background"
288 value: shell.background
330 value: shell.background
289 }
331 }
332+ Binding {
333+ target: applicationsDisplayLoader.item
334+ property: "shellPrimaryOrientation"
335+ value: shell.primaryOrientation
336+ }
337+ Binding {
338+ target: applicationsDisplayLoader.item
339+ property: "nativeOrientation"
340+ value: shell.nativeOrientation
341+ }
342+ Binding {
343+ target: applicationsDisplayLoader.item
344+ property: "nativeWidth"
345+ value: shell.nativeWidth
346+ }
347+ Binding {
348+ target: applicationsDisplayLoader.item
349+ property: "nativeHeight"
350+ value: shell.nativeHeight
351+ }
352+ Binding {
353+ target: applicationsDisplayLoader.item
354+ property: "beingResized"
355+ value: shell.beingResized
356+ }
290 }
357 }
291
358
292 Tutorial {
359 Tutorial {
@@ -351,50 +418,59 @@ Item {
351 }
418 }
352 }
419 }
353
420
354− Greeter {
421+ Loader {
355− id: greeter
422+ id: greeterLoader
356− objectName: "greeter"
357−
358− hides: [launcher, panel.indicators]
359− tabletMode: shell.sideStageEnabled
360− launcherOffset: launcher.progress
361− forcedUnlock: tutorial.running
362− background: shell.background
363−
364 anchors.fill: parent
423 anchors.fill: parent
365 anchors.topMargin: panel.panelHeight
424 anchors.topMargin: panel.panelHeight
425+ sourceComponent: shellMode != "shell" ? integratedGreeter :
426+ Qt.createComponent(Qt.resolvedUrl("Greeter/ShimGreeter.qml"));
427+ onLoaded: {
428+ item.objectName = "greeter"
429+ }
430+ }
366
431
367− // avoid overlapping with Launcher's edge drag area
432+ Component {
368− // FIXME: Fix TouchRegistry & friends and remove this workaround
433+ id: integratedGreeter
369− // Issue involves launcher's DDA getting disabled on a long
434+ Greeter {
370− // left-edge drag
371− dragHandleLeftMargin: launcher.available ? launcher.dragAreaWidth + 1 : 0
372
435
373− onSessionStarted: {
436+ hides: [launcher, panel.indicators]
374− launcher.hide();
437+ tabletMode: shell.sideStageEnabled
375− }
438+ launcherOffset: launcher.progress
439+ forcedUnlock: tutorial.running
440+ background: shell.background
376
441
377− onTease: {
442+ // avoid overlapping with Launcher's edge drag area
378− if (!tutorial.running) {
443+ // FIXME: Fix TouchRegistry & friends and remove this workaround
444+ // Issue involves launcher's DDA getting disabled on a long
445+ // left-edge drag
446+ dragHandleLeftMargin: launcher.available ? launcher.dragAreaWidth + 1 : 0
447+
448+ onSessionStarted: {
379− launcher.tease();
449+ launcher.hide();
380 }
450 }
381− }
382
451
383− onEmergencyCall: startLockedApp("dialer-app")
452+ onTease: {
453+ if (!tutorial.running) {
454+ launcher.tease();
455+ }
456+ }
384
457
385− Timer {
458+ onEmergencyCall: startLockedApp("dialer-app")
386− // See powerConnection for why this is useful
459+
387− id: showGreeterDelayed
460+ Binding {
388− interval: 1
461+ target: ApplicationManager
389− onTriggered: {
462+ property: "suspended"
390− greeter.forceShow();
463+ value: greeter.shown
391 }
464 }
392 }
465 }
466+ }
393
467
394− Binding {
468+ Timer {
395− target: ApplicationManager
469+ // See powerConnection for why this is useful
396− property: "suspended"
470+ id: showGreeterDelayed
471+ interval: 1
472+ onTriggered: {
397− value: greeter.shown
473+ greeter.forceShow();
398 }
474 }
399 }
475 }
400
476
@@ -483,20 +559,18 @@ Item {
483 expandedPanelHeight: units.gu(7)
559 expandedPanelHeight: units.gu(7)
484
560
485 indicatorsModel: Indicators.IndicatorsModel {
561 indicatorsModel: Indicators.IndicatorsModel {
486− // TODO: This should be sourced by device type (e.g. "desktop", "tablet", "phone"...)
562+ // tablet and phone both use the same profile
487− profile: indicatorProfile
563+ profile: shell.usageScenario === "desktop" ? "desktop" : "phone"
488− Component.onCompleted: load()
564+ Component.onCompleted: load();
489 }
565 }
490 }
566 }
567+
491 callHint {
568 callHint {
492 greeterShown: greeter.shown
569 greeterShown: greeter.shown
493 }
570 }
494
571
495− property bool topmostApplicationIsFullscreen:
572+ property bool mainAppIsFullscreen: shell.mainApp && shell.mainApp.fullscreen
496− ApplicationManager.focusedApplicationId &&
497− ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).fullscreen
498−
499− fullscreenMode: (topmostApplicationIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
573+ fullscreenMode: (mainAppIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
500 || greeter.hasLockedApp
574 || greeter.hasLockedApp
501 }
575 }
502
576
@@ -514,7 +588,7 @@ Item {
514 available: tutorial.launcherEnabled
588 available: tutorial.launcherEnabled
515 && (!greeter.locked || AccountsService.enableLauncherWhileLocked)
589 && (!greeter.locked || AccountsService.enableLauncherWhileLocked)
516 && !greeter.hasLockedApp
590 && !greeter.hasLockedApp
517− inverted: usageModeSettings.usageMode === "Staged"
591+ inverted: shell.usageScenario !== "desktop"
518 shadeBackground: !tutorial.running
592 shadeBackground: !tutorial.running
519
593
520 onShowDashHome: showHome()
594 onShowDashHome: showHome()
@@ -556,7 +630,7 @@ Item {
556 Rectangle {
630 Rectangle {
557 id: modalNotificationBackground
631 id: modalNotificationBackground
558
632
559− visible: notifications.useModal && (notifications.state == "narrow")
633+ visible: notifications.useModal
560 color: "#000000"
634 color: "#000000"
561 anchors.fill: parent
635 anchors.fill: parent
562 opacity: 0.9
636 opacity: 0.9
@@ -601,6 +675,7 @@ Item {
601
675
602 Dialogs {
676 Dialogs {
603 id: dialogs
677 id: dialogs
678+ objectName: "dialogs"
604 anchors.fill: parent
679 anchors.fill: parent
605 z: overlay.z + 10
680 z: overlay.z + 10
606 onPowerOffClicked: {
681 onPowerOffClicked: {
qml/Stages/ApplicationWindow.qml+53−18
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright 2014 Canonical Ltd.
2+ * Copyright 2014-2015 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 Lesser General Public License as published by
5 * it under the terms of the GNU Lesser General Public License as published by
@@ -24,10 +24,11 @@ FocusScope {
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 property alias interactive: sessionContainer.interactive
27+ property bool orientationChangesEnabled: d.supportsSurfaceResize ? d.surfaceOldEnoughToBeResized : true
27
28
28 // to be set from outside
29 // to be set from outside
29 property QtObject application
30 property QtObject application
30− property int orientation
31+ property int surfaceOrientationAngle
31
32
32 QtObject {
33 QtObject {
33 id: d
34 id: d
@@ -62,6 +63,15 @@ FocusScope {
62 // Remove this when possible
63 // Remove this when possible
63 property bool surfaceInitialized: false
64 property bool surfaceInitialized: false
64
65
66+ property bool supportsSurfaceResize:
67+ application &&
68+ ((application.supportedOrientations & Qt.PortraitOrientation)
69+ || (application.supportedOrientations & Qt.InvertedPortraitOrientation))
70+ &&
71+ ((application.supportedOrientations & Qt.LandscapeOrientation)
72+ || (application.supportedOrientations & Qt.InvertedLandscapeOrientation))
73+
74+ property bool surfaceOldEnoughToBeResized: false
65 }
75 }
66
76
67 Timer {
77 Timer {
@@ -70,6 +80,12 @@ FocusScope {
70 onTriggered: { if (sessionContainer.surface) {d.surfaceInitialized = true;} }
80 onTriggered: { if (sessionContainer.surface) {d.surfaceInitialized = true;} }
71 }
81 }
72
82
83+ Timer {
84+ id: surfaceIsOldTimer
85+ interval: 1000
86+ onTriggered: { if (stateGroup.state === "surface") { d.surfaceOldEnoughToBeResized = true; } }
87+ }
88+
73 Image {
89 Image {
74 id: screenshotImage
90 id: screenshotImage
75 objectName: "screenshotImage"
91 objectName: "screenshotImage"
@@ -113,7 +129,8 @@ FocusScope {
113 // A fake application might not even have a session property.
129 // A fake application might not even have a session property.
114 session: application && application.session ? application.session : null
130 session: application && application.session ? application.session : null
115 anchors.fill: parent
131 anchors.fill: parent
116− orientation: root.orientation
132+
133+ surfaceOrientationAngle: application && application.rotatesWindowContents ? root.surfaceOrientationAngle : 0
117
134
118 onSurfaceChanged: {
135 onSurfaceChanged: {
119 if (sessionContainer.surface) {
136 if (sessionContainer.surface) {
@@ -179,15 +196,21 @@ FocusScope {
179 UbuntuNumberAnimation { target: sessionContainer.surfaceContainer; property: "opacity";
196 UbuntuNumberAnimation { target: sessionContainer.surfaceContainer; property: "opacity";
180 from: 0.0; to: 1.0
197 from: 0.0; to: 1.0
181 duration: UbuntuAnimation.BriskDuration }
198 duration: UbuntuAnimation.BriskDuration }
199+ ScriptAction { script: {
182− PropertyAction { target: splashLoader; property: "active"; value: false }
200+ splashLoader.active = false;
201+ surfaceIsOldTimer.start();
202+ } }
183 }
203 }
184 },
204 },
185 Transition {
205 Transition {
186 from: "surface"; to: "splashScreen"
206 from: "surface"; to: "splashScreen"
187 SequentialAnimation {
207 SequentialAnimation {
208+ ScriptAction { script: {
209+ surfaceIsOldTimer.stop();
210+ d.surfaceOldEnoughToBeResized = false;
188− PropertyAction { target: splashLoader; property: "active"; value: true }
211+ splashLoader.active = true;
189− PropertyAction { target: sessionContainer.surfaceContainer
212+ sessionContainer.surfaceContainer.visible = true;
190− property: "visible"; value: true }
213+ } }
191 UbuntuNumberAnimation { target: splashLoader; property: "opacity";
214 UbuntuNumberAnimation { target: splashLoader; property: "opacity";
192 from: 0.0; to: 1.0
215 from: 0.0; to: 1.0
193 duration: UbuntuAnimation.BriskDuration }
216 duration: UbuntuAnimation.BriskDuration }
@@ -198,14 +221,18 @@ FocusScope {
198 Transition {
221 Transition {
199 from: "surface"; to: "screenshot"
222 from: "surface"; to: "screenshot"
200 SequentialAnimation {
223 SequentialAnimation {
224+ ScriptAction { script: {
225+ surfaceIsOldTimer.stop();
226+ d.surfaceOldEnoughToBeResized = false;
201− PropertyAction { target: screenshotImage
227+ screenshotImage.visible = true;
202− property: "visible"; value: true }
228+ } }
203 UbuntuNumberAnimation { target: screenshotImage; property: "opacity";
229 UbuntuNumberAnimation { target: screenshotImage; property: "opacity";
204 from: 0.0; to: 1.0
230 from: 0.0; to: 1.0
205 duration: UbuntuAnimation.BriskDuration }
231 duration: UbuntuAnimation.BriskDuration }
232+ ScriptAction { script: {
206− PropertyAction { target: sessionContainer.surfaceContainer
233+ sessionContainer.surfaceContainer.visible = false;
207− property: "visible"; value: false }
208− ScriptAction { script: { if (sessionContainer.session) { sessionContainer.session.release(); } } }
234+ if (sessionContainer.session) { sessionContainer.session.release(); }
235+ } }
209 }
236 }
210 },
237 },
211 Transition {
238 Transition {
@@ -216,8 +243,11 @@ FocusScope {
216 UbuntuNumberAnimation { target: screenshotImage; property: "opacity";
243 UbuntuNumberAnimation { target: screenshotImage; property: "opacity";
217 from: 1.0; to: 0.0
244 from: 1.0; to: 0.0
218 duration: UbuntuAnimation.BriskDuration }
245 duration: UbuntuAnimation.BriskDuration }
246+ ScriptAction { script: {
219− PropertyAction { target: screenshotImage; property: "visible"; value: false }
247+ screenshotImage.visible = false;
220− PropertyAction { target: screenshotImage; property: "source"; value: "" }
248+ screenshotImage.source = "";
249+ surfaceIsOldTimer.start();
250+ } }
221 }
251 }
222 },
252 },
223 Transition {
253 Transition {
@@ -233,10 +263,12 @@ FocusScope {
233 },
263 },
234 Transition {
264 Transition {
235 from: "surface"; to: "void"
265 from: "surface"; to: "void"
236− SequentialAnimation {
266+ ScriptAction { script: {
237− PropertyAction { target: sessionContainer.surfaceContainer; property: "visible"; value: false }
267+ surfaceIsOldTimer.stop();
268+ d.surfaceOldEnoughToBeResized = false;
269+ sessionContainer.surfaceContainer.visible = false;
238− ScriptAction { script: { if (sessionContainer.session) { sessionContainer.session.release(); } } }
270+ if (sessionContainer.session) { sessionContainer.session.release(); }
239− }
271+ } }
240 },
272 },
241 Transition {
273 Transition {
242 from: "void"; to: "surface"
274 from: "void"; to: "surface"
@@ -246,6 +278,9 @@ FocusScope {
246 UbuntuNumberAnimation { target: sessionContainer.surfaceContainer; property: "opacity";
278 UbuntuNumberAnimation { target: sessionContainer.surfaceContainer; property: "opacity";
247 from: 0.0; to: 1.0
279 from: 0.0; to: 1.0
248 duration: UbuntuAnimation.BriskDuration }
280 duration: UbuntuAnimation.BriskDuration }
281+ ScriptAction { script: {
282+ surfaceIsOldTimer.start();
283+ } }
249 }
284 }
250 }
285 }
251 ]
286 ]
qml/Stages/DecoratedWindow.qml+1
@@ -42,6 +42,7 @@ FocusScope {
42
42
43 WindowDecoration {
43 WindowDecoration {
44 id: decoration
44 id: decoration
45+ objectName: application ? "appWindowDecoration_" + application.appId : "appWindowDecoration_null"
45 anchors { left: parent.left; top: parent.top; right: parent.right }
46 anchors { left: parent.left; top: parent.top; right: parent.right }
46 height: units.gu(3)
47 height: units.gu(3)
47 title: model.name
48 title: model.name
qml/Stages/DesktopStage.qml+43−14
@@ -20,16 +20,36 @@ import QtQuick 2.3
20import Ubuntu.Components 1.1
20import Ubuntu.Components 1.1
21import Unity.Application 0.1
21import Unity.Application 0.1
22import "../Components/PanelState"
22import "../Components/PanelState"
23−import Utils 0.1
24
23
25−FocusScope {
24+Rectangle {
26 id: root
25 id: root
27
26
28 anchors.fill: parent
27 anchors.fill: parent
29
28
30− property alias background: wallpaper.source
29+ // Controls to be set from outside
30+ property int dragAreaWidth // just to comply with the interface shared between stages
31+ property real maximizedAppTopMargin
32+ property bool interactive
33+ property bool spreadEnabled // just to comply with the interface shared between stages
34+ property real inverseProgress: 0 // just to comply with the interface shared between stages
35+ property int shellOrientationAngle: 0
36+ property int shellOrientation
37+ property int shellPrimaryOrientation
38+ property int nativeOrientation
39+ property bool beingResized: false
40+
41+ // functions to be called from outside
42+ function updateFocusedAppOrientation() { /* TODO */ }
43+ function updateFocusedAppOrientationAnimated() { /* TODO */}
44+
45+ // To be read from outside
46+ readonly property var mainApp: ApplicationManager.focusedApplicationId
47+ ? ApplicationManager.findApplication(ApplicationManager.focusedApplicationId)
48+ : null
49+ property int mainAppWindowOrientationAngle: 0
50+ readonly property bool orientationChangesEnabled: false
31
51
32− property var windowStateStorage: WindowStateStorage
52+ property alias background: wallpaper.source
33
53
34 CrossFadeImage {
54 CrossFadeImage {
35 id: wallpaper
55 id: wallpaper
@@ -58,7 +78,16 @@ FocusScope {
58 id: priv
78 id: priv
59
79
60 readonly property string focusedAppId: ApplicationManager.focusedApplicationId
80 readonly property string focusedAppId: ApplicationManager.focusedApplicationId
61− readonly property var focusedAppDelegate: focusedAppId ? appRepeater.itemAt(indexOf(focusedAppId)) : null
81+ readonly property var focusedAppDelegate: {
82+ var index = indexOf(focusedAppId);
83+ return index >= 0 && index < appRepeater.count ? appRepeater.itemAt(index) : null
84+ }
85+
86+ onFocusedAppDelegateChanged: {
87+ if (focusedAppDelegate) {
88+ focusedAppDelegate.focus = true;
89+ }
90+ }
62
91
63 function indexOf(appId) {
92 function indexOf(appId) {
64 for (var i = 0; i < ApplicationManager.count; i++) {
93 for (var i = 0; i < ApplicationManager.count; i++) {
@@ -89,13 +118,19 @@ FocusScope {
89 id: appRepeater
118 id: appRepeater
90 model: ApplicationManager
119 model: ApplicationManager
91
120
92− delegate: Item {
121+ delegate: FocusScope {
93 id: appDelegate
122 id: appDelegate
94 z: ApplicationManager.count - index
123 z: ApplicationManager.count - index
95 y: units.gu(3)
124 y: units.gu(3)
96 width: units.gu(60)
125 width: units.gu(60)
97 height: units.gu(50)
126 height: units.gu(50)
98
127
128+ onFocusChanged: {
129+ if (focus) {
130+ ApplicationManager.requestFocusApplication(model.appId);
131+ }
132+ }
133+
99 readonly property int minWidth: units.gu(10)
134 readonly property int minWidth: units.gu(10)
100 readonly property int minHeight: units.gu(10)
135 readonly property int minHeight: units.gu(10)
101
136
@@ -119,14 +154,13 @@ FocusScope {
119 ]
154 ]
120
155
121 WindowMoveResizeArea {
156 WindowMoveResizeArea {
122− windowStateStorage: root.windowStateStorage
123 target: appDelegate
157 target: appDelegate
124 minWidth: appDelegate.minWidth
158 minWidth: appDelegate.minWidth
125 minHeight: appDelegate.minHeight
159 minHeight: appDelegate.minHeight
126 resizeHandleWidth: units.gu(0.5)
160 resizeHandleWidth: units.gu(0.5)
127 windowId: model.appId // FIXME: Change this to point to windowId once we have such a thing
161 windowId: model.appId // FIXME: Change this to point to windowId once we have such a thing
128
162
129− onPressed: decoratedWindow.focus = true;
163+ onPressed: appDelegate.focus = true;
130 }
164 }
131
165
132 DecoratedWindow {
166 DecoratedWindow {
@@ -135,12 +169,7 @@ FocusScope {
135 anchors.fill: parent
169 anchors.fill: parent
136 application: ApplicationManager.get(index)
170 application: ApplicationManager.get(index)
137 active: ApplicationManager.focusedApplicationId === model.appId
171 active: ApplicationManager.focusedApplicationId === model.appId
138−
139− onFocusChanged: {
140− if (focus) {
172+ focus: true
141− ApplicationManager.requestFocusApplication(model.appId);
142− }
143− }
144
173
145 onClose: ApplicationManager.stopApplication(model.appId)
174 onClose: ApplicationManager.stopApplication(model.appId)
146 onMaximize: appDelegate.state = (appDelegate.state == "maximized" ? "normal" : "maximized")
175 onMaximize: appDelegate.state = (appDelegate.state == "maximized" ? "normal" : "maximized")
qml/Stages/OrientationChangeAnimation.qmlnew file+241
@@ -0,0 +1,241 @@
1+/*
2+ * Copyright 2015 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.3
18+
19+QtObject {
20+ id: root
21+
22+ // to be set from outside
23+ property Item spreadDelegate
24+ property Item background
25+ property Item window
26+ property Item screenshot
27+
28+ function start() {
29+ if (window.orientationAngle === 0) {
30+ if (spreadDelegate.shellOrientationAngle === 90) {
31+ chosenAnimation = simple90Animation;
32+ } else if (spreadDelegate.shellOrientationAngle === 180) {
33+ chosenAnimation = halfLoopAnimation;
34+ } else if (spreadDelegate.shellOrientationAngle === 270) {
35+ chosenAnimation = moving90Animation;
36+ } else {
37+ chosenAnimation = null;
38+ }
39+ } else if (window.orientationAngle === 90) {
40+ if (spreadDelegate.shellOrientationAngle === 0) {
41+ chosenAnimation = simple90Animation;
42+ } else if (spreadDelegate.shellOrientationAngle === 180) {
43+ chosenAnimation = moving90Animation;
44+ } else if (spreadDelegate.shellOrientationAngle === 270) {
45+ chosenAnimation = halfLoopAnimation;
46+ } else {
47+ chosenAnimation = null;
48+ }
49+ } else if (window.orientationAngle === 180) {
50+ if (spreadDelegate.shellOrientationAngle === 0) {
51+ chosenAnimation = halfLoopAnimation;
52+ } else if (spreadDelegate.shellOrientationAngle === 90) {
53+ chosenAnimation = moving90Animation;
54+ } else if (spreadDelegate.shellOrientationAngle === 270) {
55+ chosenAnimation = simple90Animation;
56+ } else {
57+ chosenAnimation = null;
58+ }
59+ } else if (window.orientationAngle === 270) {
60+ if (spreadDelegate.shellOrientationAngle === 0) {
61+ chosenAnimation = moving90Animation;
62+ } else if (spreadDelegate.shellOrientationAngle === 90) {
63+ chosenAnimation = halfLoopAnimation;
64+ } else if (spreadDelegate.shellOrientationAngle === 180) {
65+ chosenAnimation = simple90Animation;
66+ } else {
67+ chosenAnimation = null;
68+ }
69+ }
70+
71+ if (chosenAnimation)
72+ chosenAnimation.start();
73+ }
74+
75+ // to be read from outside
76+ property bool running: chosenAnimation ? chosenAnimation.running : false
77+
78+ property int duration: 450
79+ property int easingType: Easing.InOutCubic
80+
81+ property int shortestDimension: spreadDelegate.width < spreadDelegate.height
82+ ? spreadDelegate.width : spreadDelegate.height
83+ property int longestDimension: spreadDelegate.width > spreadDelegate.height
84+ ? spreadDelegate.width : spreadDelegate.height
85+ property string longestAxis: spreadDelegate.width > spreadDelegate.height ? "x" : "y"
86+
87+ property QtObject chosenAnimation
88+
89+ function setup90Animation() {
90+ background.visible = true;
91+
92+ screenshot.width = window.width;
93+ screenshot.height = window.height;
94+ screenshot.window.anchors.topMargin = window.window.anchors.topMargin;
95+ screenshot.take();
96+ screenshot.transformOriginX = root.shortestDimension / 2;
97+ screenshot.transformOriginY = root.shortestDimension / 2;
98+ screenshot.visible = true;
99+
100+ window.rotation = 0;
101+ window.width = spreadDelegate.width;
102+ window.height = spreadDelegate.height;
103+ window.transformOriginX = root.shortestDimension / 2;
104+ window.transformOriginY = root.shortestDimension / 2;
105+ }
106+
107+ function tearDown90Animation() {
108+ window.orientationAngle = spreadDelegate.shellOrientationAngle;
109+ screenshot.discard();
110+ screenshot.visible = false;
111+ background.visible = false;
112+ }
113+
114+ property QtObject simple90Animation: SequentialAnimation {
115+ id: simple90Animation
116+
117+ ScriptAction { script: setup90Animation() }
118+ ParallelAnimation {
119+ RotationAnimation {
120+ target: root.window
121+ duration: root.duration
122+ easing.type: root.easingType
123+ from: window.orientationAngle - spreadDelegate.shellOrientationAngle
124+ to: 0
125+ property: "transformRotationAngle"
126+ }
127+ RotationAnimation {
128+ target: root.screenshot
129+ duration: root.duration
130+ easing.type: root.easingType
131+ from: window.orientationAngle - spreadDelegate.shellOrientationAngle
132+ to: 0
133+ property: "transformRotationAngle"
134+ }
135+ NumberAnimation {
136+ target: root.screenshot
137+ duration: root.duration
138+ easing.type: root.easingType
139+ property: "opacity"
140+ from: 1.0
141+ to: 0.0
142+ }
143+ NumberAnimation {
144+ target: root.window
145+ duration: root.duration
146+ easing.type: root.easingType
147+ property: "opacity"
148+ from: 0.0
149+ to: 1.0
150+ }
151+ }
152+ ScriptAction { script: tearDown90Animation() }
153+ }
154+
155+ property QtObject moving90Animation: SequentialAnimation {
156+ id: moving90Animation
157+
158+ ScriptAction { script: setup90Animation() }
159+ ParallelAnimation {
160+ RotationAnimation {
161+ target: root.window
162+ duration: root.duration
163+ easing.type: root.easingType
164+ direction: RotationAnimation.Shortest
165+ from: window.orientationAngle - spreadDelegate.shellOrientationAngle
166+ to: 0
167+ property: "transformRotationAngle"
168+ }
169+ RotationAnimation {
170+ target: root.screenshot
171+ duration: root.duration
172+ easing.type: root.easingType
173+ direction: RotationAnimation.Shortest
174+ from: window.orientationAngle - spreadDelegate.shellOrientationAngle
175+ to: 0
176+ property: "transformRotationAngle"
177+ }
178+ NumberAnimation {
179+ target: root.screenshot
180+ duration: root.duration
181+ easing.type: root.easingType
182+ property: "opacity"
183+ from: 1.0
184+ to: 0.0
185+ }
186+ NumberAnimation {
187+ target: root.window
188+ duration: root.duration
189+ easing.type: root.easingType
190+ property: "opacity"
191+ from: 0.0
192+ to: 1.0
193+ }
194+ NumberAnimation {
195+ target: root.window
196+ duration: root.duration
197+ easing.type: root.easingType
198+ property: root.longestAxis
199+ from: root.longestDimension - root.shortestDimension
200+ to: 0
201+ }
202+ NumberAnimation {
203+ target: root.screenshot
204+ duration: root.duration
205+ easing.type: root.easingType
206+ property: root.longestAxis
207+ from: root.longestDimension - root.shortestDimension
208+ to: 0
209+ }
210+ }
211+ ScriptAction { script: tearDown90Animation() }
212+ }
213+
214+ property QtObject halfLoopAnimation: SequentialAnimation {
215+ id: halfLoopAnimation
216+
217+ ScriptAction { script: {
218+ background.visible = true;
219+
220+ window.rotation = 0;
221+ window.width = spreadDelegate.width;
222+ window.height = spreadDelegate.height;
223+ window.transformOriginX = window.width / 2
224+ window.transformOriginY = window.height / 2
225+ } }
226+ ParallelAnimation {
227+ RotationAnimation {
228+ target: root.window
229+ duration: root.duration
230+ easing.type: root.easingType
231+ from: window.orientationAngle - spreadDelegate.shellOrientationAngle
232+ to: 0
233+ property: "transformRotationAngle"
234+ }
235+ }
236+ ScriptAction { script: {
237+ window.orientationAngle = spreadDelegate.shellOrientationAngle;
238+ background.visible = false;
239+ } }
240+ }
241+}
qml/Stages/PhoneStage.qml+140−41
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2014 Canonical, Ltd.
2+ * Copyright (C) 2014-2015 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
@@ -31,12 +31,64 @@ Rectangle {
31 property bool interactive
31 property bool interactive
32 property bool spreadEnabled: true // If false, animations and right edge will be disabled
32 property bool spreadEnabled: true // If false, animations and right edge will be disabled
33 property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.
33 property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.
34− property int orientation: Qt.PortraitOrientation
35 property QtObject applicationManager: ApplicationManager
34 property QtObject applicationManager: ApplicationManager
36 property bool focusFirstApp: true // If false, focused app will appear on right edge like other apps
35 property bool focusFirstApp: true // If false, focused app will appear on right edge like other apps
37 property bool altTabEnabled: true
36 property bool altTabEnabled: true
38 property real startScale: 1.1
37 property real startScale: 1.1
39 property real endScale: 0.7
38 property real endScale: 0.7
39+ property int shellOrientationAngle: 0
40+ property int shellOrientation
41+ property int shellPrimaryOrientation
42+ property int nativeOrientation
43+ property real nativeWidth
44+ property real nativeHeight
45+ property bool beingResized: false
46+ onBeingResizedChanged: {
47+ if (beingResized) {
48+ // Brace yourselves for impact!
49+ spreadView.selectedIndex = -1;
50+ spreadView.phase = 0;
51+ spreadView.contentX = -spreadView.shift;
52+ }
53+ }
54+ function updateFocusedAppOrientation() {
55+ if (spreadRepeater.count > 0) {
56+ spreadRepeater.itemAt(0).matchShellOrientation();
57+ }
58+
59+ for (var i = 1; i < spreadRepeater.count; ++i) {
60+
61+ var spreadDelegate = spreadRepeater.itemAt(i);
62+
63+ var delta = spreadDelegate.appWindowOrientationAngle - root.shellOrientationAngle;
64+ if (delta < 0) { delta += 360; }
65+ delta = delta % 360;
66+
67+ var supportedOrientations = spreadDelegate.application.supportedOrientations;
68+ if (supportedOrientations === Qt.PrimaryOrientation) {
69+ supportedOrientations = spreadDelegate.shellPrimaryOrientation;
70+ }
71+
72+ if (delta === 180 && (supportedOrientations & spreadDelegate.shellOrientation)) {
73+ spreadDelegate.matchShellOrientation();
74+ }
75+ }
76+ }
77+ function updateFocusedAppOrientationAnimated() {
78+ if (spreadRepeater.count > 0) {
79+ spreadRepeater.itemAt(0).animateToShellOrientation();
80+ }
81+ }
82+
83+ // To be read from outside
84+ readonly property var mainApp: applicationManager.focusedApplicationId
85+ ? applicationManager.findApplication(applicationManager.focusedApplicationId)
86+ : null
87+ property int mainAppWindowOrientationAngle: 0
88+ readonly property bool orientationChangesEnabled: priv.focusedAppOrientationChangesEnabled
89+ && !priv.focusedAppDelegateIsDislocated
90+ && !(priv.focusedAppDelegate && priv.focusedAppDelegate.xBehavior.running)
91+ && spreadView.phase === 0
40
92
41 // How far left the stage has been dragged
93 // How far left the stage has been dragged
42 readonly property real dragProgress: spreadRepeater.count > 0 ? -spreadRepeater.itemAt(0).xTranslate : 0
94 readonly property real dragProgress: spreadRepeater.count > 0 ? -spreadRepeater.itemAt(0).xTranslate : 0
@@ -54,12 +106,6 @@ Rectangle {
54 spreadView.snapTo(priv.indexOf(appId));
106 spreadView.snapTo(priv.indexOf(appId));
55 }
107 }
56
108
57− onWidthChanged: {
58− spreadView.selectedIndex = -1;
59− spreadView.phase = 0;
60− spreadView.contentX = -spreadView.shift;
61− }
62−
63 onInverseProgressChanged: {
109 onInverseProgressChanged: {
64 // This can't be a simple binding because that would be triggered after this handler
110 // This can't be a simple binding because that would be triggered after this handler
65 // while we need it active before doing the anition left/right
111 // while we need it active before doing the anition left/right
@@ -73,6 +119,20 @@ Rectangle {
73 priv.oldInverseProgress = inverseProgress;
119 priv.oldInverseProgress = inverseProgress;
74 }
120 }
75
121
122+ // <FIXME-contentX> See rationale in the next comment with this tag
123+ onWidthChanged: {
124+ if (!root.beingResized) {
125+ // we're being resized without a warning (ie, the corresponding property wasn't set
126+ root.beingResized = true;
127+ beingResizedTimer.start();
128+ }
129+ }
130+ Timer {
131+ id: beingResizedTimer
132+ interval: 100
133+ onTriggered: { root.beingResized = false; }
134+ }
135+
76 Connections {
136 Connections {
77 target: applicationManager
137 target: applicationManager
78
138
@@ -115,31 +175,44 @@ Rectangle {
115 QtObject {
175 QtObject {
116 id: priv
176 id: priv
117
177
178+ property string focusedAppId: root.applicationManager.focusedApplicationId
179+ property bool focusedAppOrientationChangesEnabled: false
118 readonly property int firstSpreadIndex: root.focusFirstApp ? 1 : 0
180 readonly property int firstSpreadIndex: root.focusFirstApp ? 1 : 0
119− property string focusedAppId: applicationManager.focusedApplicationId
120− property var focusedApplication: applicationManager.findApplication(focusedAppId)
121− property var focusedAppDelegate: null
181+ readonly property var focusedAppDelegate: {
182+ var index = indexOf(focusedAppId);
183+ return index >= 0 && index < spreadRepeater.count ? spreadRepeater.itemAt(index) : null
184+ }
122
185
123 property real oldInverseProgress: 0
186 property real oldInverseProgress: 0
124 property bool animateX: false
187 property bool animateX: false
125
188
126− onFocusedAppIdChanged: focusedAppDelegate = spreadRepeater.itemAt(0);
127−
128 onFocusedAppDelegateChanged: {
189 onFocusedAppDelegateChanged: {
129 if (focusedAppDelegate) {
190 if (focusedAppDelegate) {
130 focusedAppDelegate.focus = true;
191 focusedAppDelegate.focus = true;
131 }
192 }
132 }
193 }
133
194
195+ property bool focusedAppDelegateIsDislocated: focusedAppDelegate && focusedAppDelegate.x !== 0
196+
134 function indexOf(appId) {
197 function indexOf(appId) {
135− for (var i = 0; i < applicationManager.count; i++) {
198+ for (var i = 0; i < root.applicationManager.count; i++) {
136− if (applicationManager.get(i).appId == appId) {
199+ if (root.applicationManager.get(i).appId == appId) {
137 return i;
200 return i;
138 }
201 }
139 }
202 }
140 return -1;
203 return -1;
141 }
204 }
142
205
206+ // Is more stable than "spreadView.shiftedContentX === 0" as it filters out noise caused by
207+ // Flickable.contentX changing due to resizes.
208+ property bool fullyShowingFocusedApp: true
209+ }
210+ Timer {
211+ id: fullyShowingFocusedAppUpdateTimer
212+ interval: 100
213+ onTriggered: {
214+ priv.fullyShowingFocusedApp = spreadView.shiftedContentX === 0;
215+ }
143 }
216 }
144
217
145 Flickable {
218 Flickable {
@@ -187,9 +260,25 @@ Rectangle {
187 property int draggedDelegateCount: 0
260 property int draggedDelegateCount: 0
188 property int closingIndex: -1
261 property int closingIndex: -1
189
262
190− property bool focusChanging: false
263+ // <FIXME-contentX> Workaround Flickable's behavior of bringing contentX back between valid boundaries
264+ // when resized. The proper way to fix this is refactoring PhoneStage so that it doesn't
265+ // rely on having Flickable.contentX keeping an out-of-bounds value when it's set programatically
266+ // (as opposed to having contentX reaching an out-of-bounds value through dragging, which will trigger
267+ // the Flickable.boundsBehavior upon release).
268+ onContentXChanged: { forceItToRemainStillIfBeingResized(); }
269+ onShiftChanged: { forceItToRemainStillIfBeingResized(); }
270+ function forceItToRemainStillIfBeingResized() {
271+ if (root.beingResized && contentX != -spreadView.shift) {
272+ contentX = -spreadView.shift;
273+ }
274+ }
191
275
192 onShiftedContentXChanged: {
276 onShiftedContentXChanged: {
277+ if (root.beingResized) {
278+ // Flickabe.contentX wiggles during resizes. Don't react to it.
279+ return;
280+ }
281+
193 switch (phase) {
282 switch (phase) {
194 case 0:
283 case 0:
195 if (shiftedContentX > width * positionMarker2) {
284 if (shiftedContentX > width * positionMarker2) {
@@ -204,6 +293,7 @@ Rectangle {
204 }
293 }
205 break;
294 break;
206 }
295 }
296+ fullyShowingFocusedAppUpdateTimer.restart();
207 }
297 }
208
298
209 function snap() {
299 function snap() {
@@ -228,7 +318,7 @@ Rectangle {
228 snapAnimation.start();
318 snapAnimation.start();
229 return;
319 return;
230 }
320 }
231− if (applicationManager.count <= index) {
321+ if (root.applicationManager.count <= index) {
232 // In case we're trying to snap to some non existing app, lets snap back to the first one
322 // In case we're trying to snap to some non existing app, lets snap back to the first one
233 index = 0;
323 index = 0;
234 }
324 }
@@ -265,7 +355,7 @@ Rectangle {
265 ScriptAction {
355 ScriptAction {
266 script: {
356 script: {
267 if (spreadView.selectedIndex >= 0) {
357 if (spreadView.selectedIndex >= 0) {
268− applicationManager.focusApplication(applicationManager.get(spreadView.selectedIndex).appId);
358+ root.applicationManager.focusApplication(root.applicationManager.get(spreadView.selectedIndex).appId);
269
359
270 spreadView.selectedIndex = -1;
360 spreadView.selectedIndex = -1;
271 spreadView.phase = 0;
361 spreadView.phase = 0;
@@ -280,7 +370,7 @@ Rectangle {
280 // This width controls how much the spread can be flicked left/right. It's composed of:
370 // This width controls how much the spread can be flicked left/right. It's composed of:
281 // tileDistance * app count (with a minimum of 3 apps, in order to also allow moving 1 and 2 apps a bit)
371 // tileDistance * app count (with a minimum of 3 apps, in order to also allow moving 1 and 2 apps a bit)
282 // + some constant value (still scales with the screen width) which looks good and somewhat fills the screen
372 // + some constant value (still scales with the screen width) which looks good and somewhat fills the screen
283− width: Math.max(3, applicationManager.count) * spreadView.tileDistance + (spreadView.width - spreadView.tileDistance) * 1.5
373+ width: Math.max(3, root.applicationManager.count) * spreadView.tileDistance + (spreadView.width - spreadView.tileDistance) * 1.5
284 height: parent.height
374 height: parent.height
285 Behavior on width {
375 Behavior on width {
286 enabled: spreadView.closingIndex >= 0
376 enabled: spreadView.closingIndex >= 0
@@ -303,7 +393,7 @@ Rectangle {
303 Repeater {
393 Repeater {
304 id: spreadRepeater
394 id: spreadRepeater
305 objectName: "spreadRepeater"
395 objectName: "spreadRepeater"
306− model: applicationManager
396+ model: root.applicationManager
307 delegate: TransformedSpreadDelegate {
397 delegate: TransformedSpreadDelegate {
308 id: appDelegate
398 id: appDelegate
309 objectName: "appDelegate" + index
399 objectName: "appDelegate" + index
@@ -318,11 +408,10 @@ Rectangle {
318 selected: spreadView.selectedIndex == index
408 selected: spreadView.selectedIndex == index
319 otherSelected: spreadView.selectedIndex >= 0 && !selected
409 otherSelected: spreadView.selectedIndex >= 0 && !selected
320 interactive: !spreadView.interactive && spreadView.phase === 0
410 interactive: !spreadView.interactive && spreadView.phase === 0
321− && spreadView.shiftedContentX === 0 && root.interactive && isFocused
411+ && priv.fullyShowingFocusedApp && root.interactive && isFocused
322 swipeToCloseEnabled: spreadView.interactive && root.interactive && !snapAnimation.running
412 swipeToCloseEnabled: spreadView.interactive && root.interactive && !snapAnimation.running
323 maximizedAppTopMargin: root.maximizedAppTopMargin
413 maximizedAppTopMargin: root.maximizedAppTopMargin
324− dropShadow: spreadView.active ||
414+ dropShadow: spreadView.active || priv.focusedAppDelegateIsDislocated
325− (priv.focusedAppDelegate && priv.focusedAppDelegate.x !== 0)
326 focusFirstApp: root.focusFirstApp
415 focusFirstApp: root.focusFirstApp
327
416
328 readonly property bool isDash: model.appId == "unity8-dash"
417 readonly property bool isDash: model.appId == "unity8-dash"
@@ -345,7 +434,7 @@ Rectangle {
345 return spreadView.width + spreadIndex * spreadView.tileDistance;
434 return spreadView.width + spreadIndex * spreadView.tileDistance;
346 }
435 }
347
436
348− application: applicationManager.get(index)
437+ application: root.applicationManager.get(index)
349 closeable: !isDash
438 closeable: !isDash
350
439
351 property real behavioredIndex: index
440 property real behavioredIndex: index
@@ -361,18 +450,16 @@ Rectangle {
361 }
450 }
362 }
451 }
363
452
453+ property var xBehavior: xBehavior
364 Behavior on x {
454 Behavior on x {
455+ id: xBehavior
365 enabled: root.spreadEnabled &&
456 enabled: root.spreadEnabled &&
366 !spreadView.active &&
457 !spreadView.active &&
367 !snapAnimation.running &&
458 !snapAnimation.running &&
368− priv.animateX
459+ priv.animateX &&
460+ !root.beingResized
369 UbuntuNumberAnimation {
461 UbuntuNumberAnimation {
370 duration: UbuntuAnimation.BriskDuration
462 duration: UbuntuAnimation.BriskDuration
371− onRunningChanged: {
372− if (!running && root.inverseProgress == 0) {
373− spreadView.focusChanging = false;
374− }
375− }
376 }
463 }
377 }
464 }
378
465
@@ -412,22 +499,21 @@ Rectangle {
412 }
499 }
413
500
414 // Hiding tiles when their progress is negative or reached the maximum
501 // Hiding tiles when their progress is negative or reached the maximum
415− visible: (progress >= 0 && progress < 1.7) ||
502+ visible: (progress >= 0 && progress < 1.7)
416− (isDash && priv.focusedAppDelegate.x !== 0)
503+ || (isDash && priv.focusedAppDelegateIsDislocated)
417
504
418− Binding {
505+
419− target: appDelegate
506+ shellOrientationAngle: root.shellOrientationAngle
420− property: "orientation"
507+ shellOrientation: root.shellOrientation
421− when: appDelegate.interactive
508+ shellPrimaryOrientation: root.shellPrimaryOrientation
422− value: root.orientation
509+ nativeOrientation: root.nativeOrientation
423− }
424
510
425 onClicked: {
511 onClicked: {
426 if (root.altTabEnabled && spreadView.phase == 2) {
512 if (root.altTabEnabled && spreadView.phase == 2) {
427− if (applicationManager.focusedApplicationId == applicationManager.get(index).appId) {
513+ if (root.applicationManager.focusedApplicationId == root.applicationManager.get(index).appId) {
428 spreadView.snapTo(index);
514 spreadView.snapTo(index);
429 } else {
515 } else {
430− applicationManager.requestFocusApplication(applicationManager.get(index).appId);
516+ root.applicationManager.requestFocusApplication(root.applicationManager.get(index).appId);
431 }
517 }
432 }
518 }
433 }
519 }
@@ -442,7 +528,20 @@ Rectangle {
442
528
443 onClosed: {
529 onClosed: {
444 spreadView.closingIndex = index;
530 spreadView.closingIndex = index;
445− applicationManager.stopApplication(applicationManager.get(index).appId);
531+ root.applicationManager.stopApplication(root.applicationManager.get(index).appId);
532+ }
533+
534+ Binding {
535+ target: root
536+ when: index == 0
537+ property: "mainAppWindowOrientationAngle"
538+ value: appWindowOrientationAngle
539+ }
540+ Binding {
541+ target: priv
542+ when: index == 0
543+ property: "focusedAppOrientationChangesEnabled"
544+ value: orientationChangesEnabled
446 }
545 }
447 }
546 }
448 }
547 }
qml/Stages/SessionContainer.qml+2−8
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright 2014 Canonical Ltd.
2+ * Copyright 2014-2015 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 Lesser General Public License as published by
5 * it under the terms of the GNU Lesser General Public License as published by
@@ -24,14 +24,13 @@ FocusScope {
24 readonly property var childSessions: session ? session.childSessions : null
24 readonly property var childSessions: session ? session.childSessions : null
25 readonly property alias surface: _surfaceContainer.surface
25 readonly property alias surface: _surfaceContainer.surface
26 property alias interactive: _surfaceContainer.interactive
26 property alias interactive: _surfaceContainer.interactive
27− property int orientation
27+ property alias surfaceOrientationAngle: _surfaceContainer.surfaceOrientationAngle
28
28
29 readonly property alias surfaceContainer: _surfaceContainer
29 readonly property alias surfaceContainer: _surfaceContainer
30 SurfaceContainer {
30 SurfaceContainer {
31 id: _surfaceContainer
31 id: _surfaceContainer
32 anchors.fill: parent
32 anchors.fill: parent
33 surface: session ? session.surface : null
33 surface: session ? session.surface : null
34− orientation: root.orientation
35 }
34 }
36
35
37 Repeater {
36 Repeater {
@@ -72,11 +71,6 @@ FocusScope {
72 target: item; when: item
71 target: item; when: item
73 property: "height"; value: root.height
72 property: "height"; value: root.height
74 }
73 }
75−
76− Binding {
77− target: item; when: item
78− property: "orientation"; value: root.orientation
79− }
80 }
74 }
81 }
75 }
82
76
qml/Stages/ShimStage.qmlnew file+44
@@ -0,0 +1,44 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.3
18+import Ubuntu.Components 0.1
19+
20+Rectangle {
21+ id: shimStage
22+
23+ anchors.fill: parent
24+ color: UbuntuColors.lightAubergine
25+
26+ Text {
27+ id: greeterModeText
28+
29+ anchors.horizontalCenter: parent.horizontalCenter
30+ anchors.top: parent.top
31+ anchors.topMargin: units.gu(10)
32+ font.bold: true
33+ horizontalAlignment: Text.AlignHCenter
34+ text: "Shell is in \"greeter\" mode"
35+ }
36+
37+ Text {
38+ anchors.centerIn: parent
39+ color: UbuntuColors.orange
40+ font.pointSize: units.gu(8)
41+ horizontalAlignment: Text.AlignHCenter
42+ text: "Shim \nStage"
43+ }
44+}
qml/Stages/SpreadDelegate.qml+261−20
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright 2014 Canonical Ltd.
2+ * Copyright 2014-2015 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 Lesser General Public License as published by
5 * it under the terms of the GNU Lesser General Public License as published by
@@ -18,6 +18,7 @@
18 */
18 */
19
19
20import QtQuick 2.0
20import QtQuick 2.0
21+import QtQuick.Window 2.0
21import Ubuntu.Components 1.1
22import Ubuntu.Components 1.1
22import "../Components"
23import "../Components"
23
24
@@ -28,6 +29,9 @@ FocusScope {
28 readonly property bool dragged: dragArea.moving
29 readonly property bool dragged: dragArea.moving
29 signal clicked()
30 signal clicked()
30 signal closed()
31 signal closed()
32+ readonly property alias appWindowOrientationAngle: appWindowWithShadow.orientationAngle
33+ readonly property alias appWindowRotation: appWindowWithShadow.rotation
34+ readonly property alias orientationChangesEnabled: appWindow.orientationChangesEnabled
31
35
32 // to be set from outside
36 // to be set from outside
33 property bool interactive: true
37 property bool interactive: true
@@ -36,10 +40,54 @@ FocusScope {
36 property alias swipeToCloseEnabled: dragArea.enabled
40 property alias swipeToCloseEnabled: dragArea.enabled
37 property bool closeable
41 property bool closeable
38 property alias application: appWindow.application
42 property alias application: appWindow.application
39− property int orientation
43+ property int shellOrientationAngle
44+ property int shellOrientation
45+ property int shellPrimaryOrientation
46+ property int nativeOrientation
47+
48+ function matchShellOrientation() {
49+ if (!root.application)
50+ return;
51+ appWindowWithShadow.orientationAngle = root.shellOrientationAngle;
52+ }
53+
54+ function animateToShellOrientation() {
55+ if (!root.application)
56+ return;
57+
58+ if (root.application.rotatesWindowContents) {
59+ appWindowWithShadow.orientationAngle = root.shellOrientationAngle;
60+ } else {
61+ orientationChangeAnimation.start();
62+ }
63+ }
64+
65+ OrientationChangeAnimation {
66+ id: orientationChangeAnimation
67+ objectName: "orientationChangeAnimation"
68+ spreadDelegate: root
69+ background: background
70+ window: appWindowWithShadow
71+ screenshot: appWindowScreenshotWithShadow
72+ }
73+
74+ QtObject {
75+ id: priv
76+ property bool startingUp: true
77+ }
78+
79+ Component.onCompleted: { finishStartUpTimer.start(); }
80+ Timer { id: finishStartUpTimer; interval: 400; onTriggered: priv.startingUp = false }
81+
82+ Rectangle {
83+ id: background
84+ color: "black"
85+ anchors.fill: parent
86+ visible: false
87+ }
40
88
41 Item {
89 Item {
42− objectName: "appWindowWithShadow"
90+ objectName: "displacedAppWindowWithShadow"
43
91
44 readonly property real limit: root.height / 4
92 readonly property real limit: root.height / 4
45
93
@@ -52,27 +100,220 @@ FocusScope {
52 return k * (1 - Math.pow((k - 1) / k, distance))
100 return k * (1 - Math.pow((k - 1) / k, distance))
53 }
101 }
54
102
55− BorderImage {
103+ Item {
56− anchors {
104+ id: appWindowWithShadow
105+ objectName: "appWindowWithShadow"
106+
107+ property int orientationAngle
108+
109+ property real transformRotationAngle: 0
110+ property real transformOriginX
111+ property real transformOriginY
112+
57− fill: appWindow
113+ property var window: appWindow
58− margins: -units.gu(2)
114+
115+ transform: Rotation {
116+ origin.x: appWindowWithShadow.transformOriginX
117+ origin.y: appWindowWithShadow.transformOriginY
118+ axis { x: 0; y: 0; z: 1 }
119+ angle: appWindowWithShadow.transformRotationAngle
120+ }
121+
122+ state: {
123+ if (priv.startingUp) {
124+ return "startingUp";
125+ } else if (root.application && root.application.rotatesWindowContents) {
126+ return "counterRotate";
127+ } else if (orientationChangeAnimation.running) {
128+ return "animatingRotation";
129+ } else {
130+ return "keepSceneRotation";
131+ }
59 }
132 }
60− source: "graphics/dropshadow2gu.sci"
61− opacity: root.dropShadow ? .3 : 0
62− Behavior on opacity { UbuntuNumberAnimation {} }
63− }
64
133
65− ApplicationWindow {
134+ // Ensures the given angle is in the form (0,90,180,270)
66− id: appWindow
135+ function normalizeAngle(angle) {
67− objectName: application ? "appWindow_" + application.appId : "appWindow_null"
136+ while (angle < 0) {
68− focus: true
137+ angle += 360;
69− anchors {
138+ }
70− fill: parent
139+ return angle % 360;
71− topMargin: appWindow.fullscreen ? 0 : maximizedAppTopMargin
72 }
140 }
73
141
142+ states: [
143+ // Sets the initial orientationAngle of the window, when it first slides into view
144+ // (with the splash screen likely being displayed). At that point we just try to
145+ // match shell's current orientation. We need a bit of time in this state as the
146+ // information we need to decide orientationAngle may take a few cycles to
147+ // be set.
148+ State {
149+ name: "startingUp"
150+ PropertyChanges {
151+ target: appWindowWithShadow
152+ restoreEntryValues: false
153+ orientationAngle: {
154+ if (!root.application || root.application.rotatesWindowContents) {
155+ return 0;
156+ }
157+ var supportedOrientations = root.application.supportedOrientations;
158+
159+ if (supportedOrientations === Qt.PrimaryOrientation) {
160+ supportedOrientations = root.shellPrimaryOrientation;
161+ }
162+
163+ // If it doesn't support shell's current orientation
164+ // then simply pick some arbitraty one that it does support
165+ var chosenOrientation = 0;
166+ if (supportedOrientations & root.shellOrientation) {
167+ chosenOrientation = root.shellOrientation;
168+ } else if (supportedOrientations & Qt.PortraitOrientation) {
169+ chosenOrientation = Qt.PortraitOrientation;
170+ } else if (supportedOrientations & Qt.LandscapeOrientation) {
171+ chosenOrientation = Qt.LandscapeOrientation;
172+ } else if (supportedOrientations & Qt.InvertedPortraitOrientation) {
173+ chosenOrientation = Qt.InvertedPortraitOrientation;
174+ } else if (supportedOrientations & Qt.InvertedLandscapeOrientation) {
175+ chosenOrientation = Qt.InvertedLandscapeOrientation;
176+ } else {
177+ chosenOrientation = root.shellPrimaryOrientation;
178+ }
179+
180+ return Screen.angleBetween(root.nativeOrientation, chosenOrientation);
181+ }
182+
183+ rotation: normalizeAngle(appWindowWithShadow.orientationAngle - root.shellOrientationAngle)
184+ width: {
185+ if (rotation == 0 || rotation == 180) {
186+ return root.width;
187+ } else {
188+ return root.height;
189+ }
190+ }
191+ height: {
192+ if (rotation == 0 || rotation == 180)
193+ return root.height;
194+ else
195+ return root.width;
196+ }
197+ }
198+ },
199+ // In this state we stick to our currently set orientationAngle, which may change only due
200+ // to calls made to matchShellOrientation() or animateToShellOrientation()
201+ State {
202+ id: keepSceneRotationState
203+ name: "keepSceneRotation"
204+
205+ StateChangeScript { script: {
206+ // break binding
207+ appWindowWithShadow.orientationAngle = appWindowWithShadow.orientationAngle;
208+ } }
209+ PropertyChanges {
210+ target: appWindowWithShadow
211+ restoreEntryValues: false
212+ rotation: normalizeAngle(appWindowWithShadow.orientationAngle - root.shellOrientationAngle)
213+ width: {
214+ if (rotation == 0 || rotation == 180) {
215+ return root.width;
216+ } else {
217+ return root.height;
218+ }
219+ }
220+ height: {
221+ if (rotation == 0 || rotation == 180)
222+ return root.height;
223+ else
224+ return root.width;
225+ }
226+ }
227+ },
228+ // In this state we counteract any shell rotation so that the window, in scene coordinates,
229+ // remains unrotated.
230+ State {
231+ name: "counterRotate"
232+ StateChangeScript { script: {
233+ // break binding
234+ appWindowWithShadow.orientationAngle = appWindowWithShadow.orientationAngle;
235+ } }
236+ PropertyChanges {
237+ target: appWindowWithShadow
238+ width: root.shellOrientationAngle == 0 || root.shellOrientationAngle == 180 ? root.width : root.height
239+ height: root.shellOrientationAngle == 0 || root.shellOrientationAngle == 180 ? root.height : root.width
240+ rotation: normalizeAngle(-root.shellOrientationAngle)
241+ }
242+ PropertyChanges {
243+ target: appWindow
244+ surfaceOrientationAngle: orientationAngle
245+ }
246+ },
247+ State {
248+ name: "animatingRotation"
249+ }
250+ ]
251+
252+ x: (parent.width - width) / 2
253+ y: (parent.height - height) / 2
254+
255+ BorderImage {
256+ anchors {
257+ fill: appWindow
258+ margins: -units.gu(2)
259+ }
260+ source: "graphics/dropshadow2gu.sci"
261+ opacity: root.dropShadow ? .3 : 0
262+ Behavior on opacity { UbuntuNumberAnimation {} }
263+ }
264+
265+ ApplicationWindow {
266+ id: appWindow
267+ objectName: application ? "appWindow_" + application.appId : "appWindow_null"
268+ focus: true
269+ anchors {
270+ fill: parent
271+ topMargin: appWindow.fullscreen || application.rotatesWindowContents
272+ ? 0 : maximizedAppTopMargin
273+ }
274+
74− interactive: root.interactive
275+ interactive: root.interactive
75− orientation: root.orientation
276+ }
277+ }
278+ }
279+
280+ Item {
281+ // mimics appWindowWithShadow. Do the positioning of screenshots of non-fullscreen
282+ // app windows
283+ id: appWindowScreenshotWithShadow
284+ visible: false
285+
286+ property real transformRotationAngle: 0
287+ property real transformOriginX
288+ property real transformOriginY
289+
290+ transform: Rotation {
291+ origin.x: appWindowScreenshotWithShadow.transformOriginX
292+ origin.y: appWindowScreenshotWithShadow.transformOriginY
293+ axis { x: 0; y: 0; z: 1 }
294+ angle: appWindowScreenshotWithShadow.transformRotationAngle
295+ }
296+
297+ property var window: appWindowScreenshot
298+
299+ function take() {
300+ // Format: "image://application/$APP_ID/$CURRENT_TIME_MS"
301+ // eg: "image://application/calculator-app/123456"
302+ var timeMs = new Date().getTime();
303+ appWindowScreenshot.source = "image://application/" + root.application.appId + "/" + timeMs;
304+ }
305+ function discard() {
306+ appWindowScreenshot.source = "";
307+ }
308+
309+ Image {
310+ id: appWindowScreenshot
311+ source: ""
312+
313+ anchors.fill: parent
314+
315+ sourceSize.width: width
316+ sourceSize.height: height
76 }
317 }
77 }
318 }
78
319
qml/Stages/SurfaceContainer.qml+2−2
@@ -24,8 +24,8 @@ FocusScope {
24 objectName: "surfaceContainer"
24 objectName: "surfaceContainer"
25 property Item surface: null
25 property Item surface: null
26 property bool hadSurface: false
26 property bool hadSurface: false
27− property int orientation
28 property bool interactive
27 property bool interactive
28+ property int surfaceOrientationAngle: 0
29
29
30 onSurfaceChanged: {
30 onSurfaceChanged: {
31 if (surface) {
31 if (surface) {
@@ -39,10 +39,10 @@ FocusScope {
39 }
39 }
40 }
40 }
41 Binding { target: surface; property: "anchors.fill"; value: root }
41 Binding { target: surface; property: "anchors.fill"; value: root }
42− Binding { target: surface; property: "orientation"; value: root.orientation }
43 Binding { target: surface; property: "z"; value: 1 }
42 Binding { target: surface; property: "z"; value: 1 }
44 Binding { target: surface; property: "enabled"; value: root.interactive; when: surface }
43 Binding { target: surface; property: "enabled"; value: root.interactive; when: surface }
45 Binding { target: surface; property: "antialiasing"; value: !root.interactive; when: surface }
44 Binding { target: surface; property: "antialiasing"; value: !root.interactive; when: surface }
45+ Binding { target: surface; property: "orientationAngle"; value: root.surfaceOrientationAngle; when: surface }
46
46
47 InputWatcher {
47 InputWatcher {
48 target: root.surface
48 target: root.surface
qml/Stages/TabletStage.qml+159−30
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2014 Canonical, Ltd.
2+ * Copyright (C) 2014-2015 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
@@ -28,13 +28,79 @@ Rectangle {
28 color: "#111111"
28 color: "#111111"
29
29
30 // Controls to be set from outside
30 // Controls to be set from outside
31− property bool shown: false
32− property bool moving: false
33 property int dragAreaWidth
31 property int dragAreaWidth
34 property real maximizedAppTopMargin
32 property real maximizedAppTopMargin
35 property bool interactive
33 property bool interactive
34+ property alias beingResized: spreadView.beingResized
35+
36+ property bool spreadEnabled: true // If false, animations and right edge will be disabled
37+
36 property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.
38 property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.
37− property int orientation: Qt.PortraitOrientation
39+ property int shellOrientationAngle: 0
40+ property int shellOrientation
41+ property int shellPrimaryOrientation
42+ property int nativeOrientation
43+ property real nativeWidth
44+ property real nativeHeight
45+ function updateFocusedAppOrientation() {
46+ var mainStageAppIndex = priv.indexOf(priv.mainStageAppId);
47+ if (mainStageAppIndex >= 0 && mainStageAppIndex < spreadRepeater.count) {
48+ spreadRepeater.itemAt(mainStageAppIndex).matchShellOrientation();
49+ }
50+
51+ for (var i = 0; i < spreadRepeater.count; ++i) {
52+
53+ if (i === mainStageAppIndex) {
54+ continue;
55+ }
56+
57+ var spreadDelegate = spreadRepeater.itemAt(i);
58+
59+ var delta = spreadDelegate.appWindowOrientationAngle - root.shellOrientationAngle;
60+ if (delta < 0) { delta += 360; }
61+ delta = delta % 360;
62+
63+ var supportedOrientations = spreadDelegate.application.supportedOrientations;
64+ if (supportedOrientations === Qt.PrimaryOrientation) {
65+ supportedOrientations = spreadDelegate.shellPrimaryOrientation;
66+ }
67+
68+ if (delta === 180 && (supportedOrientations & spreadDelegate.shellOrientation)) {
69+ spreadDelegate.matchShellOrientation();
70+ }
71+ }
72+ }
73+ function updateFocusedAppOrientationAnimated() {
74+ var mainStageAppIndex = priv.indexOf(priv.mainStageAppId);
75+ if (mainStageAppIndex >= 0 && mainStageAppIndex < spreadRepeater.count) {
76+ spreadRepeater.itemAt(mainStageAppIndex).animateToShellOrientation();
77+ }
78+
79+ if (priv.sideStageAppId) {
80+ var sideStageAppIndex = priv.indexOf(priv.sideStageAppId);
81+ if (sideStageAppIndex >= 0 && sideStageAppIndex < spreadRepeater.count) {
82+ spreadRepeater.itemAt(sideStageAppIndex).matchShellOrientation();
83+ }
84+ }
85+ }
86+
87+ // To be read from outside
88+ property var mainApp: null
89+ property int mainAppWindowOrientationAngle: 0
90+ readonly property bool orientationChangesEnabled: priv.mainAppOrientationChangesEnabled
91+
92+ onWidthChanged: {
93+ spreadView.selectedIndex = -1;
94+ spreadView.phase = 0;
95+ spreadView.contentX = -spreadView.shift;
96+ }
97+
98+ onShellOrientationChanged: {
99+ if (shellOrientation == Qt.PortraitOrientation || shellOrientation == Qt.InvertedPortraitOrientation) {
100+ ApplicationManager.focusApplication(priv.mainStageAppId);
101+ priv.sideStageAppId = "";
102+ }
103+ }
38
104
39 onInverseProgressChanged: {
105 onInverseProgressChanged: {
40 // This can't be a simple binding because that would be triggered after this handler
106 // This can't be a simple binding because that would be triggered after this handler
@@ -53,7 +119,19 @@ Rectangle {
53 id: priv
119 id: priv
54
120
55 property string focusedAppId: ApplicationManager.focusedApplicationId
121 property string focusedAppId: ApplicationManager.focusedApplicationId
122+ readonly property var focusedAppDelegate: {
123+ var index = indexOf(focusedAppId);
124+ return index >= 0 && index < spreadRepeater.count ? spreadRepeater.itemAt(index) : null
125+ }
126+
56 property string oldFocusedAppId: ""
127 property string oldFocusedAppId: ""
128+ property bool mainAppOrientationChangesEnabled: false
129+
130+ property real landscapeHeight: root.nativeOrientation == Qt.LandscapeOrientation ?
131+ root.nativeHeight : root.nativeWidth
132+
133+ property bool shellIsLandscape: root.shellOrientation === Qt.LandscapeOrientation
134+ || root.shellOrientation === Qt.InvertedLandscapeOrientation
57
135
58 property string mainStageAppId
136 property string mainStageAppId
59 property string sideStageAppId
137 property string sideStageAppId
@@ -71,24 +149,17 @@ Rectangle {
71 priv.sideStageAppId = focusedAppId;
149 priv.sideStageAppId = focusedAppId;
72 } else {
150 } else {
73 priv.mainStageAppId = focusedAppId;
151 priv.mainStageAppId = focusedAppId;
152+ root.mainApp = focusedApp;
74 }
153 }
75 }
154 }
76
155
77 appId0 = ApplicationManager.count >= 1 ? ApplicationManager.get(0).appId : "";
156 appId0 = ApplicationManager.count >= 1 ? ApplicationManager.get(0).appId : "";
78 appId1 = ApplicationManager.count > 1 ? ApplicationManager.get(1).appId : "";
157 appId1 = ApplicationManager.count > 1 ? ApplicationManager.get(1).appId : "";
79−
80− // Update the QML focus accordingly
81− updateSpreadDelegateFocus();
82 }
158 }
83
159
84− function updateSpreadDelegateFocus() {
160+ onFocusedAppDelegateChanged: {
85− if (priv.focusedAppId) {
161+ if (focusedAppDelegate) {
86− var focusedAppIndex = priv.indexOf(priv.focusedAppId);
162+ focusedAppDelegate.focus = true;
87− if (focusedAppIndex !== -1) {
88− spreadRepeater.itemAt(focusedAppIndex).focus = true;
89− } else {
90− console.warn("TabletStage: Failed to find the SpreadDelegate for appID=" + priv.focusedAppId);
91− }
92 }
163 }
93 }
164 }
94
165
@@ -169,6 +240,7 @@ Rectangle {
169
240
170 Flickable {
241 Flickable {
171 id: spreadView
242 id: spreadView
243+ objectName: "spreadView"
172 anchors.fill: parent
244 anchors.fill: parent
173 interactive: (spreadDragArea.dragging || phase > 1) && draggedDelegateCount === 0
245 interactive: (spreadDragArea.dragging || phase > 1) && draggedDelegateCount === 0
174 contentWidth: spreadRow.width - shift
246 contentWidth: spreadRow.width - shift
@@ -217,7 +289,25 @@ Rectangle {
217 property int draggedDelegateCount: 0
289 property int draggedDelegateCount: 0
218 property int closingIndex: -1
290 property int closingIndex: -1
219
291
292+ // FIXME: Workaround Flickable's not keepping its contentX still when resized
293+ onContentXChanged: { forceItToRemainStillIfBeingResized(); }
294+ onShiftChanged: { forceItToRemainStillIfBeingResized(); }
295+ function forceItToRemainStillIfBeingResized() {
296+ if (root.beingResized && contentX != -shift) {
297+ contentX = -shift;
298+ }
299+ }
300+
220 property bool animateX: true
301 property bool animateX: true
302+ property bool beingResized: false
303+ onBeingResizedChanged: {
304+ if (beingResized) {
305+ // Brace yourselves for impact!
306+ selectedIndex = -1;
307+ phase = 0;
308+ contentX = -shift;
309+ }
310+ }
221
311
222 property bool sideStageDragging: sideStageDragHandle.dragging
312 property bool sideStageDragging: sideStageDragHandle.dragging
223 property real sideStageDragProgress: sideStageDragHandle.progress
313 property real sideStageDragProgress: sideStageDragHandle.progress
@@ -256,7 +346,6 @@ Rectangle {
256 case "overlay":
346 case "overlay":
257 return 1;
347 return 1;
258 }
348 }
259− print("Unhandled nextInStack case! This shouldn't happen any more when the Dash is an app!");
260 return -1;
349 return -1;
261 }
350 }
262 property int nextZInStack: indexToZIndex(nextInStack)
351 property int nextZInStack: indexToZIndex(nextInStack)
@@ -292,6 +381,10 @@ Rectangle {
292 }
381 }
293
382
294 onShiftedContentXChanged: {
383 onShiftedContentXChanged: {
384+ if (root.beingResized) {
385+ // Flickabe.contentX wiggles during resizes. Don't react to it.
386+ return;
387+ }
295 if (spreadView.phase == 0 && spreadView.shiftedContentX > spreadView.width * spreadView.positionMarker2) {
388 if (spreadView.phase == 0 && spreadView.shiftedContentX > spreadView.width * spreadView.positionMarker2) {
296 spreadView.phase = 1;
389 spreadView.phase = 1;
297 } else if (spreadView.phase == 1 && spreadView.shiftedContentX > spreadView.width * spreadView.positionMarker4) {
390 } else if (spreadView.phase == 1 && spreadView.shiftedContentX > spreadView.width * spreadView.positionMarker4) {
@@ -401,8 +494,8 @@ Rectangle {
401 MouseArea {
494 MouseArea {
402 id: spreadRow
495 id: spreadRow
403 x: spreadView.contentX
496 x: spreadView.contentX
404− height: root.height
405 width: spreadView.width + Math.max(spreadView.width, ApplicationManager.count * spreadView.tileDistance)
497 width: spreadView.width + Math.max(spreadView.width, ApplicationManager.count * spreadView.tileDistance)
498+ height: root.height
406
499
407 onClicked: {
500 onClicked: {
408 spreadView.snapTo(0);
501 spreadView.snapTo(0);
@@ -411,8 +504,9 @@ Rectangle {
411 Rectangle {
504 Rectangle {
412 id: sideStageBackground
505 id: sideStageBackground
413 color: "black"
506 color: "black"
414− anchors.fill: parent
415− anchors.leftMargin: spreadView.width - (1 - sideStageDragHandle.progress) * spreadView.sideStageWidth
507+ width: spreadView.sideStageWidth * (1 - sideStageDragHandle.progress)
508+ height: priv.landscapeHeight
509+ x: spreadView.width - width
416 z: spreadView.indexToZIndex(priv.indexOf(priv.sideStageAppId))
510 z: spreadView.indexToZIndex(priv.indexOf(priv.sideStageAppId))
417 opacity: spreadView.phase == 0 ? 1 : 0
511 opacity: spreadView.phase == 0 ? 1 : 0
418 Behavior on opacity { UbuntuNumberAnimation {} }
512 Behavior on opacity { UbuntuNumberAnimation {} }
@@ -420,8 +514,10 @@ Rectangle {
420
514
421 Item {
515 Item {
422 id: sideStageDragHandle
516 id: sideStageDragHandle
423− anchors { top: parent.top; bottom: parent.bottom; left: parent.left; leftMargin: spreadView.width - spreadView.sideStageWidth - width }
517+ anchors.right: sideStageBackground.left
518+ anchors.top: sideStageBackground.top
424 width: units.gu(2)
519 width: units.gu(2)
520+ height: priv.landscapeHeight
425 z: sideStageBackground.z
521 z: sideStageBackground.z
426 opacity: spreadView.phase <= 0 && spreadView.sideStageVisible ? 1 : 0
522 opacity: spreadView.phase <= 0 && spreadView.sideStageVisible ? 1 : 0
427 property real progress: 0
523 property real progress: 0
@@ -440,7 +536,6 @@ Rectangle {
440
536
441 Image {
537 Image {
442 anchors.centerIn: parent
538 anchors.centerIn: parent
443− anchors.horizontalCenterOffset: parent.progress * spreadView.sideStageWidth - (width - parent.width) / 2
444 width: sideStageDragHandleMouseArea.pressed ? parent.width * 2 : parent.width
539 width: sideStageDragHandleMouseArea.pressed ? parent.width * 2 : parent.width
445 height: parent.height
540 height: parent.height
446 source: "graphics/sidestage_handle@20.png"
541 source: "graphics/sidestage_handle@20.png"
@@ -453,16 +548,19 @@ Rectangle {
453 enabled: spreadView.shiftedContentX == 0
548 enabled: spreadView.shiftedContentX == 0
454 property int startX
549 property int startX
455 property var gesturePoints: new Array()
550 property var gesturePoints: new Array()
551+ property real totalDiff
456
552
457 onPressed: {
553 onPressed: {
458 gesturePoints = [];
554 gesturePoints = [];
459 startX = mouseX;
555 startX = mouseX;
556+ totalDiff = 0.0;
460 sideStageDragHandle.progress = 0;
557 sideStageDragHandle.progress = 0;
461 sideStageDragHandle.dragging = true;
558 sideStageDragHandle.dragging = true;
462 }
559 }
463 onMouseXChanged: {
560 onMouseXChanged: {
561+ totalDiff += mouseX - startX;
464 if (priv.mainStageAppId) {
562 if (priv.mainStageAppId) {
465− sideStageDragHandle.progress = Math.max(0, (-startX + mouseX) / spreadView.sideStageWidth);
563+ sideStageDragHandle.progress = Math.max(0, totalDiff / spreadView.sideStageWidth);
466 }
564 }
467 gesturePoints.push(mouseX);
565 gesturePoints.push(mouseX);
468 }
566 }
@@ -491,12 +589,27 @@ Rectangle {
491
589
492 Repeater {
590 Repeater {
493 id: spreadRepeater
591 id: spreadRepeater
592+ objectName: "spreadRepeater"
494 model: ApplicationManager
593 model: ApplicationManager
495
594
496 delegate: TransformedTabletSpreadDelegate {
595 delegate: TransformedTabletSpreadDelegate {
497 id: spreadTile
596 id: spreadTile
498− height: spreadView.height
597+ objectName: model.appId ? "tabletSpreadDelegate_" + model.appId
598+ : "tabletSpreadDelegate_null";
599+ width: {
600+ if (wantsMainStage) {
601+ return spreadView.width;
602+ } else {
499− width: model.stage == ApplicationInfoInterface.MainStage ? spreadView.width : spreadView.sideStageWidth
603+ return spreadView.sideStageWidth;
604+ }
605+ }
606+ height: {
607+ if (wantsMainStage) {
608+ return spreadView.height;
609+ } else {
610+ return priv.landscapeHeight;
611+ }
612+ }
500 active: model.appId == priv.mainStageAppId || model.appId == priv.sideStageAppId
613 active: model.appId == priv.mainStageAppId || model.appId == priv.sideStageAppId
501 zIndex: spreadView.indexToZIndex(index)
614 zIndex: spreadView.indexToZIndex(index)
502 selected: spreadView.selectedIndex == index
615 selected: spreadView.selectedIndex == index
@@ -509,6 +622,8 @@ Rectangle {
509 application: ApplicationManager.get(index)
622 application: ApplicationManager.get(index)
510 closeable: !isDash
623 closeable: !isDash
511
624
625+ readonly property bool wantsMainStage: model.stage == ApplicationInfoInterface.MainStage
626+
512 readonly property bool isDash: model.appId == "unity8-dash"
627 readonly property bool isDash: model.appId == "unity8-dash"
513
628
514 // FIXME: A regular binding doesn't update any more after closing an app.
629 // FIXME: A regular binding doesn't update any more after closing an app.
@@ -560,12 +675,11 @@ Rectangle {
560 return progress;
675 return progress;
561 }
676 }
562
677
563− Binding {
678+ shellOrientationAngle: wantsMainStage ? root.shellOrientationAngle : 0
564− target: spreadTile
679+ shellOrientation: wantsMainStage ? root.shellOrientation : Qt.PortraitOrientation
565− property: "orientation"
680+ shellPrimaryOrientation: wantsMainStage ? root.shellPrimaryOrientation : Qt.PortraitOrientation
566− when: spreadTile.interactive
681+ nativeOrientation: wantsMainStage ? root.nativeOrientation : Qt.PortraitOrientation
567− value: root.orientation
682+
568− }
569
683
570 onClicked: {
684 onClicked: {
571 if (spreadView.phase == 2) {
685 if (spreadView.phase == 2) {
@@ -586,6 +700,19 @@ Rectangle {
586 ApplicationManager.stopApplication(ApplicationManager.get(index).appId);
700 ApplicationManager.stopApplication(ApplicationManager.get(index).appId);
587 }
701 }
588
702
703+ Binding {
704+ target: root
705+ when: model.appId == priv.mainStageAppId
706+ property: "mainAppWindowOrientationAngle"
707+ value: appWindowOrientationAngle
708+ }
709+ Binding {
710+ target: priv
711+ when: model.appId == priv.mainStageAppId
712+ property: "mainAppOrientationChangesEnabled"
713+ value: orientationChangesEnabled
714+ }
715+
589 EasingCurve {
716 EasingCurve {
590 id: snappingCurve
717 id: snappingCurve
591 type: EasingCurve.Linear
718 type: EasingCurve.Linear
@@ -599,9 +726,11 @@ Rectangle {
599
726
600 DirectionalDragArea {
727 DirectionalDragArea {
601 id: spreadDragArea
728 id: spreadDragArea
729+ objectName: "spreadDragArea"
602 anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
730 anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
603 width: root.dragAreaWidth
731 width: root.dragAreaWidth
604 direction: Direction.Leftwards
732 direction: Direction.Leftwards
733+ enabled: (spreadView.phase != 2 && root.spreadEnabled) || dragging
605
734
606 property var gesturePoints: new Array()
735 property var gesturePoints: new Array()
607
736
qml/Stages/TransformedSpreadDelegate.qml+50−6
@@ -298,7 +298,6 @@ SpreadDelegate {
298
298
299 return easingCurve.value;
299 return easingCurve.value;
300 }
300 }
301−
302 }
301 }
303
302
304 transform: [
303 transform: [
@@ -307,16 +306,61 @@ SpreadDelegate {
307 axis { x: 0; y: 1; z: 0 }
306 axis { x: 0; y: 1; z: 0 }
308 angle: priv.angle
307 angle: priv.angle
309 },
308 },
309+
310+ // The next two transformations are to ensure that fullscreen and rotated
311+ // windows all have the same size and position as an unrotated (0 degrees)
312+ // non-fullscreen window when they're stacked on top of each other on the
313+ // far left of the spread.
314+ Translate {
315+ y: !fullscreen && appWindowRotation === 180
316+ ? priv.topMarginProgress * maximizedAppTopMargin
317+ : 0
318+ },
319+ Scale {
320+ origin {
321+ x: appWindowRotation === 270 ? spreadView.width : 0
322+ y: spreadView.height
323+ }
324+
325+ xScale: {
326+ switch (appWindowRotation) {
327+ case 90:
328+ case 270:
329+ if (fullscreen) {
330+ return 1;
331+ } else {
332+ return 1 + priv.topMarginProgress * maximizedAppTopMargin / spreadView.width;
333+ }
334+ break;
335+ default:
336+ return 1;
337+ }
338+ }
339+
340+ yScale: {
341+ switch (appWindowRotation) {
342+ case 0:
343+ if (fullscreen) {
344+ return 1 - priv.topMarginProgress * maximizedAppTopMargin / spreadView.height;
345+ } else {
346+ return 1;
347+ }
348+ break;
349+ case 90:
350+ case 270:
351+ return 1 - priv.topMarginProgress * maximizedAppTopMargin / spreadView.height;
352+ break;
353+ default:
354+ return 1;
355+ }
356+ }
357+ },
358+
310 Scale {
359 Scale {
311 origin { x: 0; y: spreadView.height / 2 }
360 origin { x: 0; y: spreadView.height / 2 }
312 xScale: priv.scale
361 xScale: priv.scale
313 yScale: xScale
362 yScale: xScale
314 },
363 },
315− Scale {
316− origin { x: 0; y: (spreadView.height * priv.scale) + maximizedAppTopMargin * 3 }
317− xScale: 1
318− yScale: fullscreen ? 1 - priv.topMarginProgress * maximizedAppTopMargin / spreadView.height : 1
319− },
320 Translate {
364 Translate {
321 x: priv.xTranslate
365 x: priv.xTranslate
322 }
366 }
qml/Stages/TransformedTabletSpreadDelegate.qml+5−2
@@ -50,7 +50,9 @@ SpreadDelegate {
50 property int dragOffset: 0
50 property int dragOffset: 0
51
51
52 dropShadow: spreadView.active ||
52 dropShadow: spreadView.active ||
53+ (active
53− (active && model.stage == ApplicationInfoInterface.MainStage && priv.xTranslate != 0)
54+ && (model.stage == ApplicationInfoInterface.MainStage || !priv.shellIsLandscape)
55+ && priv.xTranslate != 0)
54
56
55 onSelectedChanged: {
57 onSelectedChanged: {
56 if (selected) {
58 if (selected) {
@@ -139,7 +141,8 @@ SpreadDelegate {
139 !snapAnimation.running &&
141 !snapAnimation.running &&
140 model.appId !== "unity8-dash" &&
142 model.appId !== "unity8-dash" &&
141 !spreadView.sideStageDragging &&
143 !spreadView.sideStageDragging &&
142− spreadView.animateX
144+ spreadView.animateX &&
145+ !spreadView.beingResized
143 UbuntuNumberAnimation {
146 UbuntuNumberAnimation {
144 duration: UbuntuAnimation.FastDuration
147 duration: UbuntuAnimation.FastDuration
145 }
148 }
run.sh+1−1
@@ -44,7 +44,7 @@ else
44 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/plugins/LightDM/liblightdm
44 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/plugins/LightDM/liblightdm
45fi
45fi
46
46
47−QML_PHONE_SHELL_ARGS=""
47+QML_PHONE_SHELL_ARGS="-windowgeometry=40gux68gu -devicename=mako"
48if $MOUSE_TOUCH; then
48if $MOUSE_TOUCH; then
49 QML_PHONE_SHELL_ARGS="$QML_PHONE_SHELL_ARGS -mousetouch"
49 QML_PHONE_SHELL_ARGS="$QML_PHONE_SHELL_ARGS -mousetouch"
50fi
50fi
src/ApplicationArguments.cppnew file+22
@@ -0,0 +1,22 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "ApplicationArguments.h"
18+
19+ApplicationArguments::ApplicationArguments(QObject *parent)
20+ : QObject(parent)
21+{
22+}
src/ApplicationArguments.h+7−11
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2013 Canonical, Ltd.
2+ * Copyright (C) 2013,2015 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
@@ -13,7 +13,6 @@
13 * You should have received a copy of the GNU General Public License
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/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
15 *
16− * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
17 */
16 */
18
17
19
18
@@ -22,23 +21,20 @@
22
21
23#include <QObject>
22#include <QObject>
24#include <QSize>
23#include <QSize>
25−#include <QStringList>
24+#include <QString>
26
25
27class ApplicationArguments : public QObject
26class ApplicationArguments : public QObject
28{
27{
29 Q_OBJECT
28 Q_OBJECT
29+ Q_PROPERTY(QString deviceName READ deviceName CONSTANT)
30public:
30public:
31− // Not exposed to the app as setSize isn't invokable
31+ ApplicationArguments(QObject *parent = nullptr);
32− void setSize(const QSize &size) {
33− m_size = size;
34− }
35
32
36− Q_INVOKABLE bool hasGeometry() const { return m_size.isValid(); }
33+ void setDeviceName(QString deviceName) { m_deviceName = deviceName; }
37− Q_INVOKABLE int width() const { return m_size.width(); }
34+ QString deviceName() const { return m_deviceName; }
38− Q_INVOKABLE int height() const { return m_size.height(); }
39
35
40private:
36private:
41− QSize m_size;
37+ QString m_deviceName;
42};
38};
43
39
44#endif // APPLICATION_ARGUMENTS_H
40#endif // APPLICATION_ARGUMENTS_H
src/CMakeLists.txt+5−6
@@ -17,7 +17,7 @@ file(GLOB_RECURSE QML_FILES
17)
17)
18
18
19add_executable(${SHELL_APP}
19add_executable(${SHELL_APP}
20− ApplicationArguments.h
20+ ApplicationArguments.cpp
21 main.cpp
21 main.cpp
22 MouseTouchAdaptor.cpp
22 MouseTouchAdaptor.cpp
23 CachingNetworkManagerFactory.cpp
23 CachingNetworkManagerFactory.cpp
@@ -26,13 +26,12 @@ add_executable(${SHELL_APP}
26)
26)
27
27
28qt5_use_modules(${SHELL_APP} Gui Qml Quick Test)
28qt5_use_modules(${SHELL_APP} Gui Qml Quick Test)
29−pkg_check_modules(XCB REQUIRED xcb)
30
29
31−if (NOT "${XCB_INCLUDE_DIRS}" STREQUAL "")
30+pkg_check_modules(NEEDED_LIBS REQUIRED xcb libandroid-properties)
31+if (NOT "${NEEDED_LIBS_INCLUDE_DIRS}" STREQUAL "")
32− set_target_properties(${SHELL_APP} PROPERTIES INCLUDE_DIRECTORIES ${XCB_INCLUDE_DIRS})
32+ set_target_properties(${SHELL_APP} PROPERTIES INCLUDE_DIRECTORIES ${NEEDED_LIBS_INCLUDE_DIRS})
33−
34− target_link_libraries(${SHELL_APP} ${XCB_LDFLAGS})
35endif()
33endif()
34+target_link_libraries(${SHELL_APP} ${NEEDED_LIBS_LDFLAGS})
36
35
37target_link_libraries(${SHELL_APP} UbuntuGestures connectivity-qt1)
36target_link_libraries(${SHELL_APP} UbuntuGestures connectivity-qt1)
38
37
src/Dash/CMakeLists.txt+7−1
@@ -1,6 +1,6 @@
1set(DASH_SRCS
1set(DASH_SRCS
2 main.cpp
2 main.cpp
3− ../ApplicationArguments.h
3+ ../ApplicationArguments.cpp
4 ../MouseTouchAdaptor.cpp
4 ../MouseTouchAdaptor.cpp
5 ../CachingNetworkManagerFactory.cpp
5 ../CachingNetworkManagerFactory.cpp
6)
6)
@@ -9,6 +9,12 @@ add_executable(unity8-dash ${DASH_SRCS})
9
9
10qt5_use_modules(unity8-dash Gui Qml Quick Test)
10qt5_use_modules(unity8-dash Gui Qml Quick Test)
11
11
12+pkg_check_modules(NEEDED_LIBS REQUIRED xcb libandroid-properties)
13+if (NOT "${NEEDED_LIBS_INCLUDE_DIRS}" STREQUAL "")
14+ set_target_properties(unity8-dash PROPERTIES INCLUDE_DIRECTORIES ${NEEDED_LIBS_INCLUDE_DIRS})
15+endif()
16+target_link_libraries(unity8-dash ${NEEDED_LIBS_LDFLAGS})
17+
12# For it to find libUbuntuGestures.so, needed by Ubuntu.Gestures QML module.
18# For it to find libUbuntuGestures.so, needed by Ubuntu.Gestures QML module.
13set_target_properties(unity8-dash PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}")
19set_target_properties(unity8-dash PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}")
14
20
src/Dash/main.cpp+12−12
@@ -31,9 +31,6 @@
31#include "../ApplicationArguments.h"
31#include "../ApplicationArguments.h"
32#include "../CachingNetworkManagerFactory.h"
32#include "../CachingNetworkManagerFactory.h"
33
33
34−// Ubuntu Gestures
35−#include <TouchRegistry.h>
36−
37int main(int argc, const char *argv[])
34int main(int argc, const char *argv[])
38{
35{
39 QGuiApplication *application = new QGuiApplication(argc, (char**)argv);
36 QGuiApplication *application = new QGuiApplication(argc, (char**)argv);
@@ -61,12 +58,6 @@ int main(int argc, const char *argv[])
61 parser.process(*application);
58 parser.process(*application);
62
59
63 ApplicationArguments qmlArgs;
60 ApplicationArguments qmlArgs;
64− if (parser.isSet(windowGeometryOption) &&
65− parser.value(windowGeometryOption).split('x').size() == 2)
66− {
67− QStringList geom = parser.value(windowGeometryOption).split('x');
68− qmlArgs.setSize(QSize(geom.at(0).toInt(), geom.at(1).toInt()));
69− }
70
61
71 if (getenv("QT_LOAD_TESTABILITY")) {
62 if (getenv("QT_LOAD_TESTABILITY")) {
72 QLibrary testLib(QLatin1String("qttestability"));
63 QLibrary testLib(QLatin1String("qttestability"));
@@ -88,12 +79,21 @@ int main(int argc, const char *argv[])
88
79
89 QQuickView* view = new QQuickView();
80 QQuickView* view = new QQuickView();
90 view->setResizeMode(QQuickView::SizeRootObjectToView);
81 view->setResizeMode(QQuickView::SizeRootObjectToView);
82+
83+ if (parser.isSet(windowGeometryOption) &&
84+ parser.value(windowGeometryOption).split('x').size() == 2)
85+ {
86+ QStringList geom = parser.value(windowGeometryOption).split('x');
87+ QSize windowSize(geom.at(0).toInt(), geom.at(1).toInt());
88+ if (windowSize.isValid()) {
89+ view->setWidth(windowSize.width());
90+ view->setHeight(windowSize.height());
91+ }
92+ }
93+
91 view->setTitle("Scopes");
94 view->setTitle("Scopes");
92 view->rootContext()->setContextProperty("applicationArguments", &qmlArgs);
95 view->rootContext()->setContextProperty("applicationArguments", &qmlArgs);
93
96
94− TouchRegistry touchRegistry;
95− view->installEventFilter(&touchRegistry);
96−
97 // You will need this if you want to interact with touch-only components using a mouse
97 // You will need this if you want to interact with touch-only components using a mouse
98 // Needed only when manually testing on a desktop.
98 // Needed only when manually testing on a desktop.
99 MouseTouchAdaptor *mouseTouchAdaptor = 0;
99 MouseTouchAdaptor *mouseTouchAdaptor = 0;
src/UnityCommandLineParser.cpp+5
@@ -49,6 +49,10 @@ UnityCommandLineParser::UnityCommandLineParser(const QCoreApplication &app)
49 "DISCOURAGED: Please set QT_LOAD_TESTABILITY instead.\nLoad the testability driver");
49 "DISCOURAGED: Please set QT_LOAD_TESTABILITY instead.\nLoad the testability driver");
50 parser.addOption(testabilityOption);
50 parser.addOption(testabilityOption);
51
51
52+ QCommandLineOption devicenameOption(QStringList() << "devicename",
53+ "Specify the device name instead of letting Unity 8 find it out", "devicename", "");
54+ parser.addOption(devicenameOption);
55+
52 QCommandLineOption modeOption("mode",
56 QCommandLineOption modeOption("mode",
53 "Whether to run greeter and/or shell [full-greeter, full-shell, greeter, shell]",
57 "Whether to run greeter and/or shell [full-greeter, full-shell, greeter, shell]",
54 "mode", "full-greeter");
58 "mode", "full-greeter");
@@ -73,6 +77,7 @@ UnityCommandLineParser::UnityCommandLineParser(const QCoreApplication &app)
73 m_hasFrameless = parser.isSet(framelessOption);
77 m_hasFrameless = parser.isSet(framelessOption);
74 m_hasMouseToTouch = parser.isSet(mousetouchOption);
78 m_hasMouseToTouch = parser.isSet(mousetouchOption);
75 m_hasFullscreen = parser.isSet(fullscreenOption);
79 m_hasFullscreen = parser.isSet(fullscreenOption);
80+ m_deviceName = parser.value(devicenameOption);
76 resolveMode(parser, modeOption);
81 resolveMode(parser, modeOption);
77}
82}
78
83
src/UnityCommandLineParser.h+2
@@ -30,6 +30,7 @@ public:
30 bool hasFrameless() const { return m_hasFrameless; }
30 bool hasFrameless() const { return m_hasFrameless; }
31 bool hasMouseToTouch() const { return m_hasMouseToTouch; }
31 bool hasMouseToTouch() const { return m_hasMouseToTouch; }
32 bool hasFullscreen() const { return m_hasFullscreen; }
32 bool hasFullscreen() const { return m_hasFullscreen; }
33+ QString deviceName() const { return m_deviceName; }
33 QString mode() const { return m_mode; }
34 QString mode() const { return m_mode; }
34private:
35private:
35
36
@@ -44,6 +45,7 @@ private:
44 bool m_hasFrameless;
45 bool m_hasFrameless;
45 bool m_hasMouseToTouch;
46 bool m_hasMouseToTouch;
46 bool m_hasFullscreen;
47 bool m_hasFullscreen;
48+ QString m_deviceName;
47 QString m_mode;
49 QString m_mode;
48};
50};
49
51
src/main.cpp+18−13
@@ -25,6 +25,9 @@
25#include <csignal>
25#include <csignal>
26#include <libintl.h>
26#include <libintl.h>
27
27
28+// libandroid-properties
29+#include <hybris/properties/properties.h>
30+
28// local
31// local
29#include <paths.h>
32#include <paths.h>
30#include "MouseTouchAdaptor.h"
33#include "MouseTouchAdaptor.h"
@@ -32,9 +35,6 @@
32#include "CachingNetworkManagerFactory.h"
35#include "CachingNetworkManagerFactory.h"
33#include "UnityCommandLineParser.h"
36#include "UnityCommandLineParser.h"
34
37
35−// Ubuntu Gestures
36−#include <TouchRegistry.h>
37−
38int main(int argc, const char *argv[])
38int main(int argc, const char *argv[])
39{
39{
40 bool isMirServer = false;
40 bool isMirServer = false;
@@ -50,13 +50,15 @@ int main(int argc, const char *argv[])
50
50
51 UnityCommandLineParser parser(*application);
51 UnityCommandLineParser parser(*application);
52
52
53− QString indicatorProfile = qgetenv("UNITY_INDICATOR_PROFILE");
54− if (indicatorProfile.isEmpty()) {
55− indicatorProfile = "phone";
56− }
57−
58 ApplicationArguments qmlArgs;
53 ApplicationArguments qmlArgs;
59− qmlArgs.setSize(parser.windowGeometry());
54+
55+ if (!parser.deviceName().isEmpty()) {
56+ qmlArgs.setDeviceName(parser.deviceName());
57+ } else {
58+ char buffer[200];
59+ property_get("ro.product.device", buffer /* value */, "desktop" /* default_value*/);
60+ qmlArgs.setDeviceName(QString(buffer));
61+ }
60
62
61 // The testability driver is only loaded by QApplication but not by QGuiApplication.
63 // The testability driver is only loaded by QApplication but not by QGuiApplication.
62 // However, QApplication depends on QWidget which would add some unneeded overhead => Let's load the testability driver on our own.
64 // However, QApplication depends on QWidget which would add some unneeded overhead => Let's load the testability driver on our own.
@@ -82,15 +84,18 @@ int main(int argc, const char *argv[])
82 view->setResizeMode(QQuickView::SizeRootObjectToView);
84 view->setResizeMode(QQuickView::SizeRootObjectToView);
83 view->setColor("black");
85 view->setColor("black");
84 view->setTitle("Unity8 Shell");
86 view->setTitle("Unity8 Shell");
87+
88+ if (parser.windowGeometry().isValid()) {
89+ view->setWidth(parser.windowGeometry().width());
90+ view->setHeight(parser.windowGeometry().height());
91+ }
92+
85 view->engine()->setBaseUrl(QUrl::fromLocalFile(::qmlDirectory()));
93 view->engine()->setBaseUrl(QUrl::fromLocalFile(::qmlDirectory()));
86 view->rootContext()->setContextProperty("applicationArguments", &qmlArgs);
94 view->rootContext()->setContextProperty("applicationArguments", &qmlArgs);
87− view->rootContext()->setContextProperty("indicatorProfile", indicatorProfile);
88 view->rootContext()->setContextProperty("shellMode", parser.mode());
95 view->rootContext()->setContextProperty("shellMode", parser.mode());
89 if (parser.hasFrameless()) {
96 if (parser.hasFrameless()) {
90 view->setFlags(Qt::FramelessWindowHint);
97 view->setFlags(Qt::FramelessWindowHint);
91 }
98 }
92− TouchRegistry touchRegistry;
93− view->installEventFilter(&touchRegistry);
94
99
95 // You will need this if you want to interact with touch-only components using a mouse
100 // You will need this if you want to interact with touch-only components using a mouse
96 // Needed only when manually testing on a desktop.
101 // Needed only when manually testing on a desktop.
@@ -99,7 +104,7 @@ int main(int argc, const char *argv[])
99 mouseTouchAdaptor = MouseTouchAdaptor::instance();
104 mouseTouchAdaptor = MouseTouchAdaptor::instance();
100 }
105 }
101
106
102− QUrl source(::qmlDirectory()+"Shell.qml");
107+ QUrl source(::qmlDirectory()+"OrientedShell.qml");
103 prependImportPaths(view->engine(), ::overrideImportPaths());
108 prependImportPaths(view->engine(), ::overrideImportPaths());
104 if (!isMirServer) {
109 if (!isMirServer) {
105 prependImportPaths(view->engine(), ::nonMirImportPaths());
110 prependImportPaths(view->engine(), ::nonMirImportPaths());
tests/autopilot/unity8/application_lifecycle/tests/test_application_lifecycle.py+13−3
@@ -21,6 +21,7 @@
21
21
22import logging
22import logging
23import os
23import os
24+import threading
24
25
25from autopilot.platform import model
26from autopilot.platform import model
26
27
@@ -90,10 +91,19 @@ class ApplicationLifecycleTests(tests.ApplicationLifeCycleTestCase):
90 """Greeter should hide when an app is opened"""
91 """Greeter should hide when an app is opened"""
91 process_helpers.lock_unity()
92 process_helpers.lock_unity()
92
93
93− application_name = self.launch_fake_app()
94+ # FIXME - this is because the device greeter uses a password.
95+ # Need to be able to selectively enable mocks so that we can use the fake greeter.
96+ def unlock_thread_worker(greeter):
97+ greeter.wait_swiped_away()
98+ process_helpers.unlock_unity()
99+ greeter.created.wait_for(False)
100+
94 greeter = self.main_window.get_greeter()
101 greeter = self.main_window.get_greeter()
95− greeter.wait_swiped_away()
102+ unlock_thread = threading.Thread(target=unlock_thread_worker, args=(greeter,))
96− process_helpers.unlock_unity()
103+ unlock_thread.start()
104+ application_name = self.launch_fake_app()
105+ unlock_thread.join(10)
106+
97 self.assert_current_focused_application(application_name)
107 self.assert_current_focused_application(application_name)
98
108
99 def test_greeter_hides_on_app_focus(self):
109 def test_greeter_hides_on_app_focus(self):
tests/autopilot/unity8/fixture_setup.py+131−3
@@ -17,19 +17,147 @@
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18#
18#
19
19
20−import fixtures
21−import logging
22import os
20import os
23import subprocess
21import subprocess
22+import threading
23+import fixtures
24+import logging
24
25
25import ubuntuuitoolkit
26import ubuntuuitoolkit
26from autopilot import introspection
27from autopilot import introspection
28+from autopilot.matchers import Eventually
29+from testtools.matchers import Equals
30+from ubuntuuitoolkit import fixture_setup
27
31
28from unity8 import (
32from unity8 import (
29 get_binary_path,
33 get_binary_path,
34+ sensors,
30 process_helpers
35 process_helpers
31)
36)
32
37
38+from unity8.shell import emulators
39+
40+from unity8.shell.emulators import (
41+ main_window as main_window_emulator
42+)
43+
44+from unity8 import (
45+ get_mocks_library_path,
46+ get_default_extra_mock_libraries,
47+ get_data_dirs
48+)
49+
50+logger = logging.getLogger(__name__)
51+
52+
53+class LaunchUnityWithFakeSensors(fixtures.Fixture):
54+
55+ """Fixture to launch Unity8 with an injectable sensors backend.
56+
57+ :ivar unity_proxy: The Autopilot proxy object for the Unity shell.
58+
59+ """
60+
61+ unity_proxy = None
62+ main_win = None
63+
64+ def setUp(self):
65+ """Restart Unity8 with testability and create sensors."""
66+ super().setUp()
67+ self.useFixture(
68+ fixture_setup.InitctlEnvironmentVariable(
69+ UBUNTU_PLATFORM_API_TEST_OVERRIDE='sensors'))
70+
71+ self.addCleanup(process_helpers.stop_job, 'unity8')
72+ restart_thread = threading.Thread(
73+ target=self._restart_unity_with_testability)
74+ restart_thread.start()
75+
76+ self._create_sensors()
77+
78+ restart_thread.join()
79+ self.fake_sensors = sensors.FakePlatformSensors()
80+
81+ def _get_lightdm_mock_path(self):
82+ lib_path = get_mocks_library_path()
83+ lightdm_mock_path = os.path.abspath(
84+ os.path.join(lib_path, "LightDM", "liblightdm")
85+ )
86+
87+ if not os.path.exists(lightdm_mock_path):
88+ raise RuntimeError(
89+ "LightDM mock does not exist at path {}.".
90+ format(lightdm_mock_path)
91+ )
92+ return lightdm_mock_path
93+
94+ def _get_qml_import_path_with_mock(self):
95+ """Return the QML2_IMPORT_PATH value with the mock path prepended."""
96+ qml_import_path = [get_mocks_library_path()]
97+ if os.getenv('QML2_IMPORT_PATH') is not None:
98+ qml_import_path.append(os.getenv('QML2_IMPORT_PATH'))
99+
100+ qml_import_path = ':'.join(qml_import_path)
101+ return qml_import_path
102+
103+ def _restart_unity_with_testability(self):
104+ _environment = {}
105+
106+ data_dirs = get_data_dirs(True)
107+ if data_dirs is not None:
108+ _environment['XDG_DATA_DIRS'] = data_dirs
109+
110+ _environment['QML2_IMPORT_PATH'] = (
111+ self._get_qml_import_path_with_mock()
112+ )
113+
114+ new_ld_library_path = [
115+ get_default_extra_mock_libraries(),
116+ self._get_lightdm_mock_path()
117+ ]
118+ if os.getenv('LD_LIBRARY_PATH') is not None:
119+ new_ld_library_path.append(os.getenv('LD_LIBRARY_PATH'))
120+ new_ld_library_path = ':'.join(new_ld_library_path)
121+ _environment['LD_LIBRARY_PATH'] = new_ld_library_path
122+
123+ # FIXME: we shouldn't be doing this
124+ # $MIR_SOCKET, fallback to $XDG_RUNTIME_DIR/mir_socket and
125+ # /tmp/mir_socket as last resort
126+ try:
127+ os.unlink(
128+ os.getenv('MIR_SOCKET',
129+ os.path.join(os.getenv('XDG_RUNTIME_DIR', "/tmp"),
130+ "mir_socket")))
131+ except OSError:
132+ pass
133+ try:
134+ os.unlink("/tmp/mir_socket")
135+ except OSError:
136+ pass
137+
138+ binary_arg = "BINARY=%s" % get_binary_path()
139+ env_args = ["%s=%s" % (k, v) for k, v in _environment.items()]
140+ args = [binary_arg] + env_args
141+ self.unity_proxy = process_helpers.restart_unity_with_testability(
142+ *args)
143+ self.main_win = self.unity_proxy.select_single(
144+ main_window_emulator.QQuickView)
145+
146+ def _create_sensors(self):
147+ # Wait for unity to start running.
148+ Eventually(Equals(True)).match(
149+ lambda: process_helpers.is_job_running('unity8'))
150+
151+ # Wait for the sensors fifo file to be created.
152+ fifo_path = '/tmp/sensor-fifo-{0}'.format(
153+ process_helpers.get_unity_pid())
154+ Eventually(Equals(True)).match(
155+ lambda: os.path.exists(fifo_path))
156+
157+ with open(fifo_path, 'w') as fifo:
158+ fifo.write('create accel 0 1000 0.1\n')
159+ fifo.write('create light 0 10 1\n')
160+ fifo.write('create proximity\n')
33
161
34logger = logging.getLogger(__name__)
162logger = logging.getLogger(__name__)
35
163
@@ -188,7 +316,7 @@ class LaunchMockIndicatorService(fixtures.Fixture):
188 self.ensure_not_running = ensure_not_running
316 self.ensure_not_running = ensure_not_running
189
317
190 def setUp(self):
318 def setUp(self):
191− super(LaunchMockIndicatorService, self).setUp()
319+ super().setUp()
192 if self.ensure_not_running:
320 if self.ensure_not_running:
193 self.ensure_service_not_running()
321 self.ensure_service_not_running()
194 self.addCleanup(self.stop_service)
322 self.addCleanup(self.stop_service)
tests/autopilot/unity8/indicators/tests/test_action_latency.py+4−2
@@ -70,10 +70,11 @@ class TestServerValueUpdate(TestIndicatorBaseTestCase):
70 switch_menu = self.indicator_page.get_switch_menu()
70 switch_menu = self.indicator_page.get_switch_menu()
71
71
72 switch.change_state()
72 switch.change_state()
73+ final_value = switch.checked
73
74
74 self.assertThat(
75 self.assertThat(
75 switch_menu.serverChecked,
76 switch_menu.serverChecked,
76− Eventually(Equals(switch.checked), timeout=20)
77+ Eventually(Equals(final_value), timeout=20)
77 )
78 )
78
79
79 def test_slider_reaches_server_value(self):
80 def test_slider_reaches_server_value(self):
@@ -82,6 +83,7 @@ class TestServerValueUpdate(TestIndicatorBaseTestCase):
82
83
83 old_value = slider.value
84 old_value = slider.value
84 slider.slide_left()
85 slider.slide_left()
86+ final_value = slider.value
85
87
86 self.assertThat(
88 self.assertThat(
87 slider_menu.serverValue,
89 slider_menu.serverValue,
@@ -90,7 +92,7 @@ class TestServerValueUpdate(TestIndicatorBaseTestCase):
90
92
91 self.assertThat(
93 self.assertThat(
92 slider_menu.serverValue,
94 slider_menu.serverValue,
93− Eventually(Equals(slider.value), timeout=20)
95+ Eventually(Equals(final_value), timeout=20)
94 )
96 )
95
97
96
98
tests/autopilot/unity8/indicators/tests/test_display_indicator.py+1−1
@@ -18,7 +18,7 @@
18
18
19from unity8 import (
19from unity8 import (
20 fixture_setup,
20 fixture_setup,
21− indicators,
21+ indicators
22)
22)
23from unity8.indicators import tests
23from unity8.indicators import tests
24
24
tests/autopilot/unity8/process_helpers.py+1−3
@@ -40,7 +40,6 @@ def unlock_unity():
40 """Helper function that attempts to unlock the unity greeter.
40 """Helper function that attempts to unlock the unity greeter.
41
41
42 """
42 """
43−
44 greeter.wait_for_greeter()
43 greeter.wait_for_greeter()
45 greeter.hide_greeter_with_dbus()
44 greeter.hide_greeter_with_dbus()
46
45
@@ -49,7 +48,6 @@ def lock_unity():
49 """Helper function that attempts to lock unity greeter.
48 """Helper function that attempts to lock unity greeter.
50
49
51 """
50 """
52−
53 greeter.show_greeter_with_dbus()
51 greeter.show_greeter_with_dbus()
54 greeter.wait_for_greeter()
52 greeter.wait_for_greeter()
55
53
@@ -177,7 +175,7 @@ def _get_unity_status():
177 raise CannotAccessUnity(str(error))
175 raise CannotAccessUnity(str(error))
178
176
179
177
180−def _get_unity_pid():
178+def get_unity_pid():
181 try:
179 try:
182 return get_job_pid('unity8')
180 return get_job_pid('unity8')
183 except JobError as error:
181 except JobError as error:
tests/autopilot/unity8/sensors.pynew file+93
@@ -0,0 +1,93 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2015 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+"""Control module for event injection to the fake/test platform sensors."""
21+
22+from unity8 import process_helpers
23+
24+
25+class FakePlatformSensors:
26+
27+ def __init__(self, pid=None):
28+ self.pid = pid or process_helpers.get_unity_pid()
29+
30+ def set_orientation(self, action):
31+ if action == 'top_up':
32+ with open("/tmp/sensor-fifo-{0}".format(self.pid), "w") as fifo:
33+ fifo.write("70 accel -10.050858 -0.598550 0.756568\n")
34+ fifo.write("70 accel -9.797073 -0.555455 1.019930\n")
35+ fifo.write("70 accel -10.141838 -0.770933 0.632069\n")
36+ fifo.write("70 accel -12.057199 -1.259350 1.690306\n")
37+ fifo.write("70 accel -19.282900 -3.926491 3.098097\n")
38+ fifo.write("70 accel -14.480132 -14.269443 1.216254\n")
39+ fifo.write("70 accel 16.419436 4.242526 -7.714118\n")
40+ fifo.write("70 accel 5.583278 8.279149 -1.848324\n")
41+ fifo.write("70 accel 1.422156 8.547300 0.416591\n")
42+ fifo.write("70 accel 4.357447 9.988609 -0.110133\n")
43+ fifo.write("70 accel 0.699107 9.840169 0.756568\n")
44+ fifo.write("70 accel 1.364695 9.844957 -0.287304\n")
45+ fifo.flush()
46+ elif action == 'top_down':
47+ with open("/tmp/sensor-fifo-{0}".format(self.pid), "w") as fifo:
48+ fifo.write("70 accel -10.050858 -0.598550 0.756568\n")
49+ fifo.write("70 accel 9.538500 -0.603339 1.292869\n")
50+ fifo.write("70 accel 9.485827 -0.636858 1.422156\n")
51+ fifo.write("70 accel 9.677363 -0.402226 1.374272\n")
52+ fifo.write("70 accel 9.303867 -0.507571 1.283292\n")
53+ fifo.write("70 accel 8.604761 -1.015141 1.436521\n")
54+ fifo.write("70 accel 7.580042 -2.001553 0.521936\n")
55+ fifo.write("70 accel 7.503428 -4.247314 0.502782\n")
56+ fifo.write("70 accel 7.067683 -7.240066 0.842759\n")
57+ fifo.write("70 accel 6.488286 -9.873688 -0.541090\n")
58+ fifo.write("70 accel 6.229713 -9.241618 -1.048660\n")
59+ fifo.write("70 accel 4.046201 -9.198523 -0.057461\n")
60+ fifo.write("70 accel 2.398990 -9.629479 0.957681\n")
61+ fifo.write("70 accel 1.632846 -9.361329 -0.311246\n")
62+ fifo.write("70 accel -0.181959 -9.696517 -0.301669\n")
63+ fifo.flush()
64+ elif action == 'left_up':
65+ with open("/tmp/sensor-fifo-{0}".format(self.pid), "w") as fifo:
66+ fifo.write("70 accel -10.050858 -0.598550 0.756568\n")
67+ fifo.write("70 accel 0.196325 9.878476 0.948104\n")
68+ fifo.write("70 accel 0.258574 9.955091 1.091756\n")
69+ fifo.write("70 accel 0.287304 10.041282 1.134852\n")
70+ fifo.write("70 accel 1.537078 10.553641 1.561020\n")
71+ fifo.write("70 accel 8.130709 10.093954 2.561796\n")
72+ fifo.write("70 accel -0.229843 5.348647 1.723825\n")
73+ fifo.write("70 accel -9.916783 0.488417 -3.418920\n")
74+ fifo.write("70 accel -13.417107 -0.416591 -2.360683\n")
75+ fifo.write("70 accel -13.872005 -2.049437 -0.574608\n")
76+ fifo.flush()
77+ elif action == 'right_up':
78+ with open("/tmp/sensor-fifo-{0}".format(self.pid), "w") as fifo:
79+ fifo.write("70 accel -10.050858 -0.598550 0.756568\n")
80+ fifo.write("70 accel -4.550858 -0.598550 0.856568\n")
81+ fifo.write("70 accel -0.799663 9.988609 1.197101\n")
82+ fifo.write("70 accel -0.861913 9.864111 1.066701\n")
83+ fifo.write("70 accel -0.861913 9.864111 0.866701\n")
84+ fifo.write("70 accel -1.776498 9.830592 1.273715\n")
85+ fifo.write("70 accel -2.376498 9.830592 1.273715\n")
86+ fifo.write("70 accel -13.158532 2.217031 1.091756\n")
87+ fifo.write("70 accel 5.056554 1.067814 0.799663\n")
88+ fifo.write("70 accel 5.056554 1.767814 0.799663\n")
89+ fifo.write("70 accel 14.882358 2.896984 1.221043\n")
90+ fifo.write("70 accel 9.466674 -0.363919 -1.029507\n")
91+ fifo.write("70 accel 11.253524 -0.186748 -0.311246\n")
92+ fifo.write("70 accel 12.253524 -0.186748 -0.311246\n")
93+ fifo.flush()
tests/autopilot/unity8/shell/emulators/main_window.py+12
@@ -169,6 +169,18 @@ class QQuickView(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
169 objectName='pinPadButton{}'.format(button_id)
169 objectName='pinPadButton{}'.format(button_id)
170 )
170 )
171
171
172+ def get_shell_orientation_angle(self):
173+ return self._get_shell().orientationAngle
174+
175+ def get_shell_orientation(self):
176+ return self._get_shell().orientation
177+
178+ def get_shell_primary_orientation(self):
179+ return self._get_shell().primaryOrientation
180+
181+ def get_shell_native_orientation(self):
182+ return self._get_shell().nativeOrientation
183+
172 @autopilot_logging.log_action(logger.info)
184 @autopilot_logging.log_action(logger.info)
173 def wait_for_notification(self):
185 def wait_for_notification(self):
174 """Wait for a notification dialog to appear.
186 """Wait for a notification dialog to appear.
tests/autopilot/unity8/shell/tests/test_rotation.pynew file+113
@@ -0,0 +1,113 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2015 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+"""Tests for shell-rotation"""
21+
22+from autopilot.platform import model
23+from unity8 import (
24+ fixture_setup,
25+ process_helpers
26+)
27+from unity8.shell import tests
28+import logging
29+from testtools.matchers import Equals
30+from autopilot.matchers import Eventually
31+
32+logger = logging.getLogger(__name__)
33+
34+
35+class RotationBase(tests.UnityTestCase):
36+ """Base class for all shell-rotation tests that provides helper methods."""
37+
38+ def setUp(self):
39+ if model() == 'Desktop':
40+ self.skipTest('Test cannot be run on the desktop.')
41+ super().setUp()
42+ self._qml_mock_enabled = False
43+ self._data_dirs_mock_enabled = False
44+
45+ def _assert_change_of_orientation_and_angle(self):
46+ self.assertThat(self.shell_proxy.orientation,
47+ Eventually(Equals(self.orientation)))
48+ self.assertThat(self.shell_proxy.orientationAngle,
49+ Eventually(Equals(self.angle)))
50+
51+
52+class TestFakeSensor(RotationBase):
53+ scenarios = [('top up', {'action': 'top_up', 'orientation': 1}),
54+ ('right up', {'action': 'right_up', 'orientation': 8}),
55+ ('top down', {'action': 'top_down', 'orientation': 4}),
56+ ('left up', {'action': 'left_up', 'orientation': 2})]
57+
58+ def test_fake_sensor(self):
59+ unity_with_sensors = fixture_setup.LaunchUnityWithFakeSensors()
60+ self.useFixture(unity_with_sensors)
61+ process_helpers.unlock_unity(unity_with_sensors.unity_proxy)
62+ fake_sensors = unity_with_sensors.fake_sensors
63+ o_proxy = unity_with_sensors.main_win.select_single('OrientedShell')
64+
65+ fake_sensors.set_orientation(self.action)
66+ self.assertThat(o_proxy.physicalOrientation,
67+ Eventually(Equals(self.orientation), timeout=15))
68+
69+
70+class TestRotationWithApp(RotationBase):
71+ scenarios = [
72+ ('top up, angle 0',
73+ {'action': 'top_up', 'orientation': 1, 'angle': 0}),
74+ ('right up, angle 90',
75+ {'action': 'right_up', 'orientation': 8, 'angle': 90}),
76+ ('top down, angle 180',
77+ {'action': 'top_down', 'orientation': 4, 'angle': 180}),
78+ ('left up, angle 270',
79+ {'action': 'left_up', 'orientation': 2, 'angle': 270})]
80+
81+ def test_rotation_with_webbrowser_app(self):
82+ """Do an orientation-change and verify that an app and the shell
83+ adapted correctly"""
84+
85+ unity_with_sensors = fixture_setup.LaunchUnityWithFakeSensors()
86+ self.useFixture(unity_with_sensors)
87+ process_helpers.unlock_unity(unity_with_sensors.unity_proxy)
88+ fake_sensors = unity_with_sensors.fake_sensors
89+ o_proxy = unity_with_sensors.main_win.select_single('OrientedShell')
90+ self.shell_proxy = unity_with_sensors.main_win.select_single('Shell')
91+
92+ # launch an application
93+ self.launch_upstart_application('webbrowser-app')
94+ unity_with_sensors.main_win.show_dash_from_launcher()
95+ unity_with_sensors.main_win.launch_application('webbrowser-app')
96+
97+ # skip test early, if device doesn't support a certain orientation
98+ if not (self.shell_proxy.orientation & o_proxy.supportedOrientations):
99+ self.skipTest('unsupported orientation ' + self.action)
100+
101+ self.assertThat(
102+ unity_with_sensors.main_win.get_current_focused_app_id(),
103+ Eventually(Equals('webbrowser-app')))
104+
105+ # get default orientation and angle
106+ self.orientation = self.shell_proxy.orientation
107+ self.angle = self.shell_proxy.orientationAngle
108+
109+ # check if fake sensors affect orientation and angle
110+ fake_sensors.set_orientation(self.action)
111+ self.assertThat(o_proxy.physicalOrientation,
112+ Eventually(Equals(self.orientation), timeout=15))
113+ self._assert_change_of_orientation_and_angle()
tests/libs/UbuntuGestures/tst_TouchRegistry.cpp+75−76
@@ -53,8 +53,8 @@ private Q_SLOTS:
53 void initTestCase() {} // will be called before the first test function is executed
53 void initTestCase() {} // will be called before the first test function is executed
54 void cleanupTestCase() {} // will be called after the last test function was executed.
54 void cleanupTestCase() {} // will be called after the last test function was executed.
55
55
56− void init() {} // called right before each and every test function is executed
56+ void init(); // called right before each and every test function is executed
57− void cleanup() {} // called right after each and every test function is executed
57+ void cleanup(); // called right after each and every test function is executed
58
58
59 void requestWithNoCandidates();
59 void requestWithNoCandidates();
60 void lateCandidateRequestGetsNothing();
60 void lateCandidateRequestGetsNothing();
@@ -67,11 +67,23 @@ private Q_SLOTS:
67 void rejectingTouchfterItsEnd();
67 void rejectingTouchfterItsEnd();
68 void removeOldUndecidedCandidates();
68 void removeOldUndecidedCandidates();
69 void interimOwnerWontGetUnownedTouchEvents();
69 void interimOwnerWontGetUnownedTouchEvents();
70+
71+private:
72+ TouchRegistry *touchRegistry;
70};
73};
71
74
75+void tst_TouchRegistry::init()
76+{
77+ touchRegistry = TouchRegistry::instance();
78+}
79+
80+void tst_TouchRegistry::cleanup()
81+{
82+ delete touchRegistry;
83+}
84+
72void tst_TouchRegistry::requestWithNoCandidates()
85void tst_TouchRegistry::requestWithNoCandidates()
73{
86{
74− TouchRegistry touchRegistry;
75 DummyCandidate candidate;
87 DummyCandidate candidate;
76
88
77 {
89 {
@@ -83,17 +95,16 @@ void tst_TouchRegistry::requestWithNoCandidates()
83 Qt::NoModifier,
95 Qt::NoModifier,
84 Qt::TouchPointPressed,
96 Qt::TouchPointPressed,
85 touchPoints);
97 touchPoints);
86− touchRegistry.update(&touchEvent);
98+ touchRegistry->update(&touchEvent);
87 }
99 }
88
100
89− touchRegistry.requestTouchOwnership(0, &candidate);
101+ touchRegistry->requestTouchOwnership(0, &candidate);
90
102
91 QVERIFY(candidate.ownedTouches.contains(0));
103 QVERIFY(candidate.ownedTouches.contains(0));
92}
104}
93
105
94void tst_TouchRegistry::lateCandidateRequestGetsNothing()
106void tst_TouchRegistry::lateCandidateRequestGetsNothing()
95{
107{
96− TouchRegistry touchRegistry;
97 DummyCandidate earlyCandidate;
108 DummyCandidate earlyCandidate;
98 earlyCandidate.setObjectName("early");
109 earlyCandidate.setObjectName("early");
99 DummyCandidate lateCandidate;
110 DummyCandidate lateCandidate;
@@ -108,21 +119,21 @@ void tst_TouchRegistry::lateCandidateRequestGetsNothing()
108 Qt::NoModifier,
119 Qt::NoModifier,
109 Qt::TouchPointPressed,
120 Qt::TouchPointPressed,
110 touchPoints);
121 touchPoints);
111− touchRegistry.update(&touchEvent);
122+ touchRegistry->update(&touchEvent);
112 }
123 }
113
124
114− touchRegistry.addCandidateOwnerForTouch(0, &earlyCandidate);
125+ touchRegistry->addCandidateOwnerForTouch(0, &earlyCandidate);
115− touchRegistry.addCandidateOwnerForTouch(0, &lateCandidate);
126+ touchRegistry->addCandidateOwnerForTouch(0, &lateCandidate);
116
127
117 QVERIFY(earlyCandidate.ownedTouches.isEmpty());
128 QVERIFY(earlyCandidate.ownedTouches.isEmpty());
118 QVERIFY(lateCandidate.ownedTouches.isEmpty());
129 QVERIFY(lateCandidate.ownedTouches.isEmpty());
119
130
120− touchRegistry.requestTouchOwnership(0, &lateCandidate);
131+ touchRegistry->requestTouchOwnership(0, &lateCandidate);
121
132
122 QVERIFY(earlyCandidate.ownedTouches.isEmpty());
133 QVERIFY(earlyCandidate.ownedTouches.isEmpty());
123 QVERIFY(lateCandidate.ownedTouches.isEmpty());
134 QVERIFY(lateCandidate.ownedTouches.isEmpty());
124
135
125− touchRegistry.requestTouchOwnership(0, &earlyCandidate);
136+ touchRegistry->requestTouchOwnership(0, &earlyCandidate);
126
137
127 QVERIFY(earlyCandidate.ownedTouches.contains(0));
138 QVERIFY(earlyCandidate.ownedTouches.contains(0));
128 QVERIFY(lateCandidate.ownedTouches.isEmpty());
139 QVERIFY(lateCandidate.ownedTouches.isEmpty());
@@ -130,7 +141,6 @@ void tst_TouchRegistry::lateCandidateRequestGetsNothing()
130
141
131void tst_TouchRegistry::lateCandidateGestOwnershipOnceEarlyCandidateQuits()
142void tst_TouchRegistry::lateCandidateGestOwnershipOnceEarlyCandidateQuits()
132{
143{
133− TouchRegistry touchRegistry;
134 DummyCandidate earlyCandidate;
144 DummyCandidate earlyCandidate;
135 DummyCandidate lateCandidate;
145 DummyCandidate lateCandidate;
136
146
@@ -143,21 +153,21 @@ void tst_TouchRegistry::lateCandidateGestOwnershipOnceEarlyCandidateQuits()
143 Qt::NoModifier,
153 Qt::NoModifier,
144 Qt::TouchPointPressed,
154 Qt::TouchPointPressed,
145 touchPoints);
155 touchPoints);
146− touchRegistry.update(&touchEvent);
156+ touchRegistry->update(&touchEvent);
147 }
157 }
148
158
149− touchRegistry.addCandidateOwnerForTouch(0, &earlyCandidate);
159+ touchRegistry->addCandidateOwnerForTouch(0, &earlyCandidate);
150− touchRegistry.addCandidateOwnerForTouch(0, &lateCandidate);
160+ touchRegistry->addCandidateOwnerForTouch(0, &lateCandidate);
151
161
152 QVERIFY(earlyCandidate.ownedTouches.isEmpty());
162 QVERIFY(earlyCandidate.ownedTouches.isEmpty());
153 QVERIFY(lateCandidate.ownedTouches.isEmpty());
163 QVERIFY(lateCandidate.ownedTouches.isEmpty());
154
164
155− touchRegistry.requestTouchOwnership(0, &lateCandidate);
165+ touchRegistry->requestTouchOwnership(0, &lateCandidate);
156
166
157 QVERIFY(earlyCandidate.ownedTouches.isEmpty());
167 QVERIFY(earlyCandidate.ownedTouches.isEmpty());
158 QVERIFY(lateCandidate.ownedTouches.isEmpty());
168 QVERIFY(lateCandidate.ownedTouches.isEmpty());
159
169
160− touchRegistry.removeCandidateOwnerForTouch(0, &earlyCandidate);
170+ touchRegistry->removeCandidateOwnerForTouch(0, &earlyCandidate);
161
171
162 QVERIFY(earlyCandidate.ownedTouches.isEmpty());
172 QVERIFY(earlyCandidate.ownedTouches.isEmpty());
163 QVERIFY(lateCandidate.ownedTouches.contains(0));
173 QVERIFY(lateCandidate.ownedTouches.contains(0));
@@ -165,7 +175,6 @@ void tst_TouchRegistry::lateCandidateGestOwnershipOnceEarlyCandidateQuits()
165
175
166void tst_TouchRegistry::dispatchesTouchEventsToCandidates()
176void tst_TouchRegistry::dispatchesTouchEventsToCandidates()
167{
177{
168− TouchRegistry touchRegistry;
169 QQuickItem rootItem;
178 QQuickItem rootItem;
170
179
171 DummyCandidate candidate0;
180 DummyCandidate candidate0;
@@ -190,10 +199,10 @@ void tst_TouchRegistry::dispatchesTouchEventsToCandidates()
190 Qt::NoModifier,
199 Qt::NoModifier,
191 Qt::TouchPointPressed,
200 Qt::TouchPointPressed,
192 touchPoints);
201 touchPoints);
193− touchRegistry.update(&touchEvent);
202+ touchRegistry->update(&touchEvent);
194 }
203 }
195
204
196− touchRegistry.addCandidateOwnerForTouch(0, &candidate0);
205+ touchRegistry->addCandidateOwnerForTouch(0, &candidate0);
197
206
198 {
207 {
199 QList<QTouchEvent::TouchPoint> touchPoints;
208 QList<QTouchEvent::TouchPoint> touchPoints;
@@ -208,7 +217,7 @@ void tst_TouchRegistry::dispatchesTouchEventsToCandidates()
208 Qt::NoModifier,
217 Qt::NoModifier,
209 Qt::TouchPointPressed | Qt::TouchPointMoved,
218 Qt::TouchPointPressed | Qt::TouchPointMoved,
210 touchPoints);
219 touchPoints);
211− touchRegistry.update(&touchEvent);
220+ touchRegistry->update(&touchEvent);
212 }
221 }
213
222
214 // candidate0 should have received an update on the touch he's interested on.
223 // candidate0 should have received an update on the touch he's interested on.
@@ -220,7 +229,7 @@ void tst_TouchRegistry::dispatchesTouchEventsToCandidates()
220 QCOMPARE(candidate0.unownedTouchEvents[0].touchPoints[0].rect().x(), 11 - candidate0.x());
229 QCOMPARE(candidate0.unownedTouchEvents[0].touchPoints[0].rect().x(), 11 - candidate0.x());
221 QCOMPARE(candidate0.unownedTouchEvents[0].touchPoints[0].rect().y(), 11 - candidate0.y());
230 QCOMPARE(candidate0.unownedTouchEvents[0].touchPoints[0].rect().y(), 11 - candidate0.y());
222
231
223− touchRegistry.addCandidateOwnerForTouch(1, &candidate1);
232+ touchRegistry->addCandidateOwnerForTouch(1, &candidate1);
224
233
225 {
234 {
226 QList<QTouchEvent::TouchPoint> touchPoints;
235 QList<QTouchEvent::TouchPoint> touchPoints;
@@ -235,7 +244,7 @@ void tst_TouchRegistry::dispatchesTouchEventsToCandidates()
235 Qt::NoModifier,
244 Qt::NoModifier,
236 Qt::TouchPointPressed | Qt::TouchPointMoved,
245 Qt::TouchPointPressed | Qt::TouchPointMoved,
237 touchPoints);
246 touchPoints);
238− touchRegistry.update(&touchEvent);
247+ touchRegistry->update(&touchEvent);
239 }
248 }
240
249
241 // candidate0 gets updates only for touch 0 and
250 // candidate0 gets updates only for touch 0 and
@@ -252,7 +261,6 @@ void tst_TouchRegistry::dispatchesTouchEventsToCandidates()
252
261
253void tst_TouchRegistry::dispatchesTouchEventsToWatchers()
262void tst_TouchRegistry::dispatchesTouchEventsToWatchers()
254{
263{
255− TouchRegistry touchRegistry;
256 QQuickItem rootItem;
264 QQuickItem rootItem;
257
265
258 DummyCandidate watcher;
266 DummyCandidate watcher;
@@ -271,10 +279,10 @@ void tst_TouchRegistry::dispatchesTouchEventsToWatchers()
271 Qt::NoModifier,
279 Qt::NoModifier,
272 Qt::TouchPointPressed,
280 Qt::TouchPointPressed,
273 touchPoints);
281 touchPoints);
274− touchRegistry.update(&touchEvent);
282+ touchRegistry->update(&touchEvent);
275 }
283 }
276
284
277− touchRegistry.addTouchWatcher(0, &watcher);
285+ touchRegistry->addTouchWatcher(0, &watcher);
278
286
279 {
287 {
280 QList<QTouchEvent::TouchPoint> touchPoints;
288 QList<QTouchEvent::TouchPoint> touchPoints;
@@ -289,7 +297,7 @@ void tst_TouchRegistry::dispatchesTouchEventsToWatchers()
289 Qt::NoModifier,
297 Qt::NoModifier,
290 Qt::TouchPointPressed | Qt::TouchPointMoved,
298 Qt::TouchPointPressed | Qt::TouchPointMoved,
291 touchPoints);
299 touchPoints);
292− touchRegistry.update(&touchEvent);
300+ touchRegistry->update(&touchEvent);
293 }
301 }
294
302
295 // watcher should have received an update on the touch he's interested on.
303 // watcher should have received an update on the touch he's interested on.
@@ -314,7 +322,7 @@ void tst_TouchRegistry::dispatchesTouchEventsToWatchers()
314 Qt::NoModifier,
322 Qt::NoModifier,
315 Qt::TouchPointPressed | Qt::TouchPointMoved,
323 Qt::TouchPointPressed | Qt::TouchPointMoved,
316 touchPoints);
324 touchPoints);
317− touchRegistry.update(&touchEvent);
325+ touchRegistry->update(&touchEvent);
318 }
326 }
319
327
320 // watcher gets updates only for touch 0
328 // watcher gets updates only for touch 0
@@ -326,7 +334,6 @@ void tst_TouchRegistry::dispatchesTouchEventsToWatchers()
326
334
327void tst_TouchRegistry::keepDispatchingToWatchersAfterLastCandidateGivesUp()
335void tst_TouchRegistry::keepDispatchingToWatchersAfterLastCandidateGivesUp()
328{
336{
329− TouchRegistry touchRegistry;
330 DummyCandidate item;
337 DummyCandidate item;
331
338
332 {
339 {
@@ -338,10 +345,10 @@ void tst_TouchRegistry::keepDispatchingToWatchersAfterLastCandidateGivesUp()
338 Qt::NoModifier,
345 Qt::NoModifier,
339 Qt::TouchPointPressed,
346 Qt::TouchPointPressed,
340 touchPoints);
347 touchPoints);
341− touchRegistry.update(&touchEvent);
348+ touchRegistry->update(&touchEvent);
342 }
349 }
343
350
344− touchRegistry.addCandidateOwnerForTouch(0, &item);
351+ touchRegistry->addCandidateOwnerForTouch(0, &item);
345
352
346 {
353 {
347 QList<QTouchEvent::TouchPoint> touchPoints;
354 QList<QTouchEvent::TouchPoint> touchPoints;
@@ -354,7 +361,7 @@ void tst_TouchRegistry::keepDispatchingToWatchersAfterLastCandidateGivesUp()
354 Qt::NoModifier,
361 Qt::NoModifier,
355 Qt::TouchPointPressed | Qt::TouchPointMoved,
362 Qt::TouchPointPressed | Qt::TouchPointMoved,
356 touchPoints);
363 touchPoints);
357− touchRegistry.update(&touchEvent);
364+ touchRegistry->update(&touchEvent);
358 }
365 }
359
366
360 QCOMPARE(item.unownedTouchEvents.count(), 1);
367 QCOMPARE(item.unownedTouchEvents.count(), 1);
@@ -362,7 +369,7 @@ void tst_TouchRegistry::keepDispatchingToWatchersAfterLastCandidateGivesUp()
362 QCOMPARE(item.unownedTouchEvents[0].touchPoints[0].id(), 0);
369 QCOMPARE(item.unownedTouchEvents[0].touchPoints[0].id(), 0);
363 item.unownedTouchEvents.clear();
370 item.unownedTouchEvents.clear();
364
371
365− touchRegistry.addTouchWatcher(1, &item);
372+ touchRegistry->addTouchWatcher(1, &item);
366
373
367 {
374 {
368 QList<QTouchEvent::TouchPoint> touchPoints;
375 QList<QTouchEvent::TouchPoint> touchPoints;
@@ -375,7 +382,7 @@ void tst_TouchRegistry::keepDispatchingToWatchersAfterLastCandidateGivesUp()
375 Qt::NoModifier,
382 Qt::NoModifier,
376 Qt::TouchPointMoved,
383 Qt::TouchPointMoved,
377 touchPoints);
384 touchPoints);
378− touchRegistry.update(&touchEvent);
385+ touchRegistry->update(&touchEvent);
379 }
386 }
380
387
381 QCOMPARE(item.unownedTouchEvents.count(), 1);
388 QCOMPARE(item.unownedTouchEvents.count(), 1);
@@ -395,7 +402,7 @@ void tst_TouchRegistry::keepDispatchingToWatchersAfterLastCandidateGivesUp()
395 Qt::NoModifier,
402 Qt::NoModifier,
396 Qt::TouchPointReleased | Qt::TouchPointMoved,
403 Qt::TouchPointReleased | Qt::TouchPointMoved,
397 touchPoints);
404 touchPoints);
398− touchRegistry.update(&touchEvent);
405+ touchRegistry->update(&touchEvent);
399 }
406 }
400
407
401 QCOMPARE(item.unownedTouchEvents.count(), 1);
408 QCOMPARE(item.unownedTouchEvents.count(), 1);
@@ -404,7 +411,7 @@ void tst_TouchRegistry::keepDispatchingToWatchersAfterLastCandidateGivesUp()
404 QVERIFY(item.unownedTouchEvents[0].containsTouchWithId(1));
411 QVERIFY(item.unownedTouchEvents[0].containsTouchWithId(1));
405 item.unownedTouchEvents.clear();
412 item.unownedTouchEvents.clear();
406
413
407− touchRegistry.removeCandidateOwnerForTouch(0, &item);
414+ touchRegistry->removeCandidateOwnerForTouch(0, &item);
408
415
409 {
416 {
410 QList<QTouchEvent::TouchPoint> touchPoints;
417 QList<QTouchEvent::TouchPoint> touchPoints;
@@ -415,7 +422,7 @@ void tst_TouchRegistry::keepDispatchingToWatchersAfterLastCandidateGivesUp()
415 Qt::NoModifier,
422 Qt::NoModifier,
416 Qt::TouchPointReleased,
423 Qt::TouchPointReleased,
417 touchPoints);
424 touchPoints);
418− touchRegistry.update(&touchEvent);
425+ touchRegistry->update(&touchEvent);
419 }
426 }
420
427
421 QCOMPARE(item.unownedTouchEvents.count(), 1);
428 QCOMPARE(item.unownedTouchEvents.count(), 1);
@@ -423,7 +430,7 @@ void tst_TouchRegistry::keepDispatchingToWatchersAfterLastCandidateGivesUp()
423 QVERIFY(item.unownedTouchEvents[0].containsTouchWithId(1));
430 QVERIFY(item.unownedTouchEvents[0].containsTouchWithId(1));
424 item.unownedTouchEvents.clear();
431 item.unownedTouchEvents.clear();
425
432
426− QVERIFY(touchRegistry.m_touchInfoPool.isEmpty());
433+ QVERIFY(touchRegistry->m_touchInfoPool.isEmpty());
427}
434}
428
435
429/*
436/*
@@ -432,7 +439,6 @@ void tst_TouchRegistry::keepDispatchingToWatchersAfterLastCandidateGivesUp()
432 */
439 */
433void tst_TouchRegistry::candidatesAndWatchers_1()
440void tst_TouchRegistry::candidatesAndWatchers_1()
434{
441{
435− TouchRegistry touchRegistry;
436 DummyCandidate item;
442 DummyCandidate item;
437
443
438 {
444 {
@@ -444,10 +450,10 @@ void tst_TouchRegistry::candidatesAndWatchers_1()
444 Qt::NoModifier,
450 Qt::NoModifier,
445 Qt::TouchPointPressed,
451 Qt::TouchPointPressed,
446 touchPoints);
452 touchPoints);
447− touchRegistry.update(&touchEvent);
453+ touchRegistry->update(&touchEvent);
448 }
454 }
449
455
450− touchRegistry.addCandidateOwnerForTouch(0, &item);
456+ touchRegistry->addCandidateOwnerForTouch(0, &item);
451
457
452 {
458 {
453 QList<QTouchEvent::TouchPoint> touchPoints;
459 QList<QTouchEvent::TouchPoint> touchPoints;
@@ -460,14 +466,14 @@ void tst_TouchRegistry::candidatesAndWatchers_1()
460 Qt::NoModifier,
466 Qt::NoModifier,
461 Qt::TouchPointPressed | Qt::TouchPointMoved,
467 Qt::TouchPointPressed | Qt::TouchPointMoved,
462 touchPoints);
468 touchPoints);
463− touchRegistry.update(&touchEvent);
469+ touchRegistry->update(&touchEvent);
464 }
470 }
465
471
466− touchRegistry.addTouchWatcher(1, &item);
472+ touchRegistry->addTouchWatcher(1, &item);
467
473
468− touchRegistry.removeCandidateOwnerForTouch(0, &item);
474+ touchRegistry->removeCandidateOwnerForTouch(0, &item);
469
475
470− touchRegistry.addTouchWatcher(0, &item);
476+ touchRegistry->addTouchWatcher(0, &item);
471
477
472 {
478 {
473 QList<QTouchEvent::TouchPoint> touchPoints;
479 QList<QTouchEvent::TouchPoint> touchPoints;
@@ -480,7 +486,7 @@ void tst_TouchRegistry::candidatesAndWatchers_1()
480 Qt::NoModifier,
486 Qt::NoModifier,
481 Qt::TouchPointReleased | Qt::TouchPointMoved,
487 Qt::TouchPointReleased | Qt::TouchPointMoved,
482 touchPoints);
488 touchPoints);
483− touchRegistry.update(&touchEvent);
489+ touchRegistry->update(&touchEvent);
484 }
490 }
485
491
486 {
492 {
@@ -492,10 +498,10 @@ void tst_TouchRegistry::candidatesAndWatchers_1()
492 Qt::NoModifier,
498 Qt::NoModifier,
493 Qt::TouchPointReleased,
499 Qt::TouchPointReleased,
494 touchPoints);
500 touchPoints);
495− touchRegistry.update(&touchEvent);
501+ touchRegistry->update(&touchEvent);
496 }
502 }
497
503
498− QVERIFY(touchRegistry.m_touchInfoPool.isEmpty());
504+ QVERIFY(touchRegistry->m_touchInfoPool.isEmpty());
499
505
500 item.unownedTouchEvents.clear();
506 item.unownedTouchEvents.clear();
501
507
@@ -508,7 +514,7 @@ void tst_TouchRegistry::candidatesAndWatchers_1()
508 Qt::NoModifier,
514 Qt::NoModifier,
509 Qt::TouchPointPressed,
515 Qt::TouchPointPressed,
510 touchPoints);
516 touchPoints);
511− touchRegistry.update(&touchEvent);
517+ touchRegistry->update(&touchEvent);
512 }
518 }
513
519
514 // Haven't made any subscription for that new touch 0.
520 // Haven't made any subscription for that new touch 0.
@@ -521,8 +527,6 @@ void tst_TouchRegistry::candidatesAndWatchers_1()
521 */
527 */
522void tst_TouchRegistry::candidatesAndWatchers_2()
528void tst_TouchRegistry::candidatesAndWatchers_2()
523{
529{
524− TouchRegistry touchRegistry;
525−
526 DummyCandidate directionalDragArea;
530 DummyCandidate directionalDragArea;
527 directionalDragArea.setObjectName("DirectionalDragArea");
531 directionalDragArea.setObjectName("DirectionalDragArea");
528
532
@@ -539,14 +543,14 @@ void tst_TouchRegistry::candidatesAndWatchers_2()
539 Qt::NoModifier,
543 Qt::NoModifier,
540 Qt::TouchPointPressed,
544 Qt::TouchPointPressed,
541 touchPoints);
545 touchPoints);
542− touchRegistry.update(&touchEvent);
546+ touchRegistry->update(&touchEvent);
543 }
547 }
544
548
545 // [TouchRegistry] addCandidateOwnerForTouch id 0 candidate DirectionalDragArea
549 // [TouchRegistry] addCandidateOwnerForTouch id 0 candidate DirectionalDragArea
546− touchRegistry.addCandidateOwnerForTouch(0, &directionalDragArea);
550+ touchRegistry->addCandidateOwnerForTouch(0, &directionalDragArea);
547
551
548 // [TouchRegistry] requestTouchOwnership id 0 candidate TouchGate
552 // [TouchRegistry] requestTouchOwnership id 0 candidate TouchGate
549− touchRegistry.requestTouchOwnership(0, &touchGate);
553+ touchRegistry->requestTouchOwnership(0, &touchGate);
550
554
551 //[TouchRegistry] got TouchUpdate (id:0, state:moved, scenePos:(147,1023)) (id:1, state:pressed, scenePos:(327,792))
555 //[TouchRegistry] got TouchUpdate (id:0, state:moved, scenePos:(147,1023)) (id:1, state:pressed, scenePos:(327,792))
552 {
556 {
@@ -560,24 +564,24 @@ void tst_TouchRegistry::candidatesAndWatchers_2()
560 Qt::NoModifier,
564 Qt::NoModifier,
561 Qt::TouchPointPressed | Qt::TouchPointMoved,
565 Qt::TouchPointPressed | Qt::TouchPointMoved,
562 touchPoints);
566 touchPoints);
563− touchRegistry.update(&touchEvent);
567+ touchRegistry->update(&touchEvent);
564 }
568 }
565
569
566 // [TouchRegistry] addTouchWatcher id 1 watcher DirectionalDragArea
570 // [TouchRegistry] addTouchWatcher id 1 watcher DirectionalDragArea
567− touchRegistry.addTouchWatcher(1, &directionalDragArea);
571+ touchRegistry->addTouchWatcher(1, &directionalDragArea);
568
572
569 // [TouchRegistry] removeCandidateOwnerForTouch id 0 candidate DirectionalDragArea
573 // [TouchRegistry] removeCandidateOwnerForTouch id 0 candidate DirectionalDragArea
570− touchRegistry.removeCandidateOwnerForTouch(0, &directionalDragArea);
574+ touchRegistry->removeCandidateOwnerForTouch(0, &directionalDragArea);
571
575
572 //[TouchRegistry] sending TouchWonershipEvent(id = 0 gained) to candidate TouchGate
576 //[TouchRegistry] sending TouchWonershipEvent(id = 0 gained) to candidate TouchGate
573 QCOMPARE(touchGate.ownedTouches.count(), 1);
577 QCOMPARE(touchGate.ownedTouches.count(), 1);
574 QVERIFY(touchGate.ownedTouches.contains(0));
578 QVERIFY(touchGate.ownedTouches.contains(0));
575
579
576 // [TouchRegistry] addTouchWatcher id 0 watcher DirectionalDragArea
580 // [TouchRegistry] addTouchWatcher id 0 watcher DirectionalDragArea
577− touchRegistry.addTouchWatcher(0, &directionalDragArea);
581+ touchRegistry->addTouchWatcher(0, &directionalDragArea);
578
582
579 // [TouchRegistry] requestTouchOwnership id 1 candidate TouchGate
583 // [TouchRegistry] requestTouchOwnership id 1 candidate TouchGate
580− touchRegistry.requestTouchOwnership(1, &touchGate);
584+ touchRegistry->requestTouchOwnership(1, &touchGate);
581
585
582 //[TouchRegistry] sending TouchWonershipEvent(id = 1 gained) to candidate TouchGate
586 //[TouchRegistry] sending TouchWonershipEvent(id = 1 gained) to candidate TouchGate
583 QCOMPARE(touchGate.ownedTouches.count(), 2);
587 QCOMPARE(touchGate.ownedTouches.count(), 2);
@@ -598,7 +602,7 @@ void tst_TouchRegistry::candidatesAndWatchers_2()
598 Qt::NoModifier,
602 Qt::NoModifier,
599 Qt::TouchPointMoved,
603 Qt::TouchPointMoved,
600 touchPoints);
604 touchPoints);
601− touchRegistry.update(&touchEvent);
605+ touchRegistry->update(&touchEvent);
602 }
606 }
603
607
604 //vvvvv DDA Watchers are being ignored from now on vvvvvvv
608 //vvvvv DDA Watchers are being ignored from now on vvvvvvv
@@ -624,7 +628,7 @@ void tst_TouchRegistry::candidatesAndWatchers_2()
624 Qt::NoModifier,
628 Qt::NoModifier,
625 Qt::TouchPointMoved | Qt::TouchPointReleased,
629 Qt::TouchPointMoved | Qt::TouchPointReleased,
626 touchPoints);
630 touchPoints);
627− touchRegistry.update(&touchEvent);
631+ touchRegistry->update(&touchEvent);
628 }
632 }
629
633
630 QCOMPARE(directionalDragArea.unownedTouchEvents.count(), 1);
634 QCOMPARE(directionalDragArea.unownedTouchEvents.count(), 1);
@@ -646,7 +650,7 @@ void tst_TouchRegistry::candidatesAndWatchers_2()
646 Qt::NoModifier,
650 Qt::NoModifier,
647 Qt::TouchPointReleased,
651 Qt::TouchPointReleased,
648 touchPoints);
652 touchPoints);
649− touchRegistry.update(&touchEvent);
653+ touchRegistry->update(&touchEvent);
650 }
654 }
651
655
652 QCOMPARE(directionalDragArea.unownedTouchEvents.count(), 1);
656 QCOMPARE(directionalDragArea.unownedTouchEvents.count(), 1);
@@ -658,7 +662,6 @@ void tst_TouchRegistry::candidatesAndWatchers_2()
658
662
659void tst_TouchRegistry::rejectingTouchfterItsEnd()
663void tst_TouchRegistry::rejectingTouchfterItsEnd()
660{
664{
661− TouchRegistry touchRegistry;
662 DummyCandidate earlyCandidate;
665 DummyCandidate earlyCandidate;
663 DummyCandidate lateCandidate;
666 DummyCandidate lateCandidate;
664
667
@@ -671,16 +674,16 @@ void tst_TouchRegistry::rejectingTouchfterItsEnd()
671 Qt::NoModifier,
674 Qt::NoModifier,
672 Qt::TouchPointPressed,
675 Qt::TouchPointPressed,
673 touchPoints);
676 touchPoints);
674− touchRegistry.update(&touchEvent);
677+ touchRegistry->update(&touchEvent);
675 }
678 }
676
679
677− touchRegistry.addCandidateOwnerForTouch(0, &earlyCandidate);
680+ touchRegistry->addCandidateOwnerForTouch(0, &earlyCandidate);
678− touchRegistry.addCandidateOwnerForTouch(0, &lateCandidate);
681+ touchRegistry->addCandidateOwnerForTouch(0, &lateCandidate);
679
682
680 QVERIFY(earlyCandidate.ownedTouches.isEmpty());
683 QVERIFY(earlyCandidate.ownedTouches.isEmpty());
681 QVERIFY(lateCandidate.ownedTouches.isEmpty());
684 QVERIFY(lateCandidate.ownedTouches.isEmpty());
682
685
683− touchRegistry.requestTouchOwnership(0, &lateCandidate);
686+ touchRegistry->requestTouchOwnership(0, &lateCandidate);
684
687
685 QVERIFY(earlyCandidate.ownedTouches.isEmpty());
688 QVERIFY(earlyCandidate.ownedTouches.isEmpty());
686 QVERIFY(lateCandidate.ownedTouches.isEmpty());
689 QVERIFY(lateCandidate.ownedTouches.isEmpty());
@@ -694,25 +697,25 @@ void tst_TouchRegistry::rejectingTouchfterItsEnd()
694 Qt::NoModifier,
697 Qt::NoModifier,
695 Qt::TouchPointPressed,
698 Qt::TouchPointPressed,
696 touchPoints);
699 touchPoints);
697− touchRegistry.update(&touchEvent);
700+ touchRegistry->update(&touchEvent);
698 }
701 }
699
702
700 QVERIFY(earlyCandidate.ownedTouches.isEmpty());
703 QVERIFY(earlyCandidate.ownedTouches.isEmpty());
701 QVERIFY(lateCandidate.ownedTouches.isEmpty());
704 QVERIFY(lateCandidate.ownedTouches.isEmpty());
702
705
703− touchRegistry.removeCandidateOwnerForTouch(0, &earlyCandidate);
706+ touchRegistry->removeCandidateOwnerForTouch(0, &earlyCandidate);
704
707
705 QCOMPARE(lateCandidate.ownedTouches.count(), 1);
708 QCOMPARE(lateCandidate.ownedTouches.count(), 1);
706 QCOMPARE(lateCandidate.ownedTouches.contains(0), 1);
709 QCOMPARE(lateCandidate.ownedTouches.contains(0), 1);
707
710
708 // Check that there's no trace left of touch 0 as we no longer need to keep tabs on it.
711 // Check that there's no trace left of touch 0 as we no longer need to keep tabs on it.
709− QVERIFY(!touchRegistry.findTouchInfo(0));
712+ QVERIFY(!touchRegistry->findTouchInfo(0));
710}
713}
711
714
712void tst_TouchRegistry::removeOldUndecidedCandidates()
715void tst_TouchRegistry::removeOldUndecidedCandidates()
713{
716{
714 FakeTimerFactory *fakeTimerFactory = new FakeTimerFactory;
717 FakeTimerFactory *fakeTimerFactory = new FakeTimerFactory;
715− TouchRegistry *touchRegistry = new TouchRegistry(nullptr, fakeTimerFactory);
718+ touchRegistry->setTimerFactory(fakeTimerFactory);
716
719
717 DummyCandidate undecidedCandidate;
720 DummyCandidate undecidedCandidate;
718 undecidedCandidate.setObjectName("undecided");
721 undecidedCandidate.setObjectName("undecided");
@@ -749,8 +752,6 @@ void tst_TouchRegistry::removeOldUndecidedCandidates()
749 QVERIFY(undecidedCandidate.lostTouches.contains(0));
752 QVERIFY(undecidedCandidate.lostTouches.contains(0));
750 QVERIFY(candidateThatWantsTouch.ownedTouches.contains(0));
753 QVERIFY(candidateThatWantsTouch.ownedTouches.contains(0));
751 QVERIFY(candidateThatWantsTouch.lostTouches.isEmpty());
754 QVERIFY(candidateThatWantsTouch.lostTouches.isEmpty());
752−
753− delete touchRegistry;
754}
755}
755
756
756/*
757/*
@@ -762,7 +763,7 @@ void tst_TouchRegistry::removeOldUndecidedCandidates()
762void tst_TouchRegistry::interimOwnerWontGetUnownedTouchEvents()
763void tst_TouchRegistry::interimOwnerWontGetUnownedTouchEvents()
763{
764{
764 FakeTimerFactory *fakeTimerFactory = new FakeTimerFactory;
765 FakeTimerFactory *fakeTimerFactory = new FakeTimerFactory;
765− TouchRegistry *touchRegistry = new TouchRegistry(nullptr, fakeTimerFactory);
766+ touchRegistry->setTimerFactory(fakeTimerFactory);
766
767
767 DummyCandidate undecidedCandidate;
768 DummyCandidate undecidedCandidate;
768 undecidedCandidate.setObjectName("undecided");
769 undecidedCandidate.setObjectName("undecided");
@@ -814,8 +815,6 @@ void tst_TouchRegistry::interimOwnerWontGetUnownedTouchEvents()
814
815
815 QCOMPARE(undecidedCandidate.unownedTouchEvents.count(), 2);
816 QCOMPARE(undecidedCandidate.unownedTouchEvents.count(), 2);
816 QCOMPARE(interimOwner.unownedTouchEvents.count(), 0);
817 QCOMPARE(interimOwner.unownedTouchEvents.count(), 0);
817−
818− delete touchRegistry;
819}
818}
820
819
821////////////// TouchMemento //////////
820////////////// TouchMemento //////////
tests/mocks/AccountsService/plugin.h+1−1
@@ -29,7 +29,7 @@ class AccountsServicePlugin : public QQmlExtensionPlugin
29 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
29 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
30
30
31public:
31public:
32− void registerTypes(const char *uri);
32+ void registerTypes(const char *uri) override;
33};
33};
34
34
35#endif
35#endif
tests/mocks/CMakeLists.txt+1
@@ -41,6 +41,7 @@ add_subdirectory(Ubuntu)
41add_subdirectory(Unity)
41add_subdirectory(Unity)
42add_subdirectory(QtMultimedia)
42add_subdirectory(QtMultimedia)
43add_subdirectory(Wizard)
43add_subdirectory(Wizard)
44+add_subdirectory(Utils)
44
45
45install(
46install(
46 DIRECTORY data
47 DIRECTORY data
tests/mocks/GSettings.1.0/fake_gsettings.h+2−2
@@ -78,10 +78,10 @@ public:
78 ~GSettingsControllerQml();
78 ~GSettingsControllerQml();
79
79
80 QString pictureUri() const;
80 QString pictureUri() const;
81− void setPictureUri(const QString &str);
81+ Q_INVOKABLE void setPictureUri(const QString &str);
82
82
83 QString usageMode() const;
83 QString usageMode() const;
84− void setUsageMode(const QString &usageMode);
84+ Q_INVOKABLE void setUsageMode(const QString &usageMode);
85
85
86Q_SIGNALS:
86Q_SIGNALS:
87 void pictureUriChanged(const QString&);
87 void pictureUriChanged(const QString&);
tests/mocks/GSettings.1.0/plugin.cpp+6
@@ -19,8 +19,14 @@
19
19
20#include <QtQml/qqml.h>
20#include <QtQml/qqml.h>
21
21
22+static QObject* controllerProvider(QQmlEngine* /* engine */, QJSEngine* /* scriptEngine */)
23+{
24+ return GSettingsControllerQml::instance();
25+}
26+
22void FakeGSettingsQmlPlugin::registerTypes(const char *uri)
27void FakeGSettingsQmlPlugin::registerTypes(const char *uri)
23{
28{
29+ qmlRegisterSingletonType<GSettingsControllerQml>(uri, 1, 0, "GSettingsController", controllerProvider);
24 qmlRegisterType<GSettingsQml>(uri, 1, 0, "GSettings");
30 qmlRegisterType<GSettingsQml>(uri, 1, 0, "GSettings");
25 qmlRegisterUncreatableType<GSettingsSchemaQml>(uri, 1, 0, "GSettingsSchema",
31 qmlRegisterUncreatableType<GSettingsSchemaQml>(uri, 1, 0, "GSettingsSchema",
26 "GSettingsSchema can only be used inside of a GSettings component");
32 "GSettingsSchema can only be used inside of a GSettings component");
tests/mocks/GSettings.1.0/plugin.h+1−1
@@ -25,7 +25,7 @@ class FakeGSettingsQmlPlugin : public QQmlExtensionPlugin
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26
26
27public:
27public:
28− void registerTypes(const char *uri);
28+ void registerTypes(const char *uri) override;
29};
29};
30
30
31#endif // PLUGIN_H
31#endif // PLUGIN_H
tests/mocks/LightDM/liblightdm/UsersModel.h+2−2
@@ -53,8 +53,8 @@ public:
53 BackgroundPathRole
53 BackgroundPathRole
54 };
54 };
55
55
56− int rowCount(const QModelIndex &parent) const;
56+ int rowCount(const QModelIndex &parent) const override;
57− QVariant data(const QModelIndex &index, int role) const;
57+ QVariant data(const QModelIndex &index, int role) const override;
58
58
59 QString mockMode() const;
59 QString mockMode() const;
60 void setMockMode(QString mockMode);
60 void setMockMode(QString mockMode);
tests/mocks/LightDM/plugin.h+1−1
@@ -26,7 +26,7 @@ class LightDMPlugin : public QQmlExtensionPlugin
26 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
27
27
28public:
28public:
29− void registerTypes(const char *uri);
29+ void registerTypes(const char *uri) override;
30};
30};
31
31
32#endif
32#endif
tests/mocks/Lights/plugin.h+1−1
@@ -26,7 +26,7 @@ class PowerdPlugin : public QQmlExtensionPlugin
26 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
27
27
28public:
28public:
29− void registerTypes(const char *uri);
29+ void registerTypes(const char *uri) override;
30};
30};
31
31
32#endif
32#endif
tests/mocks/MeeGo/QOfono/plugin.h+1−1
@@ -25,7 +25,7 @@ class BackendPlugin : public QQmlExtensionPlugin
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26
26
27public:
27public:
28− void registerTypes(const char *uri);
28+ void registerTypes(const char *uri) override;
29};
29};
30
30
31#endif // MOCK_QOFONO_PLUGIN_H
31#endif // MOCK_QOFONO_PLUGIN_H
tests/mocks/Powerd/plugin.h+1−1
@@ -28,7 +28,7 @@ class PowerdPlugin : public QQmlExtensionPlugin
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
29
29
30public:
30public:
31− void registerTypes(const char *uri);
31+ void registerTypes(const char *uri) override;
32};
32};
33
33
34#endif
34#endif
tests/mocks/QMenuModel/plugin.h+1−1
@@ -28,7 +28,7 @@ class QMenuModelPlugin : public QQmlExtensionPlugin
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
29
29
30public:
30public:
31− void registerTypes(const char *uri);
31+ void registerTypes(const char *uri) override;
32};
32};
33
33
34#endif
34#endif
tests/mocks/QMenuModel/unitymenumodel.h+6−6
@@ -61,12 +61,12 @@ public:
61
61
62 QString nameOwner() const;
62 QString nameOwner() const;
63
63
64− int rowCount(const QModelIndex &parent = QModelIndex()) const;
64+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
65− int columnCount(const QModelIndex &parent = QModelIndex()) const;
65+ int columnCount(const QModelIndex &parent = QModelIndex()) const override;
66− QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
66+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
67− QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const;
67+ QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const override;
68− QModelIndex parent(const QModelIndex &index) const;
68+ QModelIndex parent(const QModelIndex &index) const override;
69− QHash<int, QByteArray> roleNames() const;
69+ QHash<int, QByteArray> roleNames() const override;
70
70
71 Q_INVOKABLE QObject * submenu(int position, QQmlComponent* actionStateParser = nullptr);
71 Q_INVOKABLE QObject * submenu(int position, QQmlComponent* actionStateParser = nullptr);
72 Q_INVOKABLE bool loadExtendedAttributes(int position, const QVariantMap &schema);
72 Q_INVOKABLE bool loadExtendedAttributes(int position, const QVariantMap &schema);
tests/mocks/QtMultimedia/plugin.h+1−1
@@ -28,7 +28,7 @@ class MockQtMultimediaPlugin : public QQmlExtensionPlugin
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
29
29
30public:
30public:
31− void registerTypes(const char *uri);
31+ void registerTypes(const char *uri) override;
32};
32};
33
33
34#endif
34#endif
tests/mocks/Ubuntu/Connectivity/plugin.h+2−2
@@ -28,8 +28,8 @@ class QmlConnectivityNetworkingPlugin : public QQmlExtensionPlugin {
28 Q_INTERFACES(QQmlExtensionInterface)
28 Q_INTERFACES(QQmlExtensionInterface)
29
29
30public:
30public:
31− void registerTypes(const char *uri);
31+ void registerTypes(const char *uri) override;
32− void initializeEngine(QQmlEngine *engine, const char *uri);
32+ void initializeEngine(QQmlEngine *engine, const char *uri) override;
33};
33};
34
34
35#endif // QML_CONNECTIVITY_PLUGIN_H
35#endif // QML_CONNECTIVITY_PLUGIN_H
tests/mocks/Ubuntu/DownloadDaemonListener/plugin.h+1−1
@@ -24,7 +24,7 @@ class FakeUbuntuDownloadDaemonListenerQmlPlugin : public QQmlExtensionPlugin
24 Q_OBJECT
24 Q_OBJECT
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26public:
26public:
27− void registerTypes(const char *uri);
27+ void registerTypes(const char *uri) override;
28};
28};
29
29
30#endif
30#endif
tests/mocks/Ubuntu/Payments/plugin.h+1−1
@@ -25,7 +25,7 @@ class BackendPlugin : public QQmlExtensionPlugin
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26
26
27public:
27public:
28− void registerTypes(const char *uri);
28+ void registerTypes(const char *uri) override;
29};
29};
30
30
31#endif // PAYMENTS_PLUGIN_H
31#endif // PAYMENTS_PLUGIN_H
tests/mocks/Ubuntu/SystemImage/plugin.h+1−1
@@ -25,7 +25,7 @@ class BackendPlugin : public QQmlExtensionPlugin
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26
26
27public:
27public:
28− void registerTypes(const char *uri);
28+ void registerTypes(const char *uri) override;
29};
29};
30
30
31#endif // MOCK_SYSTEMIMAGE_PLUGIN_H
31#endif // MOCK_SYSTEMIMAGE_PLUGIN_H
tests/mocks/Ubuntu/SystemSettings/SecurityPrivacy/plugin.h+1−1
@@ -25,7 +25,7 @@ class BackendPlugin : public QQmlExtensionPlugin
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26
26
27public:
27public:
28− void registerTypes(const char *uri);
28+ void registerTypes(const char *uri) override;
29};
29};
30
30
31#endif // MOCK_SECURITYPRIVACY_PLUGIN_H
31#endif // MOCK_SECURITYPRIVACY_PLUGIN_H
tests/mocks/Ubuntu/Telephony/MockCallEntry.h+1−1
@@ -53,7 +53,7 @@ Q_SIGNALS:
53 void elapsedTimerRunningChanged();
53 void elapsedTimerRunningChanged();
54
54
55protected:
55protected:
56− void timerEvent(QTimerEvent * event);
56+ void timerEvent(QTimerEvent * event) override;
57
57
58private:
58private:
59 QString m_phoneNumber;
59 QString m_phoneNumber;
tests/mocks/Ubuntu/Telephony/plugin.h+2−2
@@ -27,8 +27,8 @@ class FakeUbuntuTelephonyQmlPlugin : public QQmlExtensionPlugin
27 Q_OBJECT
27 Q_OBJECT
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
29public:
29public:
30− void initializeEngine(QQmlEngine *engine, const char *uri);
30+ void initializeEngine(QQmlEngine *engine, const char *uri) override;
31− void registerTypes(const char *uri);
31+ void registerTypes(const char *uri) override;
32
32
33private:
33private:
34 QQmlContext *mRootContext;
34 QQmlContext *mRootContext;
tests/mocks/Unity/Application/ApplicationInfo.cpp+43−2
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2013-2014 Canonical, Ltd.
2+ * Copyright (C) 2013-2015 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
@@ -34,6 +34,11 @@ ApplicationInfo::ApplicationInfo(const QString &appId, QObject *parent)
34 , m_focused(false)
34 , m_focused(false)
35 , m_fullscreen(false)
35 , m_fullscreen(false)
36 , m_session(0)
36 , m_session(0)
37+ , m_supportedOrientations(Qt::PortraitOrientation |
38+ Qt::LandscapeOrientation |
39+ Qt::InvertedPortraitOrientation |
40+ Qt::InvertedLandscapeOrientation)
41+ , m_rotatesWindowContents(false)
37 , m_manualSurfaceCreation(false)
42 , m_manualSurfaceCreation(false)
38{
43{
39}
44}
@@ -45,6 +50,11 @@ ApplicationInfo::ApplicationInfo(QObject *parent)
45 , m_focused(false)
50 , m_focused(false)
46 , m_fullscreen(false)
51 , m_fullscreen(false)
47 , m_session(0)
52 , m_session(0)
53+ , m_supportedOrientations(Qt::PortraitOrientation |
54+ Qt::LandscapeOrientation |
55+ Qt::InvertedPortraitOrientation |
56+ Qt::InvertedLandscapeOrientation)
57+ , m_rotatesWindowContents(false)
48 , m_manualSurfaceCreation(false)
58 , m_manualSurfaceCreation(false)
49{
59{
50}
60}
@@ -99,9 +109,17 @@ void ApplicationInfo::setIconId(const QString &iconId)
99
109
100void ApplicationInfo::setScreenshotId(const QString &screenshotId)
110void ApplicationInfo::setScreenshotId(const QString &screenshotId)
101{
111{
112+ QString screenshotFileName;
113+
114+ if (screenshotId.endsWith(".svg")) {
115+ screenshotFileName = QString("%1/Dash/graphics/phone/screenshots/%2")
116+ .arg(qmlDirectory())
117+ .arg(screenshotId);
118+ } else {
102− QString screenshotFileName = QString("%1/Dash/graphics/phone/screenshots/%2@12.png")
119+ screenshotFileName = QString("%1/Dash/graphics/phone/screenshots/%2@12.png")
103 .arg(qmlDirectory())
120 .arg(qmlDirectory())
104 .arg(screenshotId);
121 .arg(screenshotId);
122+ }
105
123
106 if (screenshotFileName != m_screenshotFileName) {
124 if (screenshotFileName != m_screenshotFileName) {
107 m_screenshotFileName = screenshotFileName;
125 m_screenshotFileName = screenshotFileName;
@@ -145,6 +163,9 @@ void ApplicationInfo::setState(State value)
145
163
146 if (!m_manualSurfaceCreation && m_state == ApplicationInfo::Running) {
164 if (!m_manualSurfaceCreation && m_state == ApplicationInfo::Running) {
147 QTimer::singleShot(500, this, SLOT(createSession()));
165 QTimer::singleShot(500, this, SLOT(createSession()));
166+ } else if (m_state == ApplicationInfo::Stopped) {
167+ delete m_session;
168+ m_session = nullptr;
148 }
169 }
149 }
170 }
150}
171}
@@ -172,3 +193,23 @@ void ApplicationInfo::setManualSurfaceCreation(bool value)
172 Q_EMIT manualSurfaceCreationChanged(value);
193 Q_EMIT manualSurfaceCreationChanged(value);
173 }
194 }
174}
195}
196+
197+Qt::ScreenOrientations ApplicationInfo::supportedOrientations() const
198+{
199+ return m_supportedOrientations;
200+}
201+
202+void ApplicationInfo::setSupportedOrientations(Qt::ScreenOrientations orientations)
203+{
204+ m_supportedOrientations = orientations;
205+}
206+
207+bool ApplicationInfo::rotatesWindowContents() const
208+{
209+ return m_rotatesWindowContents;
210+}
211+
212+void ApplicationInfo::setRotatesWindowContents(bool value)
213+{
214+ m_rotatesWindowContents = value;
215+}
tests/mocks/Unity/Application/ApplicationInfo.h+9−1
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2013-2014 Canonical, Ltd.
2+ * Copyright (C) 2013-2015 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
@@ -80,6 +80,12 @@ public:
80 void setFullscreen(bool value);
80 void setFullscreen(bool value);
81 bool fullscreen() const { return m_fullscreen; }
81 bool fullscreen() const { return m_fullscreen; }
82
82
83+ Qt::ScreenOrientations supportedOrientations() const override;
84+ void setSupportedOrientations(Qt::ScreenOrientations orientations);
85+
86+ bool rotatesWindowContents() const override;
87+ void setRotatesWindowContents(bool value);
88+
83 bool manualSurfaceCreation() const { return m_manualSurfaceCreation; }
89 bool manualSurfaceCreation() const { return m_manualSurfaceCreation; }
84 void setManualSurfaceCreation(bool value);
90 void setManualSurfaceCreation(bool value);
85
91
@@ -108,6 +114,8 @@ private:
108 bool m_focused;
114 bool m_focused;
109 bool m_fullscreen;
115 bool m_fullscreen;
110 Session* m_session;
116 Session* m_session;
117+ Qt::ScreenOrientations m_supportedOrientations;
118+ bool m_rotatesWindowContents;
111
119
112 bool m_manualSurfaceCreation;
120 bool m_manualSurfaceCreation;
113};
121};
tests/mocks/Unity/Application/ApplicationManager.cpp+40−3
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2013-2014 Canonical, Ltd.
2+ * Copyright (C) 2013-2015 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
@@ -143,7 +143,7 @@ QModelIndex ApplicationManager::findIndex(ApplicationInfo* application)
143}
143}
144
144
145void ApplicationManager::add(ApplicationInfo *application) {
145void ApplicationManager::add(ApplicationInfo *application) {
146− if (!application) {
146+ if (!application || m_runningApplications.contains(application)) {
147 return;
147 return;
148 }
148 }
149
149
@@ -348,6 +348,13 @@ void ApplicationManager::unfocusCurrentApplication()
348
348
349void ApplicationManager::buildListOfAvailableApplications()
349void ApplicationManager::buildListOfAvailableApplications()
350{
350{
351+ /*
352+ ATTENTION!
353+ Be careful when changing application properties here as some qmltests
354+ rely on them being the way it's specified here (e.g. that camera-app
355+ is fullscreen, that twitter-webapp can rotate in all directions, etc)
356+ */
357+
351 ApplicationInfo *application;
358 ApplicationInfo *application;
352
359
353 application = new ApplicationInfo(this);
360 application = new ApplicationInfo(this);
@@ -355,6 +362,7 @@ void ApplicationManager::buildListOfAvailableApplications()
355 application->setName("Unity 8 Mock Dash");
362 application->setName("Unity 8 Mock Dash");
356 application->setScreenshotId("unity8-dash");
363 application->setScreenshotId("unity8-dash");
357 application->setStage(ApplicationInfo::MainStage);
364 application->setStage(ApplicationInfo::MainStage);
365+ application->setSupportedOrientations(Qt::PrimaryOrientation);
358 m_availableApplications.append(application);
366 m_availableApplications.append(application);
359
367
360 application = new ApplicationInfo(this);
368 application = new ApplicationInfo(this);
@@ -363,6 +371,8 @@ void ApplicationManager::buildListOfAvailableApplications()
363 application->setScreenshotId("dialer");
371 application->setScreenshotId("dialer");
364 application->setIconId("dialer-app");
372 application->setIconId("dialer-app");
365 application->setStage(ApplicationInfo::SideStage);
373 application->setStage(ApplicationInfo::SideStage);
374+ application->setSupportedOrientations(Qt::PortraitOrientation
375+ | Qt::InvertedPortraitOrientation);
366 m_availableApplications.append(application);
376 m_availableApplications.append(application);
367
377
368 application = new ApplicationInfo(this);
378 application = new ApplicationInfo(this);
@@ -371,6 +381,11 @@ void ApplicationManager::buildListOfAvailableApplications()
371 application->setScreenshotId("camera");
381 application->setScreenshotId("camera");
372 application->setIconId("camera");
382 application->setIconId("camera");
373 application->setFullscreen(true);
383 application->setFullscreen(true);
384+ application->setSupportedOrientations(Qt::PortraitOrientation
385+ | Qt::LandscapeOrientation
386+ | Qt::InvertedPortraitOrientation
387+ | Qt::InvertedLandscapeOrientation);
388+ application->setRotatesWindowContents(true);
374 m_availableApplications.append(application);
389 m_availableApplications.append(application);
375
390
376 application = new ApplicationInfo(this);
391 application = new ApplicationInfo(this);
@@ -416,13 +431,35 @@ void ApplicationManager::buildListOfAvailableApplications()
416 application->setAppId("gmail-webapp");
431 application->setAppId("gmail-webapp");
417 application->setName("GMail");
432 application->setName("GMail");
418 application->setIconId("gmail");
433 application->setIconId("gmail");
434+ application->setScreenshotId("gmail-webapp.svg");
435+ application->setFullscreen(false);
436+ application->setStage(ApplicationInfo::MainStage);
437+ application->setSupportedOrientations(Qt::PortraitOrientation
438+ | Qt::LandscapeOrientation
439+ | Qt::InvertedPortraitOrientation
440+ | Qt::InvertedLandscapeOrientation);
441+ m_availableApplications.append(application);
442+
443+ application = new ApplicationInfo(this);
444+ application->setAppId("music-app");
445+ application->setName("Music");
446+ application->setIconId("soundcloud");
447+ application->setScreenshotId("music");
448+ application->setFullscreen(false);
449+ application->setStage(ApplicationInfo::MainStage);
450+ application->setSupportedOrientations(Qt::PortraitOrientation
451+ | Qt::LandscapeOrientation
452+ | Qt::InvertedPortraitOrientation
453+ | Qt::InvertedLandscapeOrientation);
419 m_availableApplications.append(application);
454 m_availableApplications.append(application);
420
455
421 application = new ApplicationInfo(this);
456 application = new ApplicationInfo(this);
422 application->setAppId("ubuntu-weather-app");
457 application->setAppId("ubuntu-weather-app");
423 application->setName("Weather");
458 application->setName("Weather");
424 application->setIconId("weather");
459 application->setIconId("weather");
425− application->setStage(ApplicationInfo::SideStage);
460+ application->setScreenshotId("ubuntu-weather-app.svg");
461+ application->setSupportedOrientations(Qt::LandscapeOrientation
462+ | Qt::InvertedLandscapeOrientation);
426 m_availableApplications.append(application);
463 m_availableApplications.append(application);
427
464
428 application = new ApplicationInfo(this);
465 application = new ApplicationInfo(this);
tests/mocks/Unity/Application/CMakeLists.txt+1−2
@@ -1,5 +1,3 @@
1−pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=5)
2−
3set(FakeUnityApplicationQml_SOURCES
1set(FakeUnityApplicationQml_SOURCES
4 plugin.cpp
2 plugin.cpp
5 ApplicationInfo.cpp
3 ApplicationInfo.cpp
@@ -14,6 +12,7 @@ set(FakeUnityApplicationQml_SOURCES
14 SurfaceManager.cpp
12 SurfaceManager.cpp
15 SessionModel.h
13 SessionModel.h
16 UbuntuKeyboardInfo.cpp
14 UbuntuKeyboardInfo.cpp
15+ VirtualKeyboard.cpp
17 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
16 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
18 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
17 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
19)
18)
tests/mocks/Unity/Application/MirSurfaceItem.cpp+10−27
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2014 Canonical, Ltd.
2+ * Copyright (C) 2014-2015 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
@@ -39,14 +39,12 @@ MirSurfaceItem::MirSurfaceItem(const QString& name,
39 , m_type(type)
39 , m_type(type)
40 , m_state(state)
40 , m_state(state)
41 , m_live(true)
41 , m_live(true)
42− , m_orientation(Qt::PortraitOrientation)
42+ , m_orientationAngle(Angle0)
43− , m_touchPressCount(0)
44− , m_touchReleaseCount(0)
45 , m_qmlItem(nullptr)
43 , m_qmlItem(nullptr)
46 , m_screenshotUrl(screenshot)
44 , m_screenshotUrl(screenshot)
45+ , m_touchPressCount(0)
46+ , m_touchReleaseCount(0)
47{
47{
48− qDebug() << "MirSurfaceItem::MirSurfaceItem() " << this->name();
49−
50 setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton | Qt::RightButton |
48 setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton | Qt::RightButton |
51 Qt::ExtraButton1 | Qt::ExtraButton2 | Qt::ExtraButton3 | Qt::ExtraButton4 |
49 Qt::ExtraButton1 | Qt::ExtraButton2 | Qt::ExtraButton3 | Qt::ExtraButton4 |
52 Qt::ExtraButton5 | Qt::ExtraButton6 | Qt::ExtraButton7 | Qt::ExtraButton8 |
50 Qt::ExtraButton5 | Qt::ExtraButton6 | Qt::ExtraButton7 | Qt::ExtraButton8 |
@@ -55,9 +53,6 @@ MirSurfaceItem::MirSurfaceItem(const QString& name,
55
53
56 QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
54 QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
57
55
58− connect(this, &QQuickItem::focusChanged,
59− this, &MirSurfaceItem::onFocusChanged);
60−
61 // The assumptions I make here really should hold.
56 // The assumptions I make here really should hold.
62 QQuickView *quickView =
57 QQuickView *quickView =
63 qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]);
58 qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]);
@@ -117,17 +112,17 @@ void MirSurfaceItem::release()
117 }
112 }
118}
113}
119
114
120−void MirSurfaceItem::setOrientation(const Qt::ScreenOrientation orientation)
115+void MirSurfaceItem::setOrientationAngle(OrientationAngle angle)
121{
116{
122− if (m_orientation == orientation)
117+ if (m_orientationAngle == angle)
123 return;
118 return;
124
119
125− m_orientation = orientation;
120+ m_orientationAngle = angle;
126
121
127− QQmlProperty orientationProp(m_qmlItem, "orientation");
122+ QQmlProperty orientationProp(m_qmlItem, "orientationAngle");
128− orientationProp.write(QVariant::fromValue(orientation));
123+ orientationProp.write(QVariant::fromValue(m_orientationAngle));
129
124
130− Q_EMIT orientationChanged();
125+ Q_EMIT orientationAngleChanged(m_orientationAngle);
131}
126}
132
127
133void MirSurfaceItem::setSession(Session* session)
128void MirSurfaceItem::setSession(Session* session)
@@ -152,15 +147,6 @@ void MirSurfaceItem::setLive(bool live)
152 }
147 }
153}
148}
154
149
155−void MirSurfaceItem::onFocusChanged()
156−{
157− if (!hasFocus()) {
158− // Causes a crash in tst_Shell.qml, inside the mock Unity.Application itself.
159− // Didn't have time to debug yet.
160− //Q_EMIT inputMethodDismissed();
161− }
162−}
163−
164void MirSurfaceItem::setState(MirSurfaceItem::State newState)
150void MirSurfaceItem::setState(MirSurfaceItem::State newState)
165{
151{
166 if (newState != m_state) {
152 if (newState != m_state) {
@@ -197,9 +183,6 @@ void MirSurfaceItem::touchEvent(QTouchEvent * event)
197 if (event->touchPointStates() & Qt::TouchPointPressed) {
183 if (event->touchPointStates() & Qt::TouchPointPressed) {
198 ++m_touchPressCount;
184 ++m_touchPressCount;
199 Q_EMIT touchPressCountChanged(m_touchPressCount);
185 Q_EMIT touchPressCountChanged(m_touchPressCount);
200− // Causes a crash in tst_Shell.qml, inside the mock Unity.Application itself.
201− // Didn't have time to debug yet.
202− // Q_EMIT inputMethodRequested();
203 } else if (event->touchPointStates() & Qt::TouchPointReleased) {
186 } else if (event->touchPointStates() & Qt::TouchPointReleased) {
204 ++m_touchReleaseCount;
187 ++m_touchReleaseCount;
205 Q_EMIT touchReleaseCountChanged(m_touchReleaseCount);
188 Q_EMIT touchReleaseCountChanged(m_touchReleaseCount);
tests/mocks/Unity/Application/MirSurfaceItem.h+29−29
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2014 Canonical, Ltd.
2+ * Copyright (C) 2014-2015 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
@@ -29,17 +29,18 @@ class MirSurfaceItem : public QQuickItem
29 Q_OBJECT
29 Q_OBJECT
30 Q_ENUMS(Type)
30 Q_ENUMS(Type)
31 Q_ENUMS(State)
31 Q_ENUMS(State)
32+ Q_ENUMS(OrientationAngle)
32
33
33 Q_PROPERTY(Type type READ type NOTIFY typeChanged)
34 Q_PROPERTY(Type type READ type NOTIFY typeChanged)
34 Q_PROPERTY(State state READ state NOTIFY stateChanged)
35 Q_PROPERTY(State state READ state NOTIFY stateChanged)
35 Q_PROPERTY(QString name READ name CONSTANT)
36 Q_PROPERTY(QString name READ name CONSTANT)
36 Q_PROPERTY(bool live READ live NOTIFY liveChanged)
37 Q_PROPERTY(bool live READ live NOTIFY liveChanged)
37− Q_PROPERTY(Qt::ScreenOrientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged DESIGNABLE false)
38+ Q_PROPERTY(OrientationAngle orientationAngle READ orientationAngle WRITE setOrientationAngle
38−
39+ NOTIFY orientationAngleChanged DESIGNABLE false)
39− Q_PROPERTY(int touchPressCount READ touchPressCount WRITE setTouchPressCount NOTIFY touchPressCountChanged
40+ Q_PROPERTY(int touchPressCount READ touchPressCount WRITE setTouchPressCount
40− DESIGNABLE false)
41+ NOTIFY touchPressCountChanged DESIGNABLE false)
41− Q_PROPERTY(int touchReleaseCount READ touchReleaseCount WRITE setTouchReleaseCount NOTIFY touchReleaseCountChanged
42+ Q_PROPERTY(int touchReleaseCount READ touchReleaseCount WRITE setTouchReleaseCount
42− DESIGNABLE false)
43+ NOTIFY touchReleaseCountChanged DESIGNABLE false)
43
44
44public:
45public:
45 enum Type {
46 enum Type {
@@ -62,6 +63,13 @@ public:
62 Fullscreen,
63 Fullscreen,
63 };
64 };
64
65
66+ enum OrientationAngle {
67+ Angle0 = 0,
68+ Angle90 = 90,
69+ Angle180 = 180,
70+ Angle270 = 270
71+ };
72+
65 ~MirSurfaceItem();
73 ~MirSurfaceItem();
66
74
67 //getters
75 //getters
@@ -70,9 +78,9 @@ public:
70 State state() const { return m_state; }
78 State state() const { return m_state; }
71 QString name() const { return m_name; }
79 QString name() const { return m_name; }
72 bool live() const { return m_live; }
80 bool live() const { return m_live; }
73− Qt::ScreenOrientation orientation() const { return m_orientation; }
81+ OrientationAngle orientationAngle() const { return m_orientationAngle; }
74
82
75− void setOrientation(const Qt::ScreenOrientation orientation);
83+ void setOrientationAngle(OrientationAngle angle);
76
84
77 void setSession(Session* item);
85 void setSession(Session* item);
78 void setScreenshot(const QUrl& screenshot);
86 void setScreenshot(const QUrl& screenshot);
@@ -91,29 +99,14 @@ Q_SIGNALS:
91 void typeChanged(Type);
99 void typeChanged(Type);
92 void stateChanged(State);
100 void stateChanged(State);
93 void liveChanged(bool live);
101 void liveChanged(bool live);
94− void orientationChanged();
102+ void orientationAngleChanged(OrientationAngle angle);
95 void touchPressCountChanged(int count);
103 void touchPressCountChanged(int count);
96 void touchReleaseCountChanged(int count);
104 void touchReleaseCountChanged(int count);
97
105
98− void inputMethodRequested();
99− void inputMethodDismissed();
100−
101 // internal mock use
106 // internal mock use
102 void deregister();
107 void deregister();
103
108
104protected:
109protected:
105− void touchEvent(QTouchEvent * event) override;
106−
107− // becaue the default implementation ignores the events
108− void mousePressEvent(QMouseEvent *) override {}
109− void mouseMoveEvent(QMouseEvent *) override {}
110− void mouseReleaseEvent(QMouseEvent *) override {}
111−
112−private Q_SLOTS:
113− void onFocusChanged();
114− void onComponentStatusChanged(QQmlComponent::Status status);
115−
116−private:
117 explicit MirSurfaceItem(const QString& name,
110 explicit MirSurfaceItem(const QString& name,
118 Type type,
111 Type type,
119 State state,
112 State state,
@@ -121,6 +114,12 @@ private:
121 const QString &qmlFilePath = QString(),
114 const QString &qmlFilePath = QString(),
122 QQuickItem *parent = 0);
115 QQuickItem *parent = 0);
123
116
117+ void touchEvent(QTouchEvent * event) override;
118+
119+private Q_SLOTS:
120+ void onComponentStatusChanged(QQmlComponent::Status status);
121+
122+private:
124 void createQmlContentItem();
123 void createQmlContentItem();
125 void printComponentErrors();
124 void printComponentErrors();
126
125
@@ -129,19 +128,20 @@ private:
129 const Type m_type;
128 const Type m_type;
130 State m_state;
129 State m_state;
131 bool m_live;
130 bool m_live;
132− Qt::ScreenOrientation m_orientation;
131+ OrientationAngle m_orientationAngle;
133− int m_touchPressCount;
134− int m_touchReleaseCount;
135
132
136 QQmlComponent *m_qmlContentComponent;
133 QQmlComponent *m_qmlContentComponent;
137 QQuickItem *m_qmlItem;
134 QQuickItem *m_qmlItem;
138 QUrl m_screenshotUrl;
135 QUrl m_screenshotUrl;
139
136
137+ int m_touchPressCount;
138+ int m_touchReleaseCount;
139+
140 friend class SurfaceManager;
140 friend class SurfaceManager;
141};
141};
142
142
143Q_DECLARE_METATYPE(MirSurfaceItem*)
143Q_DECLARE_METATYPE(MirSurfaceItem*)
144Q_DECLARE_METATYPE(QList<MirSurfaceItem*>)
144Q_DECLARE_METATYPE(QList<MirSurfaceItem*>)
145−Q_DECLARE_METATYPE(Qt::ScreenOrientation)
145+Q_DECLARE_METATYPE(MirSurfaceItem::OrientationAngle)
146
146
147#endif // MIRSURFACEITEM_H
147#endif // MIRSURFACEITEM_H
tests/mocks/Unity/Application/MirSurfaceItem.qml+12−14
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright 2014 Canonical Ltd.
2+ * Copyright 2014-2015 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 Lesser General Public License as published by
5 * it under the terms of the GNU Lesser General Public License as published by
@@ -23,19 +23,11 @@ Rectangle {
23 implicitWidth: units.gu(40)
23 implicitWidth: units.gu(40)
24 implicitHeight: units.gu(70)
24 implicitHeight: units.gu(70)
25
25
26− rotation: {
26+ width: parent ? parent.width : implicitWidth
27− if (orientation == Qt.PortraitOrientation) return 0;
28− else if (orientation == Qt.LandscapeOrientation) return 90;
29− else if (orientation == Qt.InvertedPortraitOrientation) return 180;
30− else return 270;
31− }
32− x: parent ? (parent.width - width) / 2 : 0
33− y: parent ? (parent.height - height) / 2 : 0
34− width: parent ? (rotation == 0 || rotation == 180 ? parent.width : parent.height) : implicitWidth
35− height: parent ? (rotation == 0 || rotation == 180 ? parent.height : parent.width) : implicitHeight
27+ height: parent ? parent.height : implicitHeight
36
28
37 property alias screenshotSource: screenshotImage.source
29 property alias screenshotSource: screenshotImage.source
38− property int orientation: Qt.PortraitOrientation
30+ property int orientationAngle
39
31
40 Image {
32 Image {
41 id: screenshotImage
33 id: screenshotImage
@@ -50,6 +42,7 @@ Rectangle {
50 fontSizeMode: Text.Fit
42 fontSizeMode: Text.Fit
51 minimumPixelSize: 10
43 minimumPixelSize: 10
52 verticalAlignment: Text.AlignVCenter
44 verticalAlignment: Text.AlignVCenter
45+ rotation: surfaceText.rotation
53 x: surfaceText.x
46 x: surfaceText.x
54 y: surfaceText.y
47 y: surfaceText.y
55 width: surfaceText.width
48 width: surfaceText.width
@@ -59,12 +52,17 @@ Rectangle {
59 }
52 }
60 Text {
53 Text {
61 id: surfaceText
54 id: surfaceText
62− anchors.fill: parent
63− text: "SURFACE"
55+ text: "SURFACE " + root.width + "," + root.height
64 color: root.parent && root.parent.activeFocus ? "yellow" : "blue"
56 color: root.parent && root.parent.activeFocus ? "yellow" : "blue"
65 font.bold: true
57 font.bold: true
66 fontSizeMode: Text.Fit
58 fontSizeMode: Text.Fit
67 minimumPixelSize: 10; font.pixelSize: 200
59 minimumPixelSize: 10; font.pixelSize: 200
68 verticalAlignment: Text.AlignVCenter
60 verticalAlignment: Text.AlignVCenter
61+
62+ rotation: root.orientationAngle
63+ x: (parent.width - width) / 2
64+ y: (parent.height - height) / 2
65+ width: (rotation == 0 || rotation == 180 ? parent.width : parent.height)
66+ height:(rotation == 0 || rotation == 180 ? parent.height : parent.width)
69 }
67 }
70}
68}
tests/mocks/Unity/Application/ObjectListModel.h+1−1
@@ -76,7 +76,7 @@ public:
76 return QVariant();
76 return QVariant();
77 }
77 }
78
78
79− QHash<int, QByteArray> roleNames() const
79+ QHash<int, QByteArray> roleNames() const override
80 {
80 {
81 QHash<int, QByteArray> roleNames;
81 QHash<int, QByteArray> roleNames;
82 roleNames.insert(RoleModelData, "modelData");
82 roleNames.insert(RoleModelData, "modelData");
tests/mocks/Unity/Application/SurfaceManager.cpp+4−34
@@ -16,8 +16,9 @@
16
16
17#include "SurfaceManager.h"
17#include "SurfaceManager.h"
18
18
19+#include "VirtualKeyboard.h"
20+
19#include <paths.h>
21#include <paths.h>
20−#include "MirSurfaceItem.h"
21
22
22SurfaceManager *SurfaceManager::the_surface_manager = nullptr;
23SurfaceManager *SurfaceManager::the_surface_manager = nullptr;
23
24
@@ -40,10 +41,7 @@ MirSurfaceItem *SurfaceManager::createSurface(const QString& name,
40 MirSurfaceItem::State state,
41 MirSurfaceItem::State state,
41 const QUrl& screenshot)
42 const QUrl& screenshot)
42{
43{
43− MirSurfaceItem* surface = new MirSurfaceItem(name,
44+ MirSurfaceItem* surface = new MirSurfaceItem(name, type, state, screenshot);
44− type,
45− state,
46− screenshot);
47 Q_EMIT surfaceCreated(surface);
45 Q_EMIT surfaceCreated(surface);
48 return surface;
46 return surface;
49}
47}
@@ -57,40 +55,12 @@ void SurfaceManager::registerSurface(MirSurfaceItem *surface)
57 surface->setLive(false);
55 surface->setLive(false);
58 Q_EMIT surfaceDestroyed(surface);
56 Q_EMIT surfaceDestroyed(surface);
59 });
57 });
60− connect(surface, &MirSurfaceItem::inputMethodRequested,
61− this, &SurfaceManager::showInputMethod);
62− connect(surface, &MirSurfaceItem::inputMethodDismissed,
63− this, &SurfaceManager::hideInputMethod);
64−}
65−
66−void SurfaceManager::showInputMethod()
67−{
68− inputMethodSurface()->setState(MirSurfaceItem::Restored);
69−}
70−
71−void SurfaceManager::hideInputMethod()
72−{
73− if (m_virtualKeyboard) {
74− m_virtualKeyboard->setState(MirSurfaceItem::Minimized);
75− }
76}
58}
77
59
78MirSurfaceItem *SurfaceManager::inputMethodSurface()
60MirSurfaceItem *SurfaceManager::inputMethodSurface()
79{
61{
80 if (!m_virtualKeyboard) {
62 if (!m_virtualKeyboard) {
81−
82− QString screenshotPath = QString("file://%1/Dash/graphics/phone/screenshots/vkb_portrait.png")
83− .arg(qmlDirectory());
84−
85− QString qmlFilePath = QString("%1/Unity/Application/VirtualKeyboard.qml")
86− .arg(mockPluginsDir());
87−
88− m_virtualKeyboard = new MirSurfaceItem(
63+ m_virtualKeyboard = new VirtualKeyboard;
89− "input-method",
90− MirSurfaceItem::InputMethod,
91− MirSurfaceItem::Minimized,
92− screenshotPath,
93− qmlFilePath);
94 Q_EMIT surfaceCreated(m_virtualKeyboard);
64 Q_EMIT surfaceCreated(m_virtualKeyboard);
95 }
65 }
96 return m_virtualKeyboard;
66 return m_virtualKeyboard;
tests/mocks/Unity/Application/SurfaceManager.h+2−5
@@ -20,6 +20,7 @@
20#include <QObject>
20#include <QObject>
21
21
22#include "MirSurfaceItem.h"
22#include "MirSurfaceItem.h"
23+#include "VirtualKeyboard.h"
23
24
24class SurfaceManager : public QObject
25class SurfaceManager : public QObject
25{
26{
@@ -45,13 +46,9 @@ Q_SIGNALS:
45 void surfaceCreated(MirSurfaceItem *surface);
46 void surfaceCreated(MirSurfaceItem *surface);
46 void surfaceDestroyed(MirSurfaceItem *surface);
47 void surfaceDestroyed(MirSurfaceItem *surface);
47
48
48−private Q_SLOTS:
49− void showInputMethod();
50− void hideInputMethod();
51−
52private:
49private:
53 static SurfaceManager *the_surface_manager;
50 static SurfaceManager *the_surface_manager;
54− MirSurfaceItem *m_virtualKeyboard;
51+ VirtualKeyboard *m_virtualKeyboard;
55};
52};
56
53
57#endif // SURFACEMANAGER_H
54#endif // SURFACEMANAGER_H
tests/mocks/Unity/Application/UbuntuKeyboardInfo.cpp+33−1
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2014 Canonical, Ltd.
2+ * Copyright (C) 2014-2015 Canonical, Ltd.
3 *
3 *
4 * This program is free software: you can redistribute it and/or modify it under
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
5 * the terms of the GNU Lesser General Public License version 3, as published by
@@ -26,3 +26,35 @@ UbuntuKeyboardInfo::UbuntuKeyboardInfo(QObject *parent)
26 m_height(200)
26 m_height(200)
27{
27{
28}
28}
29+
30+void UbuntuKeyboardInfo::setX(qreal value)
31+{
32+ if (value != m_x) {
33+ m_x = value;
34+ Q_EMIT xChanged(m_x);
35+ }
36+}
37+
38+void UbuntuKeyboardInfo::setY(qreal value)
39+{
40+ if (value != m_y) {
41+ m_y = value;
42+ Q_EMIT yChanged(m_y);
43+ }
44+}
45+
46+void UbuntuKeyboardInfo::setWidth(qreal value)
47+{
48+ if (value != m_width) {
49+ m_width = value;
50+ Q_EMIT widthChanged(m_width);
51+ }
52+}
53+
54+void UbuntuKeyboardInfo::setHeight(qreal value)
55+{
56+ if (value != m_height) {
57+ m_height = value;
58+ Q_EMIT heightChanged(m_height);
59+ }
60+}
tests/mocks/Unity/Application/UbuntuKeyboardInfo.h+11−5
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2014 Canonical, Ltd.
2+ * Copyright (C) 2014-2015 Canonical, Ltd.
3 *
3 *
4 * This program is free software: you can redistribute it and/or modify it under
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
5 * the terms of the GNU Lesser General Public License version 3, as published by
@@ -22,10 +22,10 @@
22
22
23class UbuntuKeyboardInfo : public QObject {
23class UbuntuKeyboardInfo : public QObject {
24 Q_OBJECT
24 Q_OBJECT
25− Q_PROPERTY(qreal x READ x NOTIFY xChanged)
25+ Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged)
26− Q_PROPERTY(qreal y READ y NOTIFY yChanged)
26+ Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged)
27− Q_PROPERTY(qreal width READ width NOTIFY widthChanged)
27+ Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY widthChanged)
28− Q_PROPERTY(qreal height READ height NOTIFY heightChanged)
28+ Q_PROPERTY(qreal height READ height WRITE setHeight NOTIFY heightChanged)
29public:
29public:
30 UbuntuKeyboardInfo(QObject *parent = 0);
30 UbuntuKeyboardInfo(QObject *parent = 0);
31 virtual ~UbuntuKeyboardInfo() {}
31 virtual ~UbuntuKeyboardInfo() {}
@@ -34,6 +34,12 @@ public:
34 qreal width() const { return m_width; }
34 qreal width() const { return m_width; }
35 qreal height() const { return m_height; }
35 qreal height() const { return m_height; }
36
36
37+ // Just in the fake implementation
38+ void setX(qreal value);
39+ void setY(qreal value);
40+ void setWidth(qreal value);
41+ void setHeight(qreal value);
42+
37 static UbuntuKeyboardInfo *singleton() {
43 static UbuntuKeyboardInfo *singleton() {
38 if (!m_instance) {
44 if (!m_instance) {
39 m_instance = new UbuntuKeyboardInfo;
45 m_instance = new UbuntuKeyboardInfo;
tests/mocks/Unity/Application/VirtualKeyboard.cppnew file+44
@@ -0,0 +1,44 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "VirtualKeyboard.h"
18+
19+#include <paths.h>
20+
21+#include <QString>
22+
23+#include <QDebug>
24+
25+VirtualKeyboard::VirtualKeyboard(QQuickItem *parent)
26+ : MirSurfaceItem("input-method",
27+ MirSurfaceItem::InputMethod,
28+ MirSurfaceItem::Minimized,
29+ QString("file://%1/Dash/graphics/phone/screenshots/vkb_portrait.png")
30+ .arg(qmlDirectory()),
31+ QString("%1/Unity/Application/VirtualKeyboard.qml")
32+ .arg(mockPluginsDir()),
33+ parent)
34+{
35+}
36+
37+VirtualKeyboard::~VirtualKeyboard()
38+{
39+}
40+
41+void VirtualKeyboard::touchEvent(QTouchEvent *event)
42+{
43+ event->setAccepted(false);
44+}
tests/mocks/Unity/Application/VirtualKeyboard.hnew file+42
@@ -0,0 +1,42 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef VIRTUALKEYBOARD_H
18+#define VIRTUALKEYBOARD_H
19+
20+#include "MirSurfaceItem.h"
21+#include "MirSurfaceItemModel.h"
22+
23+#include <QQuickItem>
24+#include <QUrl>
25+
26+class Session;
27+
28+class VirtualKeyboard : public MirSurfaceItem
29+{
30+ Q_OBJECT
31+public:
32+ explicit VirtualKeyboard(QQuickItem *parent = 0);
33+ ~VirtualKeyboard();
34+
35+protected:
36+ void touchEvent(QTouchEvent * event) override;
37+};
38+
39+Q_DECLARE_METATYPE(VirtualKeyboard*)
40+Q_DECLARE_METATYPE(QList<VirtualKeyboard*>)
41+
42+#endif // VIRTUALKEYBOARD_H
tests/mocks/Unity/Application/VirtualKeyboard.qml+7−1
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright 2014 Canonical Ltd.
2+ * Copyright 2014-2015 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 Lesser General Public License as published by
5 * it under the terms of the GNU Lesser General Public License as published by
@@ -15,6 +15,7 @@
15 */
15 */
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18+import Unity.Application 0.1
18
19
19Item {
20Item {
20 implicitWidth: units.gu(40)
21 implicitWidth: units.gu(40)
@@ -37,4 +38,9 @@ Item {
37 anchors.fill: parent
38 anchors.fill: parent
38 }
39 }
39 }
40 }
41+
42+ Binding { target: UbuntuKeyboardInfo; property: "x"; value: screenshotImage.x}
43+ Binding { target: UbuntuKeyboardInfo; property: "y"; value: screenshotImage.y}
44+ Binding { target: UbuntuKeyboardInfo; property: "width"; value: screenshotImage.width}
45+ Binding { target: UbuntuKeyboardInfo; property: "height"; value: screenshotImage.height}
40}
46}
tests/mocks/Unity/Application/plugin.h+2−2
@@ -24,8 +24,8 @@ class FakeUnityApplicationQmlPlugin : public QQmlExtensionPlugin
24 Q_OBJECT
24 Q_OBJECT
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26public:
26public:
27− void registerTypes(const char *uri);
27+ void registerTypes(const char *uri) override;
28− void initializeEngine(QQmlEngine *engine, const char *uri);
28+ void initializeEngine(QQmlEngine *engine, const char *uri) override;
29};
29};
30
30
31#endif
31#endif
tests/mocks/Unity/Connectivity/plugin.h+1−1
@@ -25,7 +25,7 @@ class BackendPlugin : public QQmlExtensionPlugin
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26
26
27public:
27public:
28− void registerTypes(const char *uri);
28+ void registerTypes(const char *uri) override;
29};
29};
30
30
31#endif // MOCK_CONNECTIVITY_PLUGIN_H
31#endif // MOCK_CONNECTIVITY_PLUGIN_H
tests/mocks/Unity/DashCommunicator/plugin.h+1−1
@@ -28,7 +28,7 @@ class DashCommunicatorPlugin : public QQmlExtensionPlugin
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
29
29
30public:
30public:
31− void registerTypes(const char *uri);
31+ void registerTypes(const char *uri) override;
32};
32};
33
33
34#endif
34#endif
tests/mocks/Unity/Indicators/fakeindicatorsmodel.h+5−5
@@ -50,11 +50,11 @@ public:
50 QVariant modelData() const { return m_modelData; }
50 QVariant modelData() const { return m_modelData; }
51
51
52 /* QAbstractItemModel */
52 /* QAbstractItemModel */
53− QHash<int, QByteArray> roleNames() const;
53+ QHash<int, QByteArray> roleNames() const override;
54− int columnCount(const QModelIndex &parent = QModelIndex()) const;
54+ int columnCount(const QModelIndex &parent = QModelIndex()) const override;
55− QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
55+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
56− QModelIndex parent (const QModelIndex &index) const;
56+ QModelIndex parent (const QModelIndex &index) const override;
57− int rowCount(const QModelIndex &parent = QModelIndex()) const;
57+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
58
58
59Q_SIGNALS:
59Q_SIGNALS:
60 void countChanged();
60 void countChanged();
tests/mocks/Unity/Indicators/fakeplugin.h+1−1
@@ -26,7 +26,7 @@ class IndicatorsFakePlugin : public QQmlExtensionPlugin
26 Q_OBJECT
26 Q_OBJECT
27 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
27 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28public:
28public:
29− void registerTypes(const char *uri);
29+ void registerTypes(const char *uri) override;
30};
30};
31
31
32#endif // INDICATORS_FAKE_PLUGIN_H
32#endif // INDICATORS_FAKE_PLUGIN_H
tests/mocks/Unity/Launcher/MockLauncherItem.h+2−2
@@ -43,9 +43,9 @@ public:
43 int progress() const override;
43 int progress() const override;
44 int count() const override;
44 int count() const override;
45 bool countVisible() const override;
45 bool countVisible() const override;
46− bool focused() const;
46+ bool focused() const override;
47
47
48− unity::shell::launcher::QuickListModelInterface *quickList() const;
48+ unity::shell::launcher::QuickListModelInterface *quickList() const override;
49
49
50private:
50private:
51 void setPinned(bool pinned);
51 void setPinned(bool pinned);
tests/mocks/Unity/Launcher/MockLauncherModel.cpp+3−1
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright 2013 Canonical Ltd.
2+ * Copyright 2013,2015 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 Lesser General Public License as published by
5 * it under the terms of the GNU Lesser General Public License as published by
@@ -35,6 +35,8 @@ MockLauncherModel::MockLauncherModel(QObject* parent): LauncherModelInterface(pa
35 item->setProgress(50);
35 item->setProgress(50);
36 item->setCountVisible(true);
36 item->setCountVisible(true);
37 m_list.append(item);
37 m_list.append(item);
38+ item = new MockLauncherItem("music-app", "/usr/share/applications/music-app.desktop", "Music", "soundcloud", this);
39+ m_list.append(item);
38 item = new MockLauncherItem("facebook-webapp", "/usr/share/applications/facebook-webapp.desktop", "Facebook", "facebook", this);
40 item = new MockLauncherItem("facebook-webapp", "/usr/share/applications/facebook-webapp.desktop", "Facebook", "facebook", this);
39 item->setProgress(150);
41 item->setProgress(150);
40 m_list.append(item);
42 m_list.append(item);
tests/mocks/Unity/Launcher/MockLauncherModel.h+10−10
@@ -34,20 +34,20 @@ public:
34 MockLauncherModel(QObject* parent = 0);
34 MockLauncherModel(QObject* parent = 0);
35 ~MockLauncherModel();
35 ~MockLauncherModel();
36
36
37− int rowCount(const QModelIndex& parent) const;
37+ int rowCount(const QModelIndex& parent) const override;
38
38
39− QVariant data(const QModelIndex& index, int role) const;
39+ QVariant data(const QModelIndex& index, int role) const override;
40
40
41− Q_INVOKABLE unity::shell::launcher::LauncherItemInterface *get(int index) const;
41+ Q_INVOKABLE unity::shell::launcher::LauncherItemInterface *get(int index) const override;
42− Q_INVOKABLE void move(int oldIndex, int newIndex);
42+ Q_INVOKABLE void move(int oldIndex, int newIndex) override;
43− Q_INVOKABLE void pin(const QString &appId, int index = -1);
43+ Q_INVOKABLE void pin(const QString &appId, int index = -1) override;
44− Q_INVOKABLE void requestRemove(const QString &appId);
44+ Q_INVOKABLE void requestRemove(const QString &appId) override;
45− Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex);
45+ Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex) override;
46− Q_INVOKABLE void setUser(const QString &username);
46+ Q_INVOKABLE void setUser(const QString &username) override;
47 Q_INVOKABLE QString getUrlForAppId(const QString &appId) const;
47 Q_INVOKABLE QString getUrlForAppId(const QString &appId) const;
48
48
49− unity::shell::application::ApplicationManagerInterface *applicationManager() const;
49+ unity::shell::application::ApplicationManagerInterface *applicationManager() const override;
50− void setApplicationManager(unity::shell::application::ApplicationManagerInterface *applicationManager);
50+ void setApplicationManager(unity::shell::application::ApplicationManagerInterface *applicationManager) override;
51
51
52 bool onlyPinned() const override;
52 bool onlyPinned() const override;
53 void setOnlyPinned(bool onlyPinned) override;
53 void setOnlyPinned(bool onlyPinned) override;
tests/mocks/Unity/Launcher/MockQuickListModel.h+2−2
@@ -30,9 +30,9 @@ class MockQuickListModel: public QuickListModelInterface
30public:
30public:
31 MockQuickListModel(QObject *parent = 0);
31 MockQuickListModel(QObject *parent = 0);
32
32
33− QVariant data(const QModelIndex &index, int role) const;
33+ QVariant data(const QModelIndex &index, int role) const override;
34
34
35− int rowCount(const QModelIndex &parent = QModelIndex()) const;
35+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
36};
36};
37
37
38#endif // MOCKQUICKLISTMODEL_H
38#endif // MOCKQUICKLISTMODEL_H
tests/mocks/Unity/Launcher/plugin.h+1−1
@@ -29,7 +29,7 @@ class TestLauncherPlugin : public QQmlExtensionPlugin
29 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
29 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
30
30
31public:
31public:
32− void registerTypes(const char* uri);
32+ void registerTypes(const char* uri) override;
33};
33};
34
34
35#endif // TESTLAUNCHER_PLUGIN_H
35#endif // TESTLAUNCHER_PLUGIN_H
tests/mocks/Unity/Notifications/MockActionModel.h+3−3
@@ -32,9 +32,9 @@ public:
32 ActionModel(QObject *parent=nullptr);
32 ActionModel(QObject *parent=nullptr);
33 virtual ~ActionModel();
33 virtual ~ActionModel();
34
34
35− virtual int rowCount(const QModelIndex &index) const;
35+ int rowCount(const QModelIndex &index) const override;
36− virtual QVariant data(const QModelIndex &index, int role) const;
36+ QVariant data(const QModelIndex &index, int role) const override;
37− virtual QHash<int, QByteArray> roleNames() const;
37+ QHash<int, QByteArray> roleNames() const override;
38
38
39 Q_ENUMS(ActionsRoles)
39 Q_ENUMS(ActionsRoles)
40 enum ActionsRoles {
40 enum ActionsRoles {
tests/mocks/Unity/Notifications/MockNotificationModel.h+3−3
@@ -35,9 +35,9 @@ public:
35 MockNotificationModel(QObject *parent=nullptr);
35 MockNotificationModel(QObject *parent=nullptr);
36 virtual ~MockNotificationModel();
36 virtual ~MockNotificationModel();
37
37
38− virtual int rowCount(const QModelIndex &parent) const;
38+ int rowCount(const QModelIndex &parent) const override;
39− virtual QVariant data(const QModelIndex &index, int role) const;
39+ QVariant data(const QModelIndex &index, int role) const override;
40− virtual QHash<int, QByteArray> roleNames() const;
40+ QHash<int, QByteArray> roleNames() const override;
41
41
42 Q_INVOKABLE void append(MockNotification* n);
42 Q_INVOKABLE void append(MockNotification* n);
43 MockNotification* getNotification(int id) const;
43 MockNotification* getNotification(int id) const;
tests/mocks/Unity/Notifications/plugin.h+1−1
@@ -28,7 +28,7 @@ class TestNotificationPlugin : public QQmlExtensionPlugin
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
29
29
30public:
30public:
31− void registerTypes(const char* uri);
31+ void registerTypes(const char* uri) override;
32};
32};
33
33
34#endif // TESTNOTIFICATION_PLUGIN_H
34#endif // TESTNOTIFICATION_PLUGIN_H
tests/mocks/Unity/fake_scopes.h+2−2
@@ -50,8 +50,8 @@ public:
50 Q_INVOKABLE void clearFavorites();
50 Q_INVOKABLE void clearFavorites();
51 Q_INVOKABLE void load();
51 Q_INVOKABLE void load();
52
52
53− QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
53+ QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
54− QModelIndex parent ( const QModelIndex & index ) const;
54+ QModelIndex parent ( const QModelIndex & index ) const override;
55
55
56 bool loaded() const override;
56 bool loaded() const override;
57 int count() const override;
57 int count() const override;
tests/mocks/Unity/fake_unity_plugin.h+1−1
@@ -28,7 +28,7 @@ class FakeUnityPlugin : public QQmlExtensionPlugin
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
29
29
30public:
30public:
31− void registerTypes(const char *uri);
31+ void registerTypes(const char *uri) override;
32};
32};
33
33
34#endif
34#endif
tests/mocks/Utils/CMakeLists.txtnew file+40
@@ -0,0 +1,40 @@
1+pkg_search_module(GIO REQUIRED gio-2.0)
2+
3+include_directories(
4+ ${CMAKE_CURRENT_SOURCE_DIR}
5+ ${CMAKE_CURRENT_BINARY_DIR}
6+ ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
7+ ${GIO_INCLUDE_DIRS}
8+ ${CMAKE_SOURCE_DIR}/plugins/Utils
9+)
10+
11+set(QMLPLUGIN_SRC
12+ ${CMAKE_SOURCE_DIR}/plugins/Utils/inputwatcher.cpp
13+ ${CMAKE_SOURCE_DIR}/plugins/Utils/qlimitproxymodelqml.cpp
14+ ${CMAKE_SOURCE_DIR}/plugins/Utils/unitysortfilterproxymodelqml.cpp
15+ ${CMAKE_SOURCE_DIR}/plugins/Utils/relativetimeformatter.cpp
16+ ${CMAKE_SOURCE_DIR}/plugins/Utils/timeformatter.cpp
17+ ${CMAKE_SOURCE_DIR}/plugins/Utils/unitymenumodelpaths.cpp
18+ ${CMAKE_SOURCE_DIR}/plugins/Utils/windowkeysfilter.cpp
19+ ${CMAKE_SOURCE_DIR}/plugins/Utils/windowscreenshotprovider.cpp
20+ ${CMAKE_SOURCE_DIR}/plugins/Utils/easingcurve.cpp
21+ constants.cpp
22+ plugin.cpp
23+ windowstatestorage.cpp
24+ )
25+
26+add_library(FakeUtils-qml SHARED
27+ ${QMLPLUGIN_SRC}
28+ )
29+
30+target_link_libraries(FakeUtils-qml ${GIO_LDFLAGS})
31+
32+# Because this is an internal support library, we want
33+# to expose all symbols in it. Consider changing this
34+# either to a static library or just using the
35+# files directly in targets.
36+set_target_properties(FakeUtils-qml PROPERTIES COMPILE_FLAGS -fvisibility=default)
37+
38+qt5_use_modules(FakeUtils-qml Qml Quick DBus Network Gui)
39+
40+add_unity8_mock(Utils 0.1 Utils TARGETS FakeUtils-qml)
tests/mocks/Utils/HomeKeyWatcher.qmlnew file+21
@@ -0,0 +1,21 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+
19+QtObject {
20+ signal activated()
21+}
tests/mocks/Utils/Style.jsnew file+37
@@ -0,0 +1,37 @@
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+.pragma library
18+
19+/*! \brief Calculate average luminance of the passed colors
20+
21+ \note If not fully opaque, luminance is dependant on blending.
22+ */
23+function luminance() {
24+ var sum = 0;
25+ // TODO this was originally
26+ // for (var k in arguments) {
27+ // but for some unkown reason was causing crashes in testDash/testDashContent
28+ // investigate when we have some time
29+ for (var k = 0; k < arguments.length; ++k) {
30+ // only way to convert string to color
31+ var c = Qt.lighter(arguments[k], 1.0);
32+
33+ sum += 0.2126 * c.r + 0.7152 * c.g + 0.0722 * c.b;
34+ }
35+
36+ return sum / arguments.length;
37+}
tests/mocks/Utils/Utils.qmltypesnew file+175
@@ -0,0 +1,175 @@
1+import QtQuick.tooling 1.1
2+
3+// This file describes the plugin-supplied types contained in the library.
4+// It is used for QML tooling purposes only.
5+//
6+// This file was auto-generated by:
7+// 'qmlplugindump -notrelocatable Utils 0.1 plugins'
8+
9+Module {
10+ Component {
11+ name: "EasingCurve"
12+ prototype: "QObject"
13+ exports: ["Utils/EasingCurve 0.1"]
14+ exportMetaObjectRevisions: [0]
15+ Property { name: "type"; type: "QEasingCurve::Type" }
16+ Property { name: "period"; type: "double" }
17+ Property { name: "progress"; type: "double" }
18+ Property { name: "value"; type: "double"; isReadonly: true }
19+ }
20+ Component {
21+ name: "QAbstractProxyModel"
22+ prototype: "QAbstractItemModel"
23+ Property { name: "sourceModel"; type: "QAbstractItemModel"; isPointer: true }
24+ }
25+ Component { name: "QIdentityProxyModel"; prototype: "QAbstractProxyModel" }
26+ Component {
27+ name: "QLimitProxyModelQML"
28+ prototype: "QIdentityProxyModel"
29+ exports: ["Utils/LimitProxyModel 0.1"]
30+ exportMetaObjectRevisions: [0]
31+ Property { name: "model"; type: "QAbstractItemModel"; isPointer: true }
32+ Property { name: "limit"; type: "int" }
33+ Property { name: "count"; type: "int"; isReadonly: true }
34+ Signal { name: "totalCountChanged" }
35+ }
36+ Component {
37+ name: "QSortFilterProxyModel"
38+ prototype: "QAbstractProxyModel"
39+ Property { name: "filterRegExp"; type: "QRegExp" }
40+ Property { name: "filterKeyColumn"; type: "int" }
41+ Property { name: "dynamicSortFilter"; type: "bool" }
42+ Property { name: "filterCaseSensitivity"; type: "Qt::CaseSensitivity" }
43+ Property { name: "sortCaseSensitivity"; type: "Qt::CaseSensitivity" }
44+ Property { name: "isSortLocaleAware"; type: "bool" }
45+ Property { name: "sortRole"; type: "int" }
46+ Property { name: "filterRole"; type: "int" }
47+ Method {
48+ name: "setFilterRegExp"
49+ Parameter { name: "pattern"; type: "string" }
50+ }
51+ Method {
52+ name: "setFilterWildcard"
53+ Parameter { name: "pattern"; type: "string" }
54+ }
55+ Method {
56+ name: "setFilterFixedString"
57+ Parameter { name: "pattern"; type: "string" }
58+ }
59+ Method { name: "clear" }
60+ Method { name: "invalidate" }
61+ }
62+ Component {
63+ name: "RelativeTimeFormatter"
64+ prototype: "TimeFormatter"
65+ exports: ["Utils/RelativeTimeFormatter 0.1"]
66+ exportMetaObjectRevisions: [0]
67+ }
68+ Component {
69+ name: "TimeFormatter"
70+ prototype: "QObject"
71+ exports: ["Utils/GDateTimeFormatter 0.1", "Utils/TimeFormatter 0.1"]
72+ exportMetaObjectRevisions: [0, 0]
73+ Property { name: "format"; type: "string" }
74+ Property { name: "timeString"; type: "string"; isReadonly: true }
75+ Property { name: "time"; type: "qlonglong" }
76+ Signal {
77+ name: "formatChanged"
78+ Parameter { name: "format"; type: "string" }
79+ }
80+ Signal {
81+ name: "timeStringChanged"
82+ Parameter { name: "timeString"; type: "string" }
83+ }
84+ Signal {
85+ name: "timeChanged"
86+ Parameter { name: "time"; type: "qlonglong" }
87+ }
88+ }
89+ Component {
90+ name: "UnityMenuModelPaths"
91+ prototype: "QObject"
92+ exports: ["Utils/UnityMenuModelPaths 0.1"]
93+ exportMetaObjectRevisions: [0]
94+ Property { name: "source"; type: "QVariant" }
95+ Property { name: "busName"; type: "QByteArray"; isReadonly: true }
96+ Property { name: "actions"; type: "QVariantMap"; isReadonly: true }
97+ Property { name: "menuObjectPath"; type: "QByteArray"; isReadonly: true }
98+ Property { name: "busNameHint"; type: "QByteArray" }
99+ Property { name: "actionsHint"; type: "QByteArray" }
100+ Property { name: "menuObjectPathHint"; type: "QByteArray" }
101+ }
102+ Component {
103+ name: "UnitySortFilterProxyModelQML"
104+ prototype: "QSortFilterProxyModel"
105+ exports: ["Utils/UnitySortFilterProxyModel 0.1"]
106+ exportMetaObjectRevisions: [0]
107+ Property { name: "model"; type: "QAbstractItemModel"; isPointer: true }
108+ Property { name: "totalCount"; type: "int"; isReadonly: true }
109+ Property { name: "count"; type: "int"; isReadonly: true }
110+ Property { name: "invertMatch"; type: "bool" }
111+ Signal {
112+ name: "invertMatchChanged"
113+ Parameter { type: "bool" }
114+ }
115+ Method {
116+ name: "get"
117+ type: "QVariantMap"
118+ Parameter { name: "row"; type: "int" }
119+ }
120+ Method {
121+ name: "data"
122+ type: "QVariant"
123+ Parameter { name: "row"; type: "int" }
124+ Parameter { name: "role"; type: "int" }
125+ }
126+ Method { name: "count"; type: "int" }
127+ Method {
128+ name: "findFirst"
129+ type: "int"
130+ Parameter { name: "role"; type: "int" }
131+ Parameter { name: "value"; type: "QVariant" }
132+ }
133+ Method {
134+ name: "mapRowToSource"
135+ type: "int"
136+ Parameter { name: "row"; type: "int" }
137+ }
138+ Method {
139+ name: "mapFromSource"
140+ type: "int"
141+ Parameter { name: "row"; type: "int" }
142+ }
143+ Method {
144+ name: "mapToSource"
145+ type: "int"
146+ Parameter { name: "row"; type: "int" }
147+ }
148+ }
149+ Component {
150+ name: "WindowKeysFilter"
151+ defaultProperty: "data"
152+ prototype: "QQuickItem"
153+ exports: ["Utils/WindowKeysFilter 0.1"]
154+ exportMetaObjectRevisions: [0]
155+ }
156+ Component {
157+ name: "WindowStateStorage"
158+ prototype: "QObject"
159+ exports: ["Utils/WindowStateStorage 0.1"]
160+ isCreatable: false
161+ isSingleton: true
162+ exportMetaObjectRevisions: [0]
163+ Method {
164+ name: "saveGeometry"
165+ Parameter { name: "windowId"; type: "string" }
166+ Parameter { name: "rect"; type: "QRect" }
167+ }
168+ Method {
169+ name: "getGeometry"
170+ type: "QRect"
171+ Parameter { name: "windowId"; type: "string" }
172+ Parameter { name: "defaultValue"; type: "QRect" }
173+ }
174+ }
175+}
tests/mocks/Utils/constants.cppnew file+23
@@ -0,0 +1,23 @@
1+/*
2+ * Copyright 2015 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+*/
16+
17+#include "constants.h"
18+
19+Constants::Constants(QObject *parent)
20+ : QObject(parent)
21+{
22+ m_indicatorValueTimeout = 5000;
23+}
tests/mocks/Utils/constants.hnew file+43
@@ -0,0 +1,43 @@
1+/*
2+ * Copyright 2015 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+*/
16+
17+#ifndef CONSTANTS_H
18+#define CONSTANTS_H
19+
20+#include <QObject>
21+
22+/**
23+ * @brief The Constants class
24+ *
25+ * This singleton class exposes contants to Qml
26+ *
27+ */
28+
29+class Constants: public QObject
30+{
31+ Q_OBJECT
32+ Q_PROPERTY(int indicatorValueTimeout READ indicatorValueTimeout CONSTANT)
33+
34+public:
35+ Constants(QObject *parent = 0);
36+
37+ int indicatorValueTimeout() const { return m_indicatorValueTimeout; }
38+
39+private:
40+ int m_indicatorValueTimeout;
41+};
42+
43+#endif
tests/mocks/Utils/plugin.cppnew file+76
@@ -0,0 +1,76 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+// Qt
18+#include <QtQml/qqml.h>
19+#include <QDBusConnection>
20+#include <QQmlContext>
21+#include <QtQuick/QQuickWindow>
22+#include <QDebug>
23+
24+// local
25+#include "plugin.h"
26+#include "windowstatestorage.h"
27+#include "constants.h"
28+
29+// plugin
30+#include <inputwatcher.h>
31+#include <qlimitproxymodelqml.h>
32+#include <unitysortfilterproxymodelqml.h>
33+#include <relativetimeformatter.h>
34+#include <timeformatter.h>
35+#include <unitymenumodelpaths.h>
36+#include <windowkeysfilter.h>
37+#include <windowscreenshotprovider.h>
38+#include <easingcurve.h>
39+
40+static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
41+{
42+ Q_UNUSED(engine)
43+ Q_UNUSED(scriptEngine)
44+ return new WindowStateStorage();
45+}
46+
47+static QObject *createConstants(QQmlEngine *engine, QJSEngine *scriptEngine)
48+{
49+ Q_UNUSED(engine)
50+ Q_UNUSED(scriptEngine)
51+ return new Constants();
52+}
53+
54+void FakeUtilsPlugin::registerTypes(const char *uri)
55+{
56+ Q_ASSERT(uri == QLatin1String("Utils"));;
57+ qmlRegisterType<QAbstractItemModel>();
58+ qmlRegisterType<QLimitProxyModelQML>(uri, 0, 1, "LimitProxyModel");
59+ qmlRegisterType<UnitySortFilterProxyModelQML>(uri, 0, 1, "UnitySortFilterProxyModel");
60+ qmlRegisterType<UnityMenuModelPaths>(uri, 0, 1, "UnityMenuModelPaths");
61+ qmlRegisterType<TimeFormatter>(uri, 0, 1, "TimeFormatter");
62+ qmlRegisterType<WindowKeysFilter>(uri, 0, 1, "WindowKeysFilter");
63+ qmlRegisterType<GDateTimeFormatter>(uri, 0, 1, "GDateTimeFormatter");
64+ qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve");
65+ qmlRegisterType<RelativeTimeFormatter>(uri, 0, 1, "RelativeTimeFormatter");
66+ qmlRegisterSingletonType<WindowStateStorage>(uri, 0, 1, "WindowStateStorage", createWindowStateStorage);
67+ qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher");
68+ qmlRegisterSingletonType<Constants>(uri, 0, 1, "Constants", createConstants);
69+}
70+
71+void FakeUtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
72+{
73+ QQmlExtensionPlugin::initializeEngine(engine, uri);
74+
75+ engine->addImageProvider(QLatin1String("window"), new WindowScreenshotProvider);
76+}
tests/mocks/Utils/plugin.hnew file+33
@@ -0,0 +1,33 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef FAKE_UTILS_PLUGIN_H
18+#define FAKE_UTILS_PLUGIN_H
19+
20+#include <QtQml/QQmlEngine>
21+#include <QtQml/QQmlExtensionPlugin>
22+
23+class FakeUtilsPlugin : public QQmlExtensionPlugin
24+{
25+ Q_OBJECT
26+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
27+
28+public:
29+ void registerTypes(const char *uri);
30+ void initializeEngine(QQmlEngine *engine, const char *uri);
31+};
32+
33+#endif
tests/mocks/Utils/qmldirnew file+5
@@ -0,0 +1,5 @@
1+module Utils
2+plugin FakeUtils-qml
3+typeinfo Utils.qmltypes
4+Style 0.1 Style.js
5+HomeKeyWatcher 0.1 HomeKeyWatcher.qml
tests/mocks/Utils/windowstatestorage.cppnew file+48
@@ -0,0 +1,48 @@
1+/*
2+ * Copyright 2015 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "windowstatestorage.h"
18+
19+#include <QRect>
20+
21+WindowStateStorage::WindowStateStorage(QObject *parent):
22+ QObject(parent)
23+{
24+}
25+
26+void WindowStateStorage::setGeometry(const QVariantMap& geometry)
27+{
28+ if (geometry != m_geometry) {
29+ m_geometry = geometry;
30+ Q_EMIT geometryChanged(m_geometry);
31+ }
32+}
33+
34+QVariantMap WindowStateStorage::geometry() const
35+{
36+ return m_geometry;
37+}
38+
39+void WindowStateStorage::saveGeometry(const QString &windowId, const QRect &rect)
40+{
41+ m_geometry[windowId] = rect;
42+}
43+
44+QRect WindowStateStorage::getGeometry(const QString &windowId, const QRect &defaultValue)
45+{
46+ if (!m_geometry.contains(windowId)) return defaultValue;
47+ return m_geometry.value(windowId).toRect();
48+}
tests/mocks/Utils/windowstatestorage.hnew file+38
@@ -0,0 +1,38 @@
1+/*
2+ * Copyright 2015 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include <QObject>
18+#include <QVariantMap>
19+
20+class WindowStateStorage: public QObject
21+{
22+ Q_OBJECT
23+ Q_PROPERTY(QVariantMap geometry READ geometry WRITE setGeometry NOTIFY geometryChanged)
24+public:
25+ WindowStateStorage(QObject *parent = 0);
26+
27+ Q_INVOKABLE void saveGeometry(const QString &windowId, const QRect &rect);
28+ Q_INVOKABLE QRect getGeometry(const QString &windowId, const QRect &defaultValue);
29+
30+Q_SIGNALS:
31+ void geometryChanged(const QVariantMap& geometry);
32+
33+private:
34+ void setGeometry(const QVariantMap& geometry);
35+ QVariantMap geometry() const;
36+
37+ QVariantMap m_geometry;
38+};
tests/mocks/Wizard/mockplugin.h+1−1
@@ -26,7 +26,7 @@ class MockWizardPlugin : public QQmlExtensionPlugin
26 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
27
27
28public:
28public:
29− void registerTypes(const char *uri);
29+ void registerTypes(const char *uri) override;
30};
30};
31
31
32#endif
32#endif
tests/mocks/indicator-service/mock-indicator-service.c+76−12
@@ -27,8 +27,15 @@ typedef struct
27 guint actions_export_id;
27 guint actions_export_id;
28 guint menu_export_id;
28 guint menu_export_id;
29 int action_delay;
29 int action_delay;
30+ int change_interval;
30} IndicatorTestService;
31} IndicatorTestService;
31
32
33+typedef struct
34+{
35+ GSimpleAction *action;
36+ GVariant* value;
37+} Action;
38+
32static void
39static void
33bus_acquired (GDBusConnection *connection,
40bus_acquired (GDBusConnection *connection,
34 const gchar *name,
41 const gchar *name,
@@ -96,10 +103,10 @@ actual_switch (gpointer user_data)
96 gboolean state = g_variant_get_boolean (v);
103 gboolean state = g_variant_get_boolean (v);
97 GVariant *new_state = g_variant_new_boolean (state == TRUE ? FALSE : TRUE);
104 GVariant *new_state = g_variant_new_boolean (state == TRUE ? FALSE : TRUE);
98
105
99− g_simple_action_set_state(G_SIMPLE_ACTION(action), new_state);
106+ g_simple_action_set_state(action, new_state);
100
107
101 g_variant_unref (v);
108 g_variant_unref (v);
102− g_message ("switching");
109+ g_message ("switching %d", state);
103 return FALSE;
110 return FALSE;
104}
111}
105
112
@@ -120,13 +127,12 @@ activate_switch (GSimpleAction *action,
120static gboolean
127static gboolean
121actual_slide (gpointer user_data)
128actual_slide (gpointer user_data)
122{
129{
123− GSimpleAction *action = user_data;
130+ Action *slide_action = user_data;
124−
125− GVariant* new_state = g_object_get_qdata (G_OBJECT (action), slider_value_quark ());
126
131
127− g_simple_action_set_state(G_SIMPLE_ACTION(action), new_state);
132+ g_simple_action_set_state(G_SIMPLE_ACTION(slide_action->action), slide_action->value);
133+ g_message ("sliding %f", g_variant_get_double(slide_action->value));
134+ free(slide_action);
128
135
129− g_message ("switching");
130 return FALSE;
136 return FALSE;
131}
137}
132
138
@@ -136,10 +142,40 @@ void change_slider (GSimpleAction *action,
136{
142{
137 IndicatorTestService *indicator = user_data;
143 IndicatorTestService *indicator = user_data;
138
144
139− g_object_set_qdata (G_OBJECT (action), slider_value_quark (), g_variant_ref(value));
145+ Action* slide_action = malloc(sizeof(Action));
146+ slide_action->action = action;
147+ slide_action->value = g_variant_ref(value);
140
148
141− g_timeout_add(indicator->action_delay, actual_slide, action);
149+ g_timeout_add(indicator->action_delay, actual_slide, slide_action);
142− g_message ("slide delay %.03f", g_variant_get_double(value));
150+ g_message ("slide delay %f", g_variant_get_double(value));
151+}
152+
153+static gboolean
154+change_interval (gpointer user_data)
155+{
156+ g_message ("change interval");
157+
158+ IndicatorTestService *indicator = user_data;
159+
160+ GAction* action_switch = g_action_map_lookup_action(G_ACTION_MAP(indicator->actions), "action.switch");
161+ actual_switch(G_SIMPLE_ACTION(action_switch));
162+
163+ GAction* action_checkbox = g_action_map_lookup_action(G_ACTION_MAP(indicator->actions), "action.checkbox");
164+ actual_switch(G_SIMPLE_ACTION(action_checkbox));
165+
166+ GAction* action_accessPoint = g_action_map_lookup_action(G_ACTION_MAP(indicator->actions), "action.accessPoint");
167+ actual_switch(G_SIMPLE_ACTION(action_accessPoint));
168+
169+ GAction* action_slider = g_action_map_lookup_action(G_ACTION_MAP(indicator->actions), "action.slider");
170+ static double old_value = 0.25;
171+ double new_value = old_value == 0.25 ? 0.75 : 0.25;
172+ old_value = new_value;
173+ Action* slide_action = malloc(sizeof(Action));
174+ slide_action->action = G_SIMPLE_ACTION(action_slider);
175+ slide_action->value = g_variant_new_double(new_value);
176+ actual_slide(slide_action);
177+
178+ return TRUE;
143}
179}
144
180
145int
181int
@@ -147,6 +183,7 @@ main (int argc, char **argv)
147{
183{
148 IndicatorTestService indicator = { 0 };
184 IndicatorTestService indicator = { 0 };
149 indicator.action_delay = -1;
185 indicator.action_delay = -1;
186+ indicator.change_interval = -1;
150 GMenuItem *item;
187 GMenuItem *item;
151 GMenu *submenu;
188 GMenu *submenu;
152 GActionEntry entries[] = {
189 GActionEntry entries[] = {
@@ -191,6 +228,27 @@ main (int argc, char **argv)
191 }
228 }
192 break;
229 break;
193 }
230 }
231+
232+ case 'c':
233+ {
234+ arg += 2;
235+ if (!arg[0] && i < argc-1) {
236+ i++;
237+ int interval = -1;
238+
239+ if (sscanf(argv[i], "%d", &interval) == 1) {
240+ indicator.change_interval = interval;
241+ } else {
242+ printf("Invalid change interval value: %s\n", argv[i]);
243+ help = 1;
244+ }
245+ } else {
246+ printf("Invalid change interval value: %s\n", argv[i]);
247+ help = 1;
248+ }
249+ break;
250+ }
251+
194 case 'h':
252 case 'h':
195 help = 1;
253 help = 1;
196 break;
254 break;
@@ -201,8 +259,9 @@ main (int argc, char **argv)
201
259
202 if (help) {
260 if (help) {
203 printf("Usage: %s [<options>]\n"
261 printf("Usage: %s [<options>]\n"
204− " -t DELAY Action activation delay\n"
262+ " -t DELAY Action activation delay\n"
263+ " -c CHANGE_INTERVAL Interval to change action values\n"
205− " -h Show this help text\n"
264+ " -h Show this help text\n"
206 , argv[0]);
265 , argv[0]);
207 return 0;
266 return 0;
208 }
267 }
@@ -249,6 +308,11 @@ main (int argc, char **argv)
249 NULL);
308 NULL);
250
309
251 loop = g_main_loop_new (NULL, FALSE);
310 loop = g_main_loop_new (NULL, FALSE);
311+
312+ if (indicator.change_interval != -1) {
313+ g_timeout_add(indicator.change_interval, change_interval, &indicator);
314+ }
315+
252 g_main_loop_run (loop);
316 g_main_loop_run (loop);
253
317
254 g_object_unref (submenu);
318 g_object_unref (submenu);
tests/plugins/Dash/cardcreator/1.res+21−8
@@ -28,12 +28,27 @@ Item {
28 active: cardData && cardData["art"] || false;
28 active: cardData && cardData["art"] || false;
29 asynchronous: root.asynchronous;
29 asynchronous: root.asynchronous;
30 visible: status == Loader.Ready;
30 visible: status == Loader.Ready;
31− sourceComponent: UbuntuShape {
31+ sourceComponent: Item {
32− id: artShape;
32+ id: artShape;
33− objectName: "artShape";
33+ objectName: "artShape";
34− radius: "medium";
34+ property bool doShapeItem: components["art"]["conciergeMode"] !== true;
35− visible: image.status == Image.Ready;
35+ visible: image.status == Image.Ready;
36+ readonly property alias image: artImage.image;
37+ ShaderEffectSource {
38+ id: artShapeSource;
39+ sourceItem: artImage;
40+ anchors.centerIn: parent;
41+ width: 1;
42+ height: 1;
43+ hideSource: doShapeItem;
44+ }
45+ Shape {
46+ image: artShapeSource;
47+ anchors.fill: parent;
48+ visible: doShapeItem;
49+ radius: "medium";
50+ }
36− readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
51+ readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
37 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1;
52 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1;
38 Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
53 Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
39 Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
54 Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
@@ -51,11 +66,9 @@ Item {
51 objectName: "artImage";
66 objectName: "artImage";
52 source: cardData && cardData["art"] || "";
67 source: cardData && cardData["art"] || "";
53 asynchronous: root.asynchronous;
68 asynchronous: root.asynchronous;
54− visible: false;
55 width: root.width;
69 width: root.width;
56 height: width / artShape.aspect;
70 height: width / artShape.aspect;
57 }
71 }
58− image: artImage.image;
59 }
72 }
60 }
73 }
61 }
74 }
tests/plugins/Dash/cardcreator/3.res+31−18
@@ -28,34 +28,47 @@ Item {
28 active: cardData && cardData["art"] || false;
28 active: cardData && cardData["art"] || false;
29 asynchronous: root.asynchronous;
29 asynchronous: root.asynchronous;
30 visible: status == Loader.Ready;
30 visible: status == Loader.Ready;
31− sourceComponent: UbuntuShape {
31+ sourceComponent: Item {
32− id: artShape;
32+ id: artShape;
33− objectName: "artShape";
33+ objectName: "artShape";
34− radius: "medium";
34+ property bool doShapeItem: components["art"]["conciergeMode"] !== true;
35− visible: image.status == Image.Ready;
35+ visible: image.status == Image.Ready;
36+ readonly property alias image: artImage.image;
37+ ShaderEffectSource {
38+ id: artShapeSource;
39+ sourceItem: artImage;
40+ anchors.centerIn: parent;
41+ width: 1;
42+ height: 1;
43+ hideSource: doShapeItem;
44+ }
45+ Shape {
46+ image: artShapeSource;
47+ anchors.fill: parent;
48+ visible: doShapeItem;
49+ radius: "medium";
50+ }
36− readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
51+ readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
37− readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1;
52+ readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1;
38− Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
53+ Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
39− Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
54+ Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
40− function updateWidthHeightBindings() {
55+ function updateWidthHeightBindings() {
41− if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) {
56+ if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) {
42− width = root.fixedArtShapeSize.width;
57+ width = root.fixedArtShapeSize.width;
43− height = root.fixedArtShapeSize.height;
58+ height = root.fixedArtShapeSize.height;
44− } else {
59+ } else {
45 width = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.width });
60 width = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.width });
46 height = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.height });
61 height = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.height });
47 }
62 }
48− }
63+ }
49 CroppedImageMinimumSourceSize {
64 CroppedImageMinimumSourceSize {
50 id: artImage;
65 id: artImage;
51 objectName: "artImage";
66 objectName: "artImage";
52− source: cardData && cardData["art"] || "";
67+ source: cardData && cardData["art"] || "";
53 asynchronous: root.asynchronous;
68 asynchronous: root.asynchronous;
54− visible: false;
55 width: root.width;
69 width: root.width;
56 height: width / artShape.aspect;
70 height: width / artShape.aspect;
57 }
71 }
58− image: artImage.image;
59 }
72 }
60 }
73 }
61 }
74 }
tests/plugins/Dash/cardcreator/5.res+32−19
@@ -28,34 +28,47 @@ Item {
28 active: cardData && cardData["art"] || false;
28 active: cardData && cardData["art"] || false;
29 asynchronous: root.asynchronous;
29 asynchronous: root.asynchronous;
30 visible: status == Loader.Ready;
30 visible: status == Loader.Ready;
31− sourceComponent: UbuntuShape {
31+ sourceComponent: Item {
32− id: artShape;
32+ id: artShape;
33− objectName: "artShape";
33+ objectName: "artShape";
34− radius: "medium";
34+ property bool doShapeItem: components["art"]["conciergeMode"] !== true;
35− visible: image.status == Image.Ready;
35+ visible: image.status == Image.Ready;
36+ readonly property alias image: artImage.image;
37+ ShaderEffectSource {
38+ id: artShapeSource;
39+ sourceItem: artImage;
40+ anchors.centerIn: parent;
41+ width: 1;
42+ height: 1;
43+ hideSource: doShapeItem;
44+ }
45+ Shape {
46+ image: artShapeSource;
47+ anchors.fill: parent;
48+ visible: doShapeItem;
49+ radius: "medium";
50+ }
36− readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
51+ readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
37− readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1;
52+ readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1;
38− Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
53+ Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
39− Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
54+ Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
40− function updateWidthHeightBindings() {
55+ function updateWidthHeightBindings() {
41− if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) {
56+ if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) {
42− width = root.fixedArtShapeSize.width;
57+ width = root.fixedArtShapeSize.width;
43− height = root.fixedArtShapeSize.height;
58+ height = root.fixedArtShapeSize.height;
44− } else {
59+ } else {
45 width = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.width });
60 width = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.width });
46 height = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.height });
61 height = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.height });
47 }
62 }
48− }
63+ }
49 CroppedImageMinimumSourceSize {
64 CroppedImageMinimumSourceSize {
50 id: artImage;
65 id: artImage;
51 objectName: "artImage";
66 objectName: "artImage";
52− source: cardData && cardData["art"] || "";
67+ source: cardData && cardData["art"] || "";
53 asynchronous: root.asynchronous;
68 asynchronous: root.asynchronous;
54− visible: false;
55 width: root.width;
69 width: root.width;
56 height: width / artShape.aspect;
70 height: width / artShape.aspect;
57 }
71 }
58− image: artImage.image;
59 }
72 }
60 }
73 }
61 }
74 }
@@ -150,5 +163,5 @@ UbuntuShape {
150 radius: "medium";
163 radius: "medium";
151 borderSource: "radius_pressed.sci"
164 borderSource: "radius_pressed.sci"
152}
165}
153−implicitHeight: subtitleLabel.y + subtitleLabel.height + units.gu(1);
166+implicitHeight: artShapeHolder.height;
154}
167}
tests/plugins/Dash/horizontaljournaltest.cpp+3−3
@@ -32,19 +32,19 @@
32
32
33class WidthModel : public QAbstractListModel {
33class WidthModel : public QAbstractListModel {
34public:
34public:
35− QHash<int, QByteArray> roleNames() const
35+ QHash<int, QByteArray> roleNames() const override
36 {
36 {
37 QHash<int, QByteArray> roles;
37 QHash<int, QByteArray> roles;
38 roles.insert(Qt::DisplayRole, "modelWidth");
38 roles.insert(Qt::DisplayRole, "modelWidth");
39 return roles;
39 return roles;
40 }
40 }
41
41
42− int rowCount(const QModelIndex & /*parent*/) const
42+ int rowCount(const QModelIndex & /*parent*/) const override
43 {
43 {
44 return m_list.count();
44 return m_list.count();
45 }
45 }
46
46
47− QVariant data(const QModelIndex &index, int /*role*/) const
47+ QVariant data(const QModelIndex &index, int /*role*/) const override
48 {
48 {
49 return m_list[index.row()];
49 return m_list[index.row()];
50 }
50 }
tests/plugins/Dash/horizontaljournaltry.cpp+1−1
@@ -29,7 +29,7 @@
29class QWidthModela : public QStringListModel {
29class QWidthModela : public QStringListModel {
30 Q_OBJECT
30 Q_OBJECT
31public:
31public:
32− QHash<int, QByteArray> roleNames() const
32+ QHash<int, QByteArray> roleNames() const override
33 {
33 {
34 QHash<int, QByteArray> roles;
34 QHash<int, QByteArray> roles;
35 roles.insert(Qt::DisplayRole, "modelWidth");
35 roles.insert(Qt::DisplayRole, "modelWidth");
tests/plugins/Dash/listviewwithpageheadersectionexternalmodeltest.cpp+3−3
@@ -37,7 +37,7 @@ public:
37 list << "A" << "B" << "C" << "D" << "E" << "F" << "G" << "H";
37 list << "A" << "B" << "C" << "D" << "E" << "F" << "G" << "H";
38 }
38 }
39
39
40− int rowCount(const QModelIndex &parent) const
40+ int rowCount(const QModelIndex &parent) const override
41 {
41 {
42 if (parent.isValid())
42 if (parent.isValid())
43 return 0;
43 return 0;
@@ -45,14 +45,14 @@ public:
45 return list.count();
45 return list.count();
46 }
46 }
47
47
48− QVariant data(const QModelIndex &index, int role) const
48+ QVariant data(const QModelIndex &index, int role) const override
49 {
49 {
50 if (role == Qt::SizeHintRole) return 50;
50 if (role == Qt::SizeHintRole) return 50;
51 else if (role == Qt::DisplayRole) return list[index.row()];
51 else if (role == Qt::DisplayRole) return list[index.row()];
52 return QVariant();
52 return QVariant();
53 }
53 }
54
54
55− QHash<int, QByteArray> roleNames() const
55+ QHash<int, QByteArray> roleNames() const override
56 {
56 {
57 QHash<int, QByteArray> hash;
57 QHash<int, QByteArray> hash;
58 hash.insert(Qt::DisplayRole, "type");
58 hash.insert(Qt::DisplayRole, "type");
tests/plugins/Dash/organicgridtest.cpp+2−2
@@ -34,12 +34,12 @@ class DummyModel : public QAbstractListModel {
34public:
34public:
35 DummyModel() : m_count(0) {}
35 DummyModel() : m_count(0) {}
36
36
37− int rowCount(const QModelIndex & /*parent*/) const
37+ int rowCount(const QModelIndex & /*parent*/) const override
38 {
38 {
39 return m_count;
39 return m_count;
40 }
40 }
41
41
42− QVariant data(const QModelIndex & /*index*/, int /*role*/) const
42+ QVariant data(const QModelIndex & /*index*/, int /*role*/) const override
43 {
43 {
44 return QVariant();
44 return QVariant();
45 }
45 }
tests/plugins/Dash/organicgridtry.cpp+2−2
@@ -31,12 +31,12 @@ class DummyModel : public QAbstractListModel {
31public:
31public:
32 DummyModel() : m_count(0) {}
32 DummyModel() : m_count(0) {}
33
33
34− int rowCount(const QModelIndex & /*parent*/) const
34+ int rowCount(const QModelIndex & /*parent*/) const override
35 {
35 {
36 return m_count;
36 return m_count;
37 }
37 }
38
38
39− QVariant data(const QModelIndex & /*index*/, int /*role*/) const
39+ QVariant data(const QModelIndex & /*index*/, int /*role*/) const override
40 {
40 {
41 return QVariant();
41 return QVariant();
42 }
42 }
tests/plugins/Dash/verticaljournaltest.cpp+3−3
@@ -32,19 +32,19 @@
32
32
33class HeightModel : public QAbstractListModel {
33class HeightModel : public QAbstractListModel {
34public:
34public:
35− QHash<int, QByteArray> roleNames() const
35+ QHash<int, QByteArray> roleNames() const override
36 {
36 {
37 QHash<int, QByteArray> roles;
37 QHash<int, QByteArray> roles;
38 roles.insert(Qt::DisplayRole, "modelHeight");
38 roles.insert(Qt::DisplayRole, "modelHeight");
39 return roles;
39 return roles;
40 }
40 }
41
41
42− int rowCount(const QModelIndex & /*parent*/) const
42+ int rowCount(const QModelIndex & /*parent*/) const override
43 {
43 {
44 return m_list.count();
44 return m_list.count();
45 }
45 }
46
46
47− QVariant data(const QModelIndex &index, int /*role*/) const
47+ QVariant data(const QModelIndex &index, int /*role*/) const override
48 {
48 {
49 return m_list[index.row()];
49 return m_list[index.row()];
50 }
50 }
tests/plugins/Dash/verticaljournaltry.cpp+1−1
@@ -29,7 +29,7 @@
29class QHeightModel : public QStringListModel {
29class QHeightModel : public QStringListModel {
30 Q_OBJECT
30 Q_OBJECT
31public:
31public:
32− QHash<int, QByteArray> roleNames() const
32+ QHash<int, QByteArray> roleNames() const override
33 {
33 {
34 QHash<int, QByteArray> roles;
34 QHash<int, QByteArray> roles;
35 roles.insert(Qt::DisplayRole, "modelHeight");
35 roles.insert(Qt::DisplayRole, "modelHeight");
tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt+1−1
@@ -1,5 +1,5 @@
1pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
1pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
2−pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=5)
2+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=6)
3
3
4include_directories(
4include_directories(
5 ${CMAKE_CURRENT_SOURCE_DIR}
5 ${CMAKE_CURRENT_SOURCE_DIR}
tests/plugins/LightDM/CMakeLists.txt+35−16
@@ -1,8 +1,38 @@
1+add_definitions(
2+ -DCURRENT_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}"
3+ )
4+include_directories(
5+ ${CMAKE_CURRENT_BINARY_DIR}
6+ )
7+
1add_executable(GreeterDBusTestExec
8add_executable(GreeterDBusTestExec
2 dbus.cpp
9 dbus.cpp
3 ${CMAKE_SOURCE_DIR}/plugins/LightDM/Greeter.cpp
10 ${CMAKE_SOURCE_DIR}/plugins/LightDM/Greeter.cpp
4 )
11 )
5qt5_use_modules(GreeterDBusTestExec Core DBus Quick Test)
12qt5_use_modules(GreeterDBusTestExec Core DBus Quick Test)
13+target_link_libraries(GreeterDBusTestExec
14+ -L${CMAKE_BINARY_DIR}/tests/mocks/LightDM/liblightdm
15+ -llightdm-qt5-2
16+ )
17+target_include_directories(GreeterDBusTestExec PUBLIC
18+ ${CMAKE_SOURCE_DIR}/plugins/LightDM
19+ ${CMAKE_SOURCE_DIR}/tests/mocks/LightDM
20+ )
21+add_binary_qml_test(GreeterDBus "${CMAKE_BINARY_DIR}/tests/mocks/LightDM/liblightdm" MockLightDM "QML2_IMPORT_PATH=${CMAKE_BINARY_DIR}/tests/mocks")
22+
23+add_executable(GreeterPamTestExec
24+ pam.cpp
25+ ${CMAKE_SOURCE_DIR}/plugins/LightDM/liblightdm/GreeterPrivate.cpp
26+ )
27+qt5_use_modules(GreeterPamTestExec Concurrent Core Test)
28+target_link_libraries(GreeterPamTestExec
29+ integratedLightDM
30+ )
31+target_include_directories(GreeterPamTestExec PUBLIC
32+ ${CMAKE_SOURCE_DIR}/plugins/LightDM/liblightdm
33+ )
34+add_qmltest_target(testGreeterPam "${CMAKE_CURRENT_BINARY_DIR}/GreeterPamTestExec" TRUE FALSE)
35+add_dependencies(testGreeterPam GreeterPamTestExec)
6
36
7add_executable(GreeterUsersModelTestExec
37add_executable(GreeterUsersModelTestExec
8 usersmodel.cpp
38 usersmodel.cpp
@@ -10,24 +40,13 @@ add_executable(GreeterUsersModelTestExec
10 ${CMAKE_SOURCE_DIR}/plugins/Utils/unitysortfilterproxymodelqml.cpp
40 ${CMAKE_SOURCE_DIR}/plugins/Utils/unitysortfilterproxymodelqml.cpp
11 )
41 )
12qt5_use_modules(GreeterUsersModelTestExec Core Test)
42qt5_use_modules(GreeterUsersModelTestExec Core Test)
13−
43+target_link_libraries(GreeterUsersModelTestExec
14−include_directories(
44+ -L${CMAKE_BINARY_DIR}/tests/mocks/LightDM/liblightdm
15− ${CMAKE_CURRENT_BINARY_DIR}
45+ -llightdm-qt5-2
46+ )
47+target_include_directories(GreeterUsersModelTestExec PUBLIC
16 ${CMAKE_SOURCE_DIR}/plugins/LightDM
48 ${CMAKE_SOURCE_DIR}/plugins/LightDM
17 ${CMAKE_SOURCE_DIR}/plugins/Utils
49 ${CMAKE_SOURCE_DIR}/plugins/Utils
18 ${CMAKE_SOURCE_DIR}/tests/mocks/LightDM
50 ${CMAKE_SOURCE_DIR}/tests/mocks/LightDM
19 )
51 )
20−
21−target_link_libraries(GreeterDBusTestExec
22− MockLightDM
23− )
24−
25−target_link_libraries(GreeterUsersModelTestExec
26− MockLightDM
27− )
28−
29−add_definitions(-DCURRENT_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
30−
31−add_binary_qml_test(GreeterDBus "${CMAKE_BINARY_DIR}/tests/mocks/LightDM/liblightdm" MockLightDM "QML2_IMPORT_PATH=${CMAKE_BINARY_DIR}/tests/mocks")
32−
33add_binary_qml_test(GreeterUsersModel "${CMAKE_BINARY_DIR}/tests/mocks/LightDM/liblightdm" MockLightDM "LIBLIGHTDM_MOCK_MODE=full")
52add_binary_qml_test(GreeterUsersModel "${CMAKE_BINARY_DIR}/tests/mocks/LightDM/liblightdm" MockLightDM "LIBLIGHTDM_MOCK_MODE=full")
tests/plugins/LightDM/pam.cppnew file+52
@@ -0,0 +1,52 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "GreeterPrivate.h"
18+
19+#include <QtTest>
20+
21+class GreeterPamTest : public QObject
22+{
23+ Q_OBJECT
24+
25+private Q_SLOTS:
26+
27+ void init()
28+ {
29+ m_greeterpriv = new QLightDM::GreeterPrivate();
30+ }
31+
32+ void cleanup()
33+ {
34+ delete m_greeterpriv;
35+ QTRY_COMPARE(QThreadPool::globalInstance()->activeThreadCount(), 0);
36+ }
37+
38+ void testRapidFireAuthentication()
39+ {
40+ m_greeterpriv->authenticationUser = qgetenv("USER");
41+ for (int i = 0; i < 100; i++) {
42+ m_greeterpriv->handleAuthenticate();
43+ }
44+ }
45+
46+private:
47+ QLightDM::GreeterPrivate *m_greeterpriv;
48+};
49+
50+QTEST_GUILESS_MAIN(GreeterPamTest)
51+
52+#include "pam.moc"
tests/plugins/Ubuntu/Gestures/CMakeLists.txt+2−1
@@ -22,7 +22,7 @@ add_definitions(-DUBUNTU_GESTURES_PLUGIN_DIR="${CMAKE_BINARY_DIR}/plugins")
22add_definitions(-DTESTS_UTILS_MODULES_DIR="${CMAKE_BINARY_DIR}/tests/utils/modules")
22add_definitions(-DTESTS_UTILS_MODULES_DIR="${CMAKE_BINARY_DIR}/tests/utils/modules")
23
23
24macro(add_gesture_ui_test CLASSNAME)
24macro(add_gesture_ui_test CLASSNAME)
25− add_executable(${CLASSNAME}TestExec tst_${CLASSNAME}.cpp GestureTest.cpp)
25+ add_executable(${CLASSNAME}TestExec tst_${CLASSNAME}.cpp GestureTest.cpp TestItem.cpp)
26 qt5_use_modules(${CLASSNAME}TestExec Test Core Qml Gui Quick)
26 qt5_use_modules(${CLASSNAME}TestExec Test Core Qml Gui Quick)
27 target_link_libraries(${CLASSNAME}TestExec UbuntuGesturesQml UbuntuGestures)
27 target_link_libraries(${CLASSNAME}TestExec UbuntuGesturesQml UbuntuGestures)
28
28
@@ -46,6 +46,7 @@ macro(add_gesture_test CLASSNAME)
46endmacro(add_gesture_test)
46endmacro(add_gesture_test)
47
47
48add_gesture_ui_test(DirectionalDragArea)
48add_gesture_ui_test(DirectionalDragArea)
49+add_gesture_ui_test(FloatingFlickable)
49add_gesture_ui_test(PressedOutsideNotifier)
50add_gesture_ui_test(PressedOutsideNotifier)
50add_gesture_ui_test(TouchDispatcher)
51add_gesture_ui_test(TouchDispatcher)
51add_gesture_ui_test(TouchGate)
52add_gesture_ui_test(TouchGate)
tests/plugins/Ubuntu/Gestures/GestureTest.cpp+2−1
@@ -53,7 +53,8 @@ void GestureTest::init()
53
53
54 m_fakeTimerFactory = new FakeTimerFactory;
54 m_fakeTimerFactory = new FakeTimerFactory;
55
55
56− m_touchRegistry = new TouchRegistry(nullptr, m_fakeTimerFactory);
56+ m_touchRegistry = TouchRegistry::instance();
57+ m_touchRegistry->setTimerFactory(m_fakeTimerFactory);
57 m_view->installEventFilter(m_touchRegistry);
58 m_view->installEventFilter(m_touchRegistry);
58
59
59 qApp->processEvents();
60 qApp->processEvents();
tests/plugins/Ubuntu/Gestures/TestItem.cppnew file+30
@@ -0,0 +1,30 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "TestItem.h"
18+
19+#include <QTouchEvent>
20+
21+void TestItem::touchEvent(QTouchEvent *event)
22+{
23+ QTouchEvent *clonedEvent = new QTouchEvent(event->type(),
24+ event->device(),
25+ event->modifiers(),
26+ event->touchPointStates(),
27+ event->touchPoints());
28+
29+ touchEventsReceived.append(QSharedPointer<QTouchEvent>(clonedEvent));
30+}
tests/plugins/Ubuntu/Gestures/TestItem.hnew file+33
@@ -0,0 +1,33 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef UBUNTUGESTURES_TEST_ITEM_H
18+#define UBUNTUGESTURES_TEST_ITEM_H
19+
20+#include <QQuickItem>
21+
22+class TestItem : public QQuickItem
23+{
24+ Q_OBJECT
25+
26+public:
27+ QList<QSharedPointer<QTouchEvent>> touchEventsReceived;
28+
29+protected:
30+ void touchEvent(QTouchEvent *event) override;
31+};
32+
33+#endif // UBUNTUGESTURES_TEST_ITEM_H
tests/plugins/Ubuntu/Gestures/tst_AxisVelocityCalculator.cpp+1−1
@@ -24,7 +24,7 @@ class FakeTimeSource : public UbuntuGestures::TimeSource {
24public:
24public:
25 FakeTimeSource() : m_value(0) {}
25 FakeTimeSource() : m_value(0) {}
26
26
27− virtual qint64 msecsSinceReference() {
27+ qint64 msecsSinceReference() override {
28 return m_value;
28 return m_value;
29 }
29 }
30
30
tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp+21−21
@@ -84,7 +84,7 @@ class tst_DirectionalDragArea: public GestureTest
84public:
84public:
85 tst_DirectionalDragArea();
85 tst_DirectionalDragArea();
86private Q_SLOTS:
86private Q_SLOTS:
87− void init(); // called right before each and every test function is executed
87+ void init() override; // called right before each and every test function is executed
88
88
89 void dragWithShortDirectionChange();
89 void dragWithShortDirectionChange();
90 void recognitionTimerUsage();
90 void recognitionTimerUsage();
@@ -202,7 +202,7 @@ void tst_DirectionalDragArea::dragWithShortDirectionChange()
202 DirectionalDragArea *edgeDragArea =
202 DirectionalDragArea *edgeDragArea =
203 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
203 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
204 QVERIFY(edgeDragArea != 0);
204 QVERIFY(edgeDragArea != 0);
205− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
205+ edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
206 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
206 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
207
207
208 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
208 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
@@ -297,7 +297,7 @@ void tst_DirectionalDragArea::sceneXAndX()
297 DirectionalDragArea *edgeDragArea =
297 DirectionalDragArea *edgeDragArea =
298 m_view->rootObject()->findChild<DirectionalDragArea*>("hnDragArea");
298 m_view->rootObject()->findChild<DirectionalDragArea*>("hnDragArea");
299 QVERIFY(edgeDragArea != 0);
299 QVERIFY(edgeDragArea != 0);
300− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
300+ edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
301 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
301 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
302 edgeDragArea->setImmediateRecognition(true);
302 edgeDragArea->setImmediateRecognition(true);
303
303
@@ -326,7 +326,7 @@ void tst_DirectionalDragArea::sceneYAndY()
326 DirectionalDragArea *edgeDragArea =
326 DirectionalDragArea *edgeDragArea =
327 m_view->rootObject()->findChild<DirectionalDragArea*>("vnDragArea");
327 m_view->rootObject()->findChild<DirectionalDragArea*>("vnDragArea");
328 QVERIFY(edgeDragArea != 0);
328 QVERIFY(edgeDragArea != 0);
329− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
329+ edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
330 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
330 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
331 edgeDragArea->setImmediateRecognition(true);
331 edgeDragArea->setImmediateRecognition(true);
332
332
@@ -357,7 +357,7 @@ void tst_DirectionalDragArea::twoFingerTap()
357 DirectionalDragArea *edgeDragArea =
357 DirectionalDragArea *edgeDragArea =
358 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
358 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
359 QVERIFY(edgeDragArea != 0);
359 QVERIFY(edgeDragArea != 0);
360− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
360+ edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
361 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
361 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
362
362
363 // Make touches evenly spaced along the edgeDragArea
363 // Make touches evenly spaced along the edgeDragArea
@@ -439,7 +439,7 @@ void tst_DirectionalDragArea::movingDDA()
439 DirectionalDragArea *edgeDragArea =
439 DirectionalDragArea *edgeDragArea =
440 rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea");
440 rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea");
441 Q_ASSERT(edgeDragArea != 0);
441 Q_ASSERT(edgeDragArea != 0);
442− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
442+ edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
443 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
443 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
444
444
445 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
445 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
@@ -479,7 +479,7 @@ void tst_DirectionalDragArea::ignoreOldFinger()
479 DirectionalDragArea *edgeDragArea =
479 DirectionalDragArea *edgeDragArea =
480 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
480 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
481 Q_ASSERT(edgeDragArea != 0);
481 Q_ASSERT(edgeDragArea != 0);
482− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
482+ edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
483 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
483 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
484
484
485 // Make touches evenly spaced along the edgeDragArea
485 // Make touches evenly spaced along the edgeDragArea
@@ -542,7 +542,7 @@ void tst_DirectionalDragArea::rotated()
542 DirectionalDragArea *edgeDragArea =
542 DirectionalDragArea *edgeDragArea =
543 rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea");
543 rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea");
544 Q_ASSERT(edgeDragArea != 0);
544 Q_ASSERT(edgeDragArea != 0);
545− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
545+ edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
546 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
546 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
547
547
548 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
548 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
@@ -582,7 +582,7 @@ void tst_DirectionalDragArea::sceneDistance()
582 DirectionalDragArea *edgeDragArea =
582 DirectionalDragArea *edgeDragArea =
583 rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea");
583 rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea");
584 Q_ASSERT(edgeDragArea != 0);
584 Q_ASSERT(edgeDragArea != 0);
585− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
585+ edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
586 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
586 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
587
587
588 // to disable the position smoothing so that we can more easily check sceneDistance values
588 // to disable the position smoothing so that we can more easily check sceneDistance values
@@ -640,7 +640,7 @@ void tst_DirectionalDragArea::disabledWhileDragging()
640 DirectionalDragArea *edgeDragArea =
640 DirectionalDragArea *edgeDragArea =
641 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
641 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
642 Q_ASSERT(edgeDragArea != 0);
642 Q_ASSERT(edgeDragArea != 0);
643− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
643+ edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
644 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
644 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
645
645
646 QPointF touchPoint = calculateInitialTouchPos(edgeDragArea);
646 QPointF touchPoint = calculateInitialTouchPos(edgeDragArea);
@@ -678,7 +678,7 @@ void tst_DirectionalDragArea::oneFingerDownFollowedByLateSecondFingerDown()
678 DirectionalDragArea *edgeDragArea =
678 DirectionalDragArea *edgeDragArea =
679 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
679 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
680 Q_ASSERT(edgeDragArea != 0);
680 Q_ASSERT(edgeDragArea != 0);
681− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
681+ edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
682 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
682 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
683
683
684 // Disable some constraints we're not interested in
684 // Disable some constraints we're not interested in
@@ -753,7 +753,7 @@ void tst_DirectionalDragArea::givesUpWhenLosesTouch()
753 DirectionalDragArea *edgeDragArea =
753 DirectionalDragArea *edgeDragArea =
754 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
754 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
755 Q_ASSERT(edgeDragArea != 0);
755 Q_ASSERT(edgeDragArea != 0);
756− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
756+ edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
757 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
757 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
758
758
759 // Disable some constraints we're not interested in
759 // Disable some constraints we're not interested in
@@ -798,7 +798,7 @@ void tst_DirectionalDragArea::threeFingerDrag()
798 DirectionalDragArea *edgeDragArea =
798 DirectionalDragArea *edgeDragArea =
799 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
799 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
800 Q_ASSERT(edgeDragArea != 0);
800 Q_ASSERT(edgeDragArea != 0);
801− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
801+ edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
802 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
802 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
803
803
804 // Disable some constraints we're not interested in
804 // Disable some constraints we're not interested in
@@ -867,7 +867,7 @@ void tst_DirectionalDragArea::immediateRecognitionWhenConstraintsDisabled()
867 DirectionalDragArea *edgeDragArea =
867 DirectionalDragArea *edgeDragArea =
868 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
868 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
869 Q_ASSERT(edgeDragArea != 0);
869 Q_ASSERT(edgeDragArea != 0);
870− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
870+ edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
871 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
871 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
872
872
873 // Disable the minimum amount of constraints to ensure immediate recognition
873 // Disable the minimum amount of constraints to ensure immediate recognition
@@ -900,7 +900,7 @@ void tst_DirectionalDragArea::withdrawTouchOwnershipCandidacyIfDisabledDuringRec
900 DirectionalDragArea *edgeDragArea =
900 DirectionalDragArea *edgeDragArea =
901 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
901 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
902 Q_ASSERT(edgeDragArea != 0);
902 Q_ASSERT(edgeDragArea != 0);
903− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
903+ edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
904 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
904 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
905
905
906 QPointF touchPoint = calculateInitialTouchPos(edgeDragArea);
906 QPointF touchPoint = calculateInitialTouchPos(edgeDragArea);
@@ -964,7 +964,7 @@ void tst_DirectionalDragArea::gettingTouchOwnershipMakesMouseAreaBehindGetCancel
964 DirectionalDragArea *edgeDragArea =
964 DirectionalDragArea *edgeDragArea =
965 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
965 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
966 QVERIFY(edgeDragArea != nullptr);
966 QVERIFY(edgeDragArea != nullptr);
967− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
967+ edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
968 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
968 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
969
969
970 QQuickMouseArea *mouseArea =
970 QQuickMouseArea *mouseArea =
@@ -1014,7 +1014,7 @@ void tst_DirectionalDragArea::interleavedTouches()
1014 DirectionalDragArea *edgeDragArea =
1014 DirectionalDragArea *edgeDragArea =
1015 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
1015 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
1016 QVERIFY(edgeDragArea != 0);
1016 QVERIFY(edgeDragArea != 0);
1017− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
1017+ edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
1018 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1018 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1019
1019
1020 QPointF touch0 = edgeDragArea->mapToScene(
1020 QPointF touch0 = edgeDragArea->mapToScene(
@@ -1109,7 +1109,7 @@ void tst_DirectionalDragArea::makoRightEdgeDrag()
1109 DirectionalDragArea *edgeDragArea =
1109 DirectionalDragArea *edgeDragArea =
1110 m_view->rootObject()->findChild<DirectionalDragArea*>("hnDragArea");
1110 m_view->rootObject()->findChild<DirectionalDragArea*>("hnDragArea");
1111 QVERIFY(edgeDragArea != nullptr);
1111 QVERIFY(edgeDragArea != nullptr);
1112− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
1112+ edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
1113 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1113 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1114
1114
1115 StatusSpy *statusSpy = new StatusSpy(edgeDragArea);
1115 StatusSpy *statusSpy = new StatusSpy(edgeDragArea);
@@ -1154,7 +1154,7 @@ void tst_DirectionalDragArea::makoRightEdgeDrag_verticalDownwards()
1154 DirectionalDragArea *edgeDragArea =
1154 DirectionalDragArea *edgeDragArea =
1155 m_view->rootObject()->findChild<DirectionalDragArea*>("hnDragArea");
1155 m_view->rootObject()->findChild<DirectionalDragArea*>("hnDragArea");
1156 QVERIFY(edgeDragArea != nullptr);
1156 QVERIFY(edgeDragArea != nullptr);
1157− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
1157+ edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
1158 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1158 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1159
1159
1160 edgeDragArea->d->setPixelsPerMm(320.0 /*mako ppi*/ * 0.03937 /* inches per mm*/);
1160 edgeDragArea->d->setPixelsPerMm(320.0 /*mako ppi*/ * 0.03937 /* inches per mm*/);
@@ -1198,7 +1198,7 @@ void tst_DirectionalDragArea::makoLeftEdgeDrag_slowStart()
1198 DirectionalDragArea *edgeDragArea =
1198 DirectionalDragArea *edgeDragArea =
1199 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
1199 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
1200 QVERIFY(edgeDragArea != nullptr);
1200 QVERIFY(edgeDragArea != nullptr);
1201− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
1201+ edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
1202 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1202 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1203
1203
1204 edgeDragArea->d->setPixelsPerMm(320.0 /*mako ppi*/ * 0.03937 /* inches per mm*/);
1204 edgeDragArea->d->setPixelsPerMm(320.0 /*mako ppi*/ * 0.03937 /* inches per mm*/);
@@ -1262,7 +1262,7 @@ void tst_DirectionalDragArea::makoLeftEdgeDrag_movesSlightlyBackwardsOnStart()
1262 DirectionalDragArea *edgeDragArea =
1262 DirectionalDragArea *edgeDragArea =
1263 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
1263 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
1264 QVERIFY(edgeDragArea != nullptr);
1264 QVERIFY(edgeDragArea != nullptr);
1265− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
1265+ edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
1266 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1266 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1267
1267
1268 edgeDragArea->d->setPixelsPerMm(320.0 /*mako ppi*/ * 0.03937 /* inches per mm*/);
1268 edgeDragArea->d->setPixelsPerMm(320.0 /*mako ppi*/ * 0.03937 /* inches per mm*/);
tests/plugins/Ubuntu/Gestures/tst_FloatingFlickable.cppnew file+122
@@ -0,0 +1,122 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include <QtTest>
18+#include <QQuickView>
19+
20+// Ubuntu.Gestures plugin
21+#include <DirectionalDragArea.h>
22+#include <FloatingFlickable.h>
23+
24+#include "GestureTest.h"
25+#include "TestItem.h"
26+
27+using namespace UbuntuGestures;
28+
29+class tst_FloatingFlickable: public GestureTest
30+{
31+ Q_OBJECT
32+public:
33+ tst_FloatingFlickable();
34+private Q_SLOTS:
35+ void tapGoesThrough();
36+ void flickChangesContentX();
37+ void flickChangesContentY();
38+};
39+
40+tst_FloatingFlickable::tst_FloatingFlickable()
41+ : GestureTest(QStringLiteral("tst_FloatingFlickable.qml"))
42+{
43+}
44+
45+void tst_FloatingFlickable::tapGoesThrough()
46+{
47+ FloatingFlickable *floatingFlickable =
48+ m_view->rootObject()->findChild<FloatingFlickable*>("floatingFlickable");
49+ QVERIFY(floatingFlickable != nullptr);
50+
51+ TestItem *testItem = new TestItem;
52+ testItem->setWidth(floatingFlickable->width());
53+ testItem->setHeight(floatingFlickable->height());
54+ testItem->setParentItem(m_view->rootObject());
55+ testItem->setZ(1.0);
56+
57+ floatingFlickable->setZ(2.0);
58+
59+ QTest::touchEvent(m_view, m_device)
60+ .press(0, QPoint(floatingFlickable->width()/2, floatingFlickable->height()/2));
61+
62+ QCOMPARE(testItem->touchEventsReceived.count(), 1);
63+}
64+
65+void tst_FloatingFlickable::flickChangesContentX()
66+{
67+ FloatingFlickable *floatingFlickable =
68+ m_view->rootObject()->findChild<FloatingFlickable*>("floatingFlickable");
69+ QVERIFY(floatingFlickable != nullptr);
70+
71+ floatingFlickable->m_dragArea->removeTimeConstraints();
72+
73+ qreal startContentX = floatingFlickable->contentX();
74+
75+ QPoint startPos(floatingFlickable->width() - 5, 10);
76+ int stepCount = 20;
77+ int step = (startPos.x() - 5) / stepCount;
78+
79+ QTest::touchEvent(m_view, m_device).press(0, startPos);
80+ for (int i = 0; i < stepCount; ++i) {
81+ QTest::qWait(10);
82+ QPoint touchPos = startPos - QPoint(step*i, 0);
83+ QTest::touchEvent(m_view, m_device).move(0, touchPos);
84+ }
85+
86+ QTest::qWait(10);
87+ QTest::touchEvent(m_view, m_device).release(0, QPoint(5, 10));
88+
89+ QVERIFY(floatingFlickable->contentX() > (startContentX + floatingFlickable->width()/2));
90+}
91+
92+void tst_FloatingFlickable::flickChangesContentY()
93+{
94+ FloatingFlickable *floatingFlickable =
95+ m_view->rootObject()->findChild<FloatingFlickable*>("floatingFlickable");
96+ QVERIFY(floatingFlickable != nullptr);
97+
98+ floatingFlickable->setDirection(Direction::Vertical);
99+ floatingFlickable->m_dragArea->removeTimeConstraints();
100+
101+ qreal startContentY = floatingFlickable->contentY();
102+
103+ QPoint startPos(10, floatingFlickable->height() - 5);
104+ int stepCount = 20;
105+ int step = (startPos.y() - 5) / stepCount;
106+
107+ QTest::touchEvent(m_view, m_device).press(0, startPos);
108+ for (int i = 0; i < stepCount; ++i) {
109+ QTest::qWait(10);
110+ QPoint touchPos = startPos - QPoint(0, step*i);
111+ QTest::touchEvent(m_view, m_device).move(0, touchPos);
112+ }
113+
114+ QTest::qWait(10);
115+ QTest::touchEvent(m_view, m_device).release(0, QPoint(10, 5));
116+
117+ QVERIFY(floatingFlickable->contentY() > (startContentY + floatingFlickable->height()/2));
118+}
119+
120+QTEST_MAIN(tst_FloatingFlickable)
121+
122+#include "tst_FloatingFlickable.moc"
tests/plugins/Ubuntu/Gestures/tst_FloatingFlickable.qmlnew file+80
@@ -0,0 +1,80 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import Ubuntu.Components 0.1
19+import Ubuntu.Gestures 0.1
20+import Unity.Test 0.1
21+
22+Rectangle {
23+ id: root
24+ width: units.gu(60)
25+ height: units.gu(60)
26+ color: "white"
27+
28+ Binding {
29+ target: MouseTouchAdaptor
30+ property: "enabled"
31+ value: true
32+ }
33+
34+ Grid {
35+ id: colorGrid
36+ readonly property bool horizontal: floatingFlickable.direction === Direction.Horizontal
37+ x: horizontal ? -floatingFlickable.contentX : 0
38+ y: horizontal ? 0 : -floatingFlickable.contentY
39+ rows: horizontal ? 1 : 100
40+ columns: horizontal ? 100 : 1
41+ Repeater {
42+ model: 100
43+ Rectangle {
44+ width: colorGrid.horizontal ? units.gu(12) : root.width
45+ height: colorGrid.horizontal ? root.height : units.gu(12)
46+ color: mouseArea.pressed ? "red"
47+ : Qt.rgba(Math.random(), Math.random(), Math.random(), 1)
48+ MouseArea {
49+ id: mouseArea
50+ anchors.fill: parent
51+ }
52+ }
53+ }
54+ }
55+
56+ FloatingFlickable {
57+ id: floatingFlickable
58+ objectName: "floatingFlickable"
59+ anchors.fill: parent
60+ contentWidth: colorGrid.width
61+ contentHeight: colorGrid.height
62+ }
63+
64+ Button {
65+ anchors.bottom: parent.bottom
66+ anchors.right: parent.right
67+ anchors.margins: units.gu(1)
68+
69+ text: floatingFlickable.direction === Direction.Horizontal ? "Horizontal" : "Vertical"
70+ activeFocusOnPress: false
71+
72+ onClicked: {
73+ if (floatingFlickable.direction === Direction.Horizontal) {
74+ floatingFlickable.direction = Direction.Vertical;
75+ } else {
76+ floatingFlickable.direction = Direction.Horizontal;
77+ }
78+ }
79+ }
80+}
tests/plugins/Ubuntu/Gestures/tst_PressedOutsideNotifier.cpp+1−1
@@ -28,7 +28,7 @@ class tst_PressedOutsideNotifier: public GestureTest
28public:
28public:
29 tst_PressedOutsideNotifier();
29 tst_PressedOutsideNotifier();
30private Q_SLOTS:
30private Q_SLOTS:
31− void init(); // called right before each and every test function is executed
31+ void init() override; // called right before each and every test function is executed
32
32
33 void touchOutsideAreaTriggersSignal();
33 void touchOutsideAreaTriggersSignal();
34 void touchInsideAreaHasNoEffect();
34 void touchInsideAreaHasNoEffect();
tests/plugins/Ubuntu/Gestures/tst_TouchGate.cpp+2−25
@@ -29,16 +29,7 @@
29#include <TouchGate.h>
29#include <TouchGate.h>
30#include <TouchRegistry.h>
30#include <TouchRegistry.h>
31
31
32−class TestItem : public QQuickItem
32+#include "TestItem.h"
33−{
34− Q_OBJECT
35−
36−public:
37− QList<QSharedPointer<QTouchEvent>> touchEventsReceived;
38−
39−protected:
40− void touchEvent(QTouchEvent *event) override;
41−};
42
33
43class CandidateItem : public QQuickItem
34class CandidateItem : public QQuickItem
44{
35{
@@ -104,10 +95,9 @@ void tst_TouchGate::cleanupTestCase()
104
95
105void tst_TouchGate::init()
96void tst_TouchGate::init()
106{
97{
107− touchRegistry = new TouchRegistry;
98+ touchRegistry = TouchRegistry::instance();
108
99
109 view = createView();
100 view = createView();
110− view->installEventFilter(touchRegistry);
111 view->setSource(QUrl::fromLocalFile("touchGateExample.qml"));
101 view->setSource(QUrl::fromLocalFile("touchGateExample.qml"));
112 view->show();
102 view->show();
113 QVERIFY(QTest::qWaitForWindowExposed(view));
103 QVERIFY(QTest::qWaitForWindowExposed(view));
@@ -381,19 +371,6 @@ void tst_TouchGate::disabledWhileHoldingTouch()
381 }
371 }
382}
372}
383
373
384−///////////// TestItem /////////////////////////////////////////////////////////////
385−
386−void TestItem::touchEvent(QTouchEvent *event)
387−{
388− QTouchEvent *clonedEvent = new QTouchEvent(event->type(),
389− event->device(),
390− event->modifiers(),
391− event->touchPointStates(),
392− event->touchPoints());
393−
394− touchEventsReceived.append(QSharedPointer<QTouchEvent>(clonedEvent));
395−}
396−
397///////////// CandidateItem /////////////////////////////////////////////////////////////
374///////////// CandidateItem /////////////////////////////////////////////////////////////
398
375
399void CandidateItem::touchEvent(QTouchEvent *event)
376void CandidateItem::touchEvent(QTouchEvent *event)
tests/plugins/Unity/Indicators/menucontentactivatortest.cpp+2−2
@@ -30,8 +30,8 @@ public:
30 : UnityIndicators::AbstractTimer(parent)
30 : UnityIndicators::AbstractTimer(parent)
31 {}
31 {}
32
32
33− virtual int interval() const { return m_duration; }
33+ int interval() const override { return m_duration; }
34− virtual void setInterval(int msecs) { m_duration = msecs; }
34+ void setInterval(int msecs) override { m_duration = msecs; }
35
35
36 void emitTimeout() {
36 void emitTimeout() {
37 if (isRunning()) {
37 if (isRunning()) {
tests/plugins/Unity/Launcher/CMakeLists.txt−1
@@ -1,6 +1,5 @@
1pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
1pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
2pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
2pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
3−pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=5)
4
3
5include_directories(
4include_directories(
6 ${CMAKE_CURRENT_SOURCE_DIR}
5 ${CMAKE_CURRENT_SOURCE_DIR}
tests/plugins/Unity/Launcher/launchermodeltest.cpp+24−22
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright 2013-2014 Canonical Ltd.
2+ * Copyright 2013-2015 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 Lesser General Public License as published by
5 * it under the terms of the GNU Lesser General Public License as published by
@@ -39,19 +39,21 @@ class MockApp: public unity::shell::application::ApplicationInfoInterface
39 Q_OBJECT
39 Q_OBJECT
40public:
40public:
41 MockApp(const QString &appId, QObject *parent = 0): ApplicationInfoInterface(appId, parent), m_appId(appId), m_focused(false) { }
41 MockApp(const QString &appId, QObject *parent = 0): ApplicationInfoInterface(appId, parent), m_appId(appId), m_focused(false) { }
42− QString appId() const { return m_appId; }
42+ QString appId() const override { return m_appId; }
43− QString name() const { return "mock"; }
43+ QString name() const override { return "mock"; }
44− QString comment() const { return "this is a mock"; }
44+ QString comment() const override { return "this is a mock"; }
45− QUrl icon() const { return QUrl(); }
45+ QUrl icon() const override { return QUrl(); }
46− ApplicationInfoInterface::Stage stage() const { return ApplicationInfoInterface::MainStage; }
46+ ApplicationInfoInterface::Stage stage() const override { return ApplicationInfoInterface::MainStage; }
47− ApplicationInfoInterface::State state() const { return ApplicationInfoInterface::Running; }
47+ ApplicationInfoInterface::State state() const override { return ApplicationInfoInterface::Running; }
48− bool focused() const { return m_focused; }
48+ bool focused() const override { return m_focused; }
49 QString splashTitle() const override { return QString(); }
49 QString splashTitle() const override { return QString(); }
50 QUrl splashImage() const override { return QUrl(); }
50 QUrl splashImage() const override { return QUrl(); }
51 bool splashShowHeader() const override { return true; }
51 bool splashShowHeader() const override { return true; }
52 QColor splashColor() const override { return QColor(0,0,0,0); }
52 QColor splashColor() const override { return QColor(0,0,0,0); }
53 QColor splashColorHeader() const override { return QColor(0,0,0,0); }
53 QColor splashColorHeader() const override { return QColor(0,0,0,0); }
54 QColor splashColorFooter() const override { return QColor(0,0,0,0); }
54 QColor splashColorFooter() const override { return QColor(0,0,0,0); }
55+ Qt::ScreenOrientations supportedOrientations() const override { return Qt::PortraitOrientation; }
56+ bool rotatesWindowContents() const override { return false; }
55
57
56 // Methods used for mocking (not in the interface)
58 // Methods used for mocking (not in the interface)
57 void setFocused(bool focused) { m_focused = focused; Q_EMIT focusedChanged(focused); }
59 void setFocused(bool focused) { m_focused = focused; Q_EMIT focusedChanged(focused); }
@@ -66,16 +68,16 @@ class MockAppManager: public unity::shell::application::ApplicationManagerInterf
66 Q_OBJECT
68 Q_OBJECT
67public:
69public:
68 MockAppManager(QObject *parent = 0): ApplicationManagerInterface(parent) {}
70 MockAppManager(QObject *parent = 0): ApplicationManagerInterface(parent) {}
69− int rowCount(const QModelIndex &) const { return m_list.count(); }
71+ int rowCount(const QModelIndex &) const override { return m_list.count(); }
70− QVariant data(const QModelIndex &, int ) const { return QVariant(); }
72+ QVariant data(const QModelIndex &, int ) const override { return QVariant(); }
71− QString focusedApplicationId() const {
73+ QString focusedApplicationId() const override {
72 Q_FOREACH(MockApp *app, m_list) {
74 Q_FOREACH(MockApp *app, m_list) {
73 if (app->focused()) return app->appId();
75 if (app->focused()) return app->appId();
74 }
76 }
75 return QString();
77 return QString();
76 }
78 }
77− unity::shell::application::ApplicationInfoInterface *get(int index) const { return m_list.at(index); }
79+ unity::shell::application::ApplicationInfoInterface *get(int index) const override { return m_list.at(index); }
78− unity::shell::application::ApplicationInfoInterface *findApplication(const QString &appId) const {
80+ unity::shell::application::ApplicationInfoInterface *findApplication(const QString &appId) const override {
79 Q_FOREACH(MockApp* app, m_list) {
81 Q_FOREACH(MockApp* app, m_list) {
80 if (app->appId() == appId) {
82 if (app->appId() == appId) {
81 return app;
83 return app;
@@ -83,8 +85,8 @@ public:
83 }
85 }
84 return nullptr;
86 return nullptr;
85 }
87 }
86− unity::shell::application::ApplicationInfoInterface *startApplication(const QString &, const QStringList &) { return nullptr; }
88+ unity::shell::application::ApplicationInfoInterface *startApplication(const QString &, const QStringList &) override { return nullptr; }
87− bool stopApplication(const QString &appId) {
89+ bool stopApplication(const QString &appId) override {
88 Q_FOREACH(MockApp* app, m_list) {
90 Q_FOREACH(MockApp* app, m_list) {
89 if (app->appId() == appId) {
91 if (app->appId() == appId) {
90 removeApplication(m_list.indexOf(app));
92 removeApplication(m_list.indexOf(app));
@@ -93,7 +95,7 @@ public:
93 }
95 }
94 return false;
96 return false;
95 }
97 }
96− bool focusApplication(const QString &appId) {
98+ bool focusApplication(const QString &appId) override {
97 Q_FOREACH(MockApp* app, m_list) {
99 Q_FOREACH(MockApp* app, m_list) {
98 app->setFocused(app->appId() == appId);
100 app->setFocused(app->appId() == appId);
99 }
101 }
@@ -101,7 +103,7 @@ public:
101 return true;
103 return true;
102 }
104 }
103
105
104− void unfocusCurrentApplication() { }
106+ void unfocusCurrentApplication() override { }
105
107
106 void addApplication(MockApp *app) {
108 void addApplication(MockApp *app) {
107 beginInsertRows(QModelIndex(), count(), count());
109 beginInsertRows(QModelIndex(), count(), count());
@@ -113,11 +115,11 @@ public:
113 m_list.takeAt(index)->deleteLater();
115 m_list.takeAt(index)->deleteLater();
114 endRemoveRows();
116 endRemoveRows();
115 }
117 }
116− bool requestFocusApplication(const QString &appId) { Q_UNUSED(appId); return true; }
118+ bool requestFocusApplication(const QString &appId) override { Q_UNUSED(appId); return true; }
117− bool suspended() const { return false; }
119+ bool suspended() const override { return false; }
118− void setSuspended(bool) {}
120+ void setSuspended(bool) override {}
119− bool forceDashActive() const { return false; }
121+ bool forceDashActive() const override { return false; }
120− void setForceDashActive(bool) {}
122+ void setForceDashActive(bool) override {}
121
123
122private:
124private:
123 QList<MockApp*> m_list;
125 QList<MockApp*> m_list;
tests/plugins/Utils/qlimitproxymodeltest.cpp+5−5
@@ -36,12 +36,12 @@ public:
36 {
36 {
37 }
37 }
38
38
39− int rowCount(const QModelIndex& /* parent */ = QModelIndex()) const
39+ int rowCount(const QModelIndex& /* parent */ = QModelIndex()) const override
40 {
40 {
41 return m_list.size();
41 return m_list.size();
42 }
42 }
43
43
44− QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const
44+ QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override
45 {
45 {
46 if (!index.isValid() || index.row() < 0 || index.row() >= m_list.size() || role != Qt::DisplayRole) {
46 if (!index.isValid() || index.row() < 0 || index.row() >= m_list.size() || role != Qt::DisplayRole) {
47 return QVariant();
47 return QVariant();
@@ -49,7 +49,7 @@ public:
49 return QVariant(m_list[index.row()]);
49 return QVariant(m_list[index.row()]);
50 }
50 }
51
51
52− QHash<int, QByteArray> roleNames() const
52+ QHash<int, QByteArray> roleNames() const override
53 {
53 {
54 return m_roles;
54 return m_roles;
55 }
55 }
@@ -65,7 +65,7 @@ public:
65 endRemoveRows();
65 endRemoveRows();
66 }
66 }
67
67
68− bool insertRows(int row, int count, const QModelIndex &parent=QModelIndex()) {
68+ bool insertRows(int row, int count, const QModelIndex &parent=QModelIndex()) override {
69 beginInsertRows(parent, row, row+count-1);
69 beginInsertRows(parent, row, row+count-1);
70 for (int i=0; i<count; i++) {
70 for (int i=0; i<count; i++) {
71 m_list.insert(i+row, QString::number(i));
71 m_list.insert(i+row, QString::number(i));
@@ -81,7 +81,7 @@ public:
81 return true;
81 return true;
82 }
82 }
83
83
84− bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) {
84+ bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) override {
85 beginRemoveRows(parent, row, row+count-1);
85 beginRemoveRows(parent, row, row+count-1);
86 for (int i=0; i<count; i++) {
86 for (int i=0; i<count; i++) {
87 m_list.removeAt(row);
87 m_list.removeAt(row);
tests/plugins/Utils/unitysortfilterproxymodeltest.cpp+5−5
@@ -39,12 +39,12 @@ public:
39 {
39 {
40 }
40 }
41
41
42− int rowCount(const QModelIndex& /* parent */ = QModelIndex()) const
42+ int rowCount(const QModelIndex& /* parent */ = QModelIndex()) const override
43 {
43 {
44 return m_list.size();
44 return m_list.size();
45 }
45 }
46
46
47− QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const
47+ QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override
48 {
48 {
49 if (!index.isValid() || index.row() < 0 || index.row() >= m_list.size() || role != Qt::DisplayRole) {
49 if (!index.isValid() || index.row() < 0 || index.row() >= m_list.size() || role != Qt::DisplayRole) {
50 return QVariant();
50 return QVariant();
@@ -52,7 +52,7 @@ public:
52 return QVariant(m_list[index.row()]);
52 return QVariant(m_list[index.row()]);
53 }
53 }
54
54
55− QHash<int, QByteArray> roleNames() const
55+ QHash<int, QByteArray> roleNames() const override
56 {
56 {
57 return m_roles;
57 return m_roles;
58 }
58 }
@@ -61,7 +61,7 @@ public:
61 m_roles = roles;
61 m_roles = roles;
62 }
62 }
63
63
64− bool insertRows(int row, int count, const QModelIndex &parent=QModelIndex()) {
64+ bool insertRows(int row, int count, const QModelIndex &parent=QModelIndex()) override {
65 beginInsertRows(parent, row, row+count-1);
65 beginInsertRows(parent, row, row+count-1);
66 for (int i=0; i<count; i++) {
66 for (int i=0; i<count; i++) {
67 m_list.insert(i+row, QString("test%1").arg(i));
67 m_list.insert(i+row, QString("test%1").arg(i));
@@ -77,7 +77,7 @@ public:
77 return true;
77 return true;
78 }
78 }
79
79
80− bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) {
80+ bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) override {
81 beginRemoveRows(parent, row, row+count-1);
81 beginRemoveRows(parent, row, row+count-1);
82 for (int i=0; i<count; i++) {
82 for (int i=0; i<count; i++) {
83 m_list.removeAt(row);
83 m_list.removeAt(row);
tests/qmltests/CMakeLists.txt+2
@@ -19,6 +19,7 @@ set(qmltest_DEFAULT_TARGETS qmluitests)
19set(qmltest_DEFAULT_NO_ADD_TEST TRUE)
19set(qmltest_DEFAULT_NO_ADD_TEST TRUE)
20set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/liblightdm:${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
20set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/liblightdm:${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
21
21
22+add_qml_test(. OrientedShell)
22add_qml_test(. Shell)
23add_qml_test(. Shell)
23add_qml_test(. ShellWithPin)
24add_qml_test(. ShellWithPin)
24add_qml_test(Components Background)
25add_qml_test(Components Background)
@@ -49,6 +50,7 @@ add_qml_test(Dash/Previews PreviewImageGallery)
49add_qml_test(Dash/Previews PreviewPayments)
50add_qml_test(Dash/Previews PreviewPayments)
50add_qml_test(Dash/Previews PreviewProgress)
51add_qml_test(Dash/Previews PreviewProgress)
51add_qml_test(Dash/Previews PreviewRatingDisplay)
52add_qml_test(Dash/Previews PreviewRatingDisplay)
53+add_qml_test(Dash/Previews PreviewRatingEdit)
52add_qml_test(Dash/Previews PreviewRatingInput)
54add_qml_test(Dash/Previews PreviewRatingInput)
53add_qml_test(Dash/Previews PreviewTable)
55add_qml_test(Dash/Previews PreviewTable)
54add_qml_test(Dash/Previews PreviewTextSummary)
56add_qml_test(Dash/Previews PreviewTextSummary)
tests/qmltests/Components/tst_DragHandle.cpp−8
@@ -26,7 +26,6 @@
26#include <DirectionalDragArea.h>
26#include <DirectionalDragArea.h>
27#include <DirectionalDragArea_p.h>
27#include <DirectionalDragArea_p.h>
28#include <Timer.h>
28#include <Timer.h>
29−#include <TouchRegistry.h>
30
29
31using namespace UbuntuGestures;
30using namespace UbuntuGestures;
32
31
@@ -61,7 +60,6 @@ private:
61
60
62 QQuickView *createView();
61 QQuickView *createView();
63 QQuickView *m_view;
62 QQuickView *m_view;
64− TouchRegistry *m_touchRegistry;
65 QTouchDevice *m_device;
63 QTouchDevice *m_device;
66 FakeTimer *m_fakeTimer;
64 FakeTimer *m_fakeTimer;
67 QSharedPointer<FakeTimeSource> m_fakeTimeSource;
65 QSharedPointer<FakeTimeSource> m_fakeTimeSource;
@@ -85,10 +83,7 @@ void tst_DragHandle::cleanupTestCase()
85
83
86void tst_DragHandle::init()
84void tst_DragHandle::init()
87{
85{
88− m_touchRegistry = new TouchRegistry;
89−
90 m_view = createView();
86 m_view = createView();
91− m_view->installEventFilter(m_touchRegistry);
92 m_view->setSource(QUrl::fromLocalFile(TEST_DIR"/tst_DragHandle.qml"));
87 m_view->setSource(QUrl::fromLocalFile(TEST_DIR"/tst_DragHandle.qml"));
93 m_view->show();
88 m_view->show();
94 QVERIFY(QTest::qWaitForWindowExposed(m_view));
89 QVERIFY(QTest::qWaitForWindowExposed(m_view));
@@ -108,9 +103,6 @@ void tst_DragHandle::cleanup()
108 delete m_view;
103 delete m_view;
109 m_view = 0;
104 m_view = 0;
110
105
111− delete m_touchRegistry;
112− m_touchRegistry = 0;
113−
114 delete m_fakeTimer;
106 delete m_fakeTimer;
115 m_fakeTimer = 0;
107 m_fakeTimer = 0;
116
108
tests/qmltests/Dash/Previews/tst_PreviewRatingEdit.qmlnew file+80
@@ -0,0 +1,80 @@
1+/*
2+ * Copyright 2014 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import QtTest 1.0
19+import Ubuntu.Components 0.1
20+import "../../../../qml/Dash/Previews"
21+import Unity.Test 0.1 as UT
22+
23+Rectangle {
24+ id: root
25+ width: units.gu(40)
26+ height: units.gu(80)
27+ color: Theme.palette.selected.background
28+
29+ property var widgetData0: { "visible": "both", "required": "both", author: "Some dude", rating: 4.5, review: "Very cool app" }
30+
31+ PreviewRatingEdit {
32+ id: previewRatingEdit
33+ anchors.left: parent.left
34+ anchors.right: parent.right
35+ widgetData: widgetData0
36+ widgetId: "previewRatingInput"
37+ }
38+
39+ SignalSpy {
40+ id: spy
41+ signalName: "triggered"
42+ }
43+
44+ UT.UnityTestCase {
45+ name: "PreviewRatingEditTest"
46+ when: windowShown
47+
48+ function test_switch_and_trigger(data) {
49+ spy.target = previewRatingEdit;
50+
51+ var authorLabel = findChild(previewRatingEdit, "authorLabel");
52+ var reviewTextArea = findChild(previewRatingEdit, "reviewTextArea");
53+ var inputRating = findChild(findChild(previewRatingEdit, "input"), "rating");
54+ verify(authorLabel.visible)
55+ verify(!reviewTextArea.visible)
56+
57+ var editButton = findChild(previewRatingEdit, "editButton");
58+ mouseClick(editButton);
59+ verify(!authorLabel.visible)
60+ verify(reviewTextArea.visible)
61+
62+ compare(reviewTextArea.text, "Very cool app");
63+ compare(inputRating.value, 4.5);
64+
65+ reviewTextArea.text = "Ho Ho";
66+ inputRating.value = 3;
67+
68+ var submitButton = findChild(previewRatingEdit, "submitButton")
69+ mouseClick(submitButton);
70+
71+ compare(spy.count, 1);
72+ var args = spy.signalArguments[0];
73+ compare(args[0], previewRatingEdit.widgetId);
74+ compare(args[1], "rated");
75+ compare(args[2]["rating"], 3);
76+ compare(args[2]["review"], "Ho Ho");
77+ verify(args[2]["author"] !== undefined); // Just verifying it exists now
78+ }
79+ }
80+}
tests/qmltests/Dash/tst_DashContent.qml+7−2
@@ -142,7 +142,7 @@ Item {
142
142
143 var startX = dashContentList.width/2;
143 var startX = dashContentList.width/2;
144 var startY = dashContentList.height/2;
144 var startY = dashContentList.height/2;
145− touchFlick(dashContentList, startX - units.gu(2), startY, startX, startY);
145+ touchFlick(dashContentList, startX - units.gu(4), startY, startX, startY);
146 tryCompare(categoryListView, "contentY", units.gu(15) - categoryListView.pageHeader.height);
146 tryCompare(categoryListView, "contentY", units.gu(15) - categoryListView.pageHeader.height);
147 }
147 }
148
148
@@ -153,7 +153,7 @@ Item {
153
153
154 tryCompare(scope, "status", Loader.Ready);
154 tryCompare(scope, "status", Loader.Ready);
155
155
156− var categoryListView = findChild(dashContentList, "categoryListView");
156+ var categoryListView = findChild(scope, "categoryListView");
157 categoryListView.contentY = units.gu(10);
157 categoryListView.contentY = units.gu(10);
158
158
159 compare(dashContentList.currentItem.item.objectName, "MockScope1")
159 compare(dashContentList.currentItem.item.objectName, "MockScope1")
@@ -353,6 +353,8 @@ Item {
353 compare(backButton.visible, true);
353 compare(backButton.visible, true);
354
354
355 tryCompare(navigationList1.navigation, "loaded", true);
355 tryCompare(navigationList1.navigation, "loaded", true);
356+ tryCompare(navigationList1, "implicitHeight", navigationList1.itemHeight * 10);
357+ tryCompare(navigationList1, "height", navigationList1.implicitHeight);
356 navigation = findChild(dashNavigationButton, "navigation1child2");
358 navigation = findChild(dashNavigationButton, "navigation1child2");
357 mouseClick(navigation);
359 mouseClick(navigation);
358 compare(dashNavigationButton.showList, false);
360 compare(dashNavigationButton.showList, false);
@@ -386,6 +388,9 @@ Item {
386 mouseClick(dashNavigationButton);
388 mouseClick(dashNavigationButton);
387 compare(dashNavigationButton.showList, true);
389 compare(dashNavigationButton.showList, true);
388 tryCompare(navigationListView.currentItem.navigation, "loaded", true);
390 tryCompare(navigationListView.currentItem.navigation, "loaded", true);
391+ var navigationList0 = findChild(dashNavigationButton, "navigation0");
392+ tryCompare(navigationList0, "implicitHeight", navigationList0.itemHeight * 8);
393+ tryCompare(navigationList0, "height", navigationList0.implicitHeight);
389 navigation = findChild(dashNavigationButton, "navigation0child2");
394 navigation = findChild(dashNavigationButton, "navigation0child2");
390 mouseClick(navigation);
395 mouseClick(navigation);
391 compare(dashNavigationButton.showList, true);
396 compare(dashNavigationButton.showList, true);
tests/qmltests/Panel/tst_IndicatorsMenu.qml−2
@@ -28,8 +28,6 @@ IndicatorTest {
28 height: units.gu(71)
28 height: units.gu(71)
29 color: "white"
29 color: "white"
30
30
31− property string indicatorProfile: "phone"
32−
33 RowLayout {
31 RowLayout {
34 anchors.fill: parent
32 anchors.fill: parent
35 anchors.margins: units.gu(1)
33 anchors.margins: units.gu(1)
tests/qmltests/Panel/tst_Panel.qml−2
@@ -29,8 +29,6 @@ IndicatorTest {
29 height: units.gu(71)
29 height: units.gu(71)
30 color: "white"
30 color: "white"
31
31
32− property string indicatorProfile: "phone"
33−
34 RowLayout {
32 RowLayout {
35 anchors.fill: parent
33 anchors.fill: parent
36 anchors.margins: units.gu(1)
34 anchors.margins: units.gu(1)
tests/qmltests/Stages/ApplicationCheckBox.qml+49−20
@@ -22,27 +22,67 @@ import Unity.Application 0.1
22RowLayout {
22RowLayout {
23 id: root
23 id: root
24 property string appId
24 property string appId
25− property alias checked: checkbox.checked
25+ property bool checked: false
26
26
27 enabled: appId !== "unity8-dash"
27 enabled: appId !== "unity8-dash"
28
28
29+ onCheckedChanged: {
30+ if (d.bindGuard) { return; }
31+ d.bindGuard = true;
32+
33+ if (checked) {
34+ ApplicationManager.startApplication(root.appId);
35+ } else {
36+ ApplicationManager.stopApplication(root.appId);
37+ }
38+ d.bindGuard = false;
39+ }
40+
41+ QtObject {
42+ id: d
43+ property bool bindGuard: false
44+ property var application: null
45+ Component.onCompleted: {
46+ application = ApplicationManager.findApplication(root.appId);
47+ }
48+ }
49+
50+ Connections {
51+ target: ApplicationManager
52+ onCountChanged: {
53+ d.application = ApplicationManager.findApplication(root.appId);
54+ }
55+ }
56+
29 Layout.fillWidth: true
57 Layout.fillWidth: true
30 CheckBox {
58 CheckBox {
31 id: checkbox
59 id: checkbox
32 checked: false
60 checked: false
33 activeFocusOnPress: false
61 activeFocusOnPress: false
34− property bool noop: false
62+
35− onCheckedChanged: {
63+ onTriggered: {
36− if (noop) {
37− return;
64+ if (d.bindGuard) { return; }
38− }
65+ d.bindGuard = true;
66+
39 if (checked) {
67 if (checked) {
40− var application = ApplicationManager.startApplication(root.appId);
68+ ApplicationManager.startApplication(root.appId);
41− appConnections.target = application;
42 } else {
69 } else {
43− appConnections.target = null;
44 ApplicationManager.stopApplication(root.appId);
70 ApplicationManager.stopApplication(root.appId);
45 }
71 }
72+ d.bindGuard = false;
73+ }
74+ onCheckedChanged: {
75+ if (d.bindGuard) { return; }
76+ d.bindGuard = true;
77+
78+ root.checked = checked;
79+
80+ d.bindGuard = false;
81+ }
82+ Binding {
83+ target: checkbox
84+ property: "checked"
85+ value: d.application != null
46 }
86 }
47 }
87 }
48 Label {
88 Label {
@@ -50,15 +90,4 @@ RowLayout {
50 color: "white"
90 color: "white"
51 anchors.verticalCenter: parent.verticalCenter
91 anchors.verticalCenter: parent.verticalCenter
52 }
92 }
53−
54− Connections {
55− id: appConnections
56− onStateChanged: {
57− if (target.state == ApplicationInfoInterface.Stopped) {
58− checkbox.noop = true;
59− checkbox.checked = false;
60− checkbox.noop = false;
61− }
62− }
63− }
64}
93}
tests/qmltests/Stages/tst_ApplicationWindow.qml+14−23
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright 2014 Canonical Ltd.
2+ * Copyright 2014-2015 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
@@ -50,7 +50,7 @@ Rectangle {
50 ApplicationWindow {
50 ApplicationWindow {
51 anchors.fill: parent
51 anchors.fill: parent
52 application: fakeApplication
52 application: fakeApplication
53− orientation: Qt.PortraitOrientation
53+ surfaceOrientationAngle: 0
54 interactive: true
54 interactive: true
55 focus: true
55 focus: true
56 }
56 }
@@ -210,15 +210,6 @@ Rectangle {
210 stateGroup = null;
210 stateGroup = null;
211 }
211 }
212
212
213− // wait until any transition animation has finished
214− function waitUntilTransitionsEnd() {
215− var transitions = stateGroup.transitions;
216− for (var i = 0; i < transitions.length; ++i) {
217− var transition = transitions[i];
218− tryCompare(transition, "running", false, 2000);
219− }
220− }
221−
222 function init() {
213 function init() {
223 findInterestingApplicationWindowChildren();
214 findInterestingApplicationWindowChildren();
224 }
215 }
@@ -280,12 +271,12 @@ Rectangle {
280
271
281 tryCompare(stateGroup, "state", "surface");
272 tryCompare(stateGroup, "state", "surface");
282
273
283− waitUntilTransitionsEnd();
274+ waitUntilTransitionsEnd(stateGroup);
284
275
285 setApplicationState(appSuspended);
276 setApplicationState(appSuspended);
286
277
287 verify(stateGroup.state === "surface");
278 verify(stateGroup.state === "surface");
288− waitUntilTransitionsEnd();
279+ waitUntilTransitionsEnd(stateGroup);
289 }
280 }
290
281
291 function test_killedAppShowsScreenshot() {
282 function test_killedAppShowsScreenshot() {
@@ -311,7 +302,7 @@ Rectangle {
311 initSession();
302 initSession();
312 setApplicationState(appRunning);
303 setApplicationState(appRunning);
313 tryCompare(stateGroup, "state", "surface");
304 tryCompare(stateGroup, "state", "surface");
314− waitUntilTransitionsEnd();
305+ waitUntilTransitionsEnd(stateGroup);
315
306
316 setApplicationState(appSuspended);
307 setApplicationState(appSuspended);
317
308
@@ -319,19 +310,19 @@ Rectangle {
319 setApplicationState(appStopped);
310 setApplicationState(appStopped);
320
311
321 tryCompare(stateGroup, "state", "screenshot");
312 tryCompare(stateGroup, "state", "screenshot");
322− waitUntilTransitionsEnd();
313+ waitUntilTransitionsEnd(stateGroup);
323 tryCompare(fakeApplication, "session", null);
314 tryCompare(fakeApplication, "session", null);
324
315
325 // and restart it
316 // and restart it
326 setApplicationState(appStarting);
317 setApplicationState(appStarting);
327
318
328− waitUntilTransitionsEnd();
319+ waitUntilTransitionsEnd(stateGroup);
329 verify(stateGroup.state === "screenshot");
320 verify(stateGroup.state === "screenshot");
330 verify(fakeSession === null);
321 verify(fakeSession === null);
331
322
332 setApplicationState(appRunning);
323 setApplicationState(appRunning);
333
324
334− waitUntilTransitionsEnd();
325+ waitUntilTransitionsEnd(stateGroup);
335 verify(stateGroup.state === "screenshot");
326 verify(stateGroup.state === "screenshot");
336
327
337 initSession();
328 initSession();
@@ -344,7 +335,7 @@ Rectangle {
344 initSession();
335 initSession();
345 setApplicationState(appRunning);
336 setApplicationState(appRunning);
346 tryCompare(stateGroup, "state", "surface");
337 tryCompare(stateGroup, "state", "surface");
347− waitUntilTransitionsEnd();
338+ waitUntilTransitionsEnd(stateGroup);
348
339
349 // oh, it crashed...
340 // oh, it crashed...
350 setApplicationState(appStopped);
341 setApplicationState(appStopped);
@@ -357,18 +348,18 @@ Rectangle {
357 initSession();
348 initSession();
358 setApplicationState(appRunning);
349 setApplicationState(appRunning);
359 tryCompare(stateGroup, "state", "surface");
350 tryCompare(stateGroup, "state", "surface");
360− waitUntilTransitionsEnd();
351+ waitUntilTransitionsEnd(stateGroup);
361 verify(fakeSession.surface !== null);
352 verify(fakeSession.surface !== null);
362
353
363 applicationWindowLoader.item.visible = false;
354 applicationWindowLoader.item.visible = false;
364
355
365− waitUntilTransitionsEnd();
356+ waitUntilTransitionsEnd(stateGroup);
366 verify(stateGroup.state === "surface");
357 verify(stateGroup.state === "surface");
367 verify(fakeSession.surface !== null);
358 verify(fakeSession.surface !== null);
368
359
369 applicationWindowLoader.item.visible = true;
360 applicationWindowLoader.item.visible = true;
370
361
371− waitUntilTransitionsEnd();
362+ waitUntilTransitionsEnd(stateGroup);
372 verify(stateGroup.state === "surface");
363 verify(stateGroup.state === "surface");
373 verify(fakeSession.surface !== null);
364 verify(fakeSession.surface !== null);
374 }
365 }
@@ -379,7 +370,7 @@ Rectangle {
379
370
380 tryCompare(stateGroup, "state", "surface");
371 tryCompare(stateGroup, "state", "surface");
381
372
382− waitUntilTransitionsEnd();
373+ waitUntilTransitionsEnd(stateGroup);
383
374
384 var fakeSurface = fakeSession.surface;
375 var fakeSurface = fakeSession.surface;
385 fakeSurface.touchPressCount = 0;
376 fakeSurface.touchPressCount = 0;
@@ -396,7 +387,7 @@ Rectangle {
396 initSession();
387 initSession();
397 setApplicationState(appRunning);
388 setApplicationState(appRunning);
398 tryCompare(stateGroup, "state", "surface");
389 tryCompare(stateGroup, "state", "surface");
399− waitUntilTransitionsEnd();
390+ waitUntilTransitionsEnd(stateGroup);
400
391
401 cleanupSession();
392 cleanupSession();
402
393
tests/qmltests/Stages/tst_DesktopStage.qml+77−67
@@ -20,6 +20,7 @@ import Ubuntu.Components 1.1
20import Ubuntu.Components.ListItems 1.0 as ListItem
20import Ubuntu.Components.ListItems 1.0 as ListItem
21import Unity.Application 0.1
21import Unity.Application 0.1
22import Unity.Test 0.1
22import Unity.Test 0.1
23+import Utils 0.1
23
24
24import "../../../qml/Stages"
25import "../../../qml/Stages"
25
26
@@ -29,31 +30,18 @@ Rectangle {
29 width: desktopStageLoader.width + controls.width
30 width: desktopStageLoader.width + controls.width
30 height: desktopStageLoader.height
31 height: desktopStageLoader.height
31
32
32− QtObject {
33+ Binding {
33− id: fakeWindowStateStorage
34+ target: MouseTouchAdaptor
34−
35− property var storedGeom: [
35+ property: "enabled"
36− ["unity8-dash", Qt.rect(units.gu(2), units.gu(2), units.gu(50), units.gu(50))],
36+ value: false
37− ["webbrowser-app", Qt.rect(units.gu(60), units.gu(2), units.gu(50), units.gu(50))]
37+ }
38− ]
39
38
40− function saveGeometry(windowId, geometry) {
39+ Component.onCompleted: {
41− for (var i = 0; i < storedGeom.length; ++i) {
40+ // ensures apps which are tested decorations are in view.
42− if (storedGeom[i][0] === windowId) {
41+ WindowStateStorage.geometry = {
43− storedGeom[i][1] = geometry;
42+ 'unity8-dash': Qt.rect(0, units.gu(3), units.gu(50), units.gu(40)),
44− return;
43+ 'dialer-app': Qt.rect(units.gu(51), units.gu(3), units.gu(50), units.gu(40)),
45− }
44+ 'camera-app': Qt.rect(0, units.gu(44), units.gu(50), units.gu(40)),
46− }
47− // if new
48− storedGeom[storedGeom.length] = [windowId, geometry];
49− }
50− function getGeometry(windowId, defaultGeometry) {
51− for (var i = 0; i < storedGeom.length; ++i) {
52− if (storedGeom[i][0] === windowId) {
53− return storedGeom[i][1];
54− }
55− }
56− return defaultGeometry;
57 }
45 }
58 }
46 }
59
47
@@ -70,7 +58,6 @@ Rectangle {
70 sourceComponent: Component {
58 sourceComponent: Component {
71 DesktopStage {
59 DesktopStage {
72 anchors.fill: parent
60 anchors.fill: parent
73− windowStateStorage: fakeWindowStateStorage
74 Component.onDestruction: {
61 Component.onDestruction: {
75 desktopStageLoader.itemDestroyed = true;
62 desktopStageLoader.itemDestroyed = true;
76 }
63 }
@@ -108,9 +95,6 @@ Rectangle {
108
95
109 property Item desktopStage: desktopStageLoader.status === Loader.Ready ? desktopStageLoader.item : null
96 property Item desktopStage: desktopStageLoader.status === Loader.Ready ? desktopStageLoader.item : null
110
97
111− function init() {
112− }
113−
114 function cleanup() {
98 function cleanup() {
115 desktopStageLoader.itemDestroyed = false;
99 desktopStageLoader.itemDestroyed = false;
116 desktopStageLoader.active = false;
100 desktopStageLoader.active = false;
@@ -145,57 +129,83 @@ Rectangle {
145 tryCompare(appWindowStates, "state", "surface");
129 tryCompare(appWindowStates, "state", "surface");
146 }
130 }
147
131
148− function rectsIntersect(aLocal, bLocal) {
132+ function startApplication(appId) {
149−
133+ var app = ApplicationManager.findApplication(appId);
150− var a = aLocal.mapToItem(null, 0, 0, aLocal.width, aLocal.height);
134+ if (!app) {
151− var b = bLocal.mapToItem(null, 0, 0, bLocal.width, bLocal.height);
135+ app = ApplicationManager.startApplication(appId);
152−
136+ }
137+ verify(app);
138+ waitUntilAppSurfaceShowsUp(appId);
139+ verify(app.session.surface);
153− return !((a.y+a.height) < b.y
140+ return app;
154− || a.y > (b.y+b.height)
155− || (a.x+a.width) < b.x
156− || a.x > (b.x+b.width));
157 }
141 }
158
142
159− function test_tappingOnWindowChangesFocusedApp() {
143+ function test_appFocusSwitch_data() {
160− ApplicationManager.startApplication("webbrowser-app");
144+ return [
161− waitUntilAppSurfaceShowsUp("webbrowser-app");
145+ {tag: "dash", apps: [ "unity8-dash", "dialer-app", "camera-app" ], focusfrom: 0, focusTo: 1 },
146+ {tag: "dash", apps: [ "unity8-dash", "dialer-app", "camera-app" ], focusfrom: 1, focusTo: 0 },
147+ ]
148+ }
162
149
163− var webbrowserWindow = findChild(desktopStage, "appWindow_webbrowser-app");
150+ function test_appFocusSwitch(data) {
164− verify(webbrowserWindow);
151+ var i;
165− var dashWindow = findChild(desktopStage, "appWindow_unity8-dash");
152+ for (i = 0; i < data.apps.length; i++) {
166− verify(dashWindow);
153+ startApplication(data.apps[i]);
154+ }
167
155
168− // some sanity check
156+ ApplicationManager.requestFocusApplication(data.apps[data.focusfrom]);
169− compare(rectsIntersect(dashWindow, webbrowserWindow), false);
157+ tryCompare(ApplicationManager.findApplication(data.apps[data.focusfrom]).session.surface, "activeFocus", true);
170
158
171− tap(dashWindow);
159+ ApplicationManager.requestFocusApplication(data.apps[data.focusTo]);
172− compare(dashWindow.application.session.surface.activeFocus, true);
160+ tryCompare(ApplicationManager.findApplication(data.apps[data.focusTo]).session.surface, "activeFocus", true);
161+ }
173
162
174− tap(webbrowserWindow);
163+ function test_tappingOnWindowChangesFocusedApp_data() {
175− compare(webbrowserWindow.application.session.surface.activeFocus, true);
164+ return [
165+ {tag: "dash", apps: [ "unity8-dash", "dialer-app", "camera-app" ], focusfrom: 0, focusTo: 1 },
166+ {tag: "dash", apps: [ "unity8-dash", "dialer-app", "camera-app" ], focusfrom: 1, focusTo: 0 },
167+ ]
176 }
168 }
177
169
178− function test_tappingOnWindowTitleChangesFocusedApp() {
170+ function test_tappingOnWindowChangesFocusedApp(data) {
171+ var i;
172+ for (i = 0; i < data.apps.length; i++) {
179− ApplicationManager.startApplication("webbrowser-app");
173+ startApplication(data.apps[i]);
180− waitUntilAppSurfaceShowsUp("webbrowser-app");
174+ }
175+
176+ var fromAppWindow = findChild(desktopStage, "appWindow_" + data.apps[data.focusfrom]);
177+ verify(fromAppWindow);
178+ tap(fromAppWindow);
179+ compare(fromAppWindow.application.session.surface.activeFocus, true);
181
180
182− var webbrowserWindow = findChild(desktopStage, "decoratedWindow_webbrowser-app");
181+ var toAppWindow = findChild(desktopStage, "appWindow_" + data.apps[data.focusTo]);
183− verify(webbrowserWindow);
182+ verify(toAppWindow);
184− var webbrowserWindowTitle = findChild(webbrowserWindow, "windowDecorationTitle");
183+ tap(toAppWindow);
185− verify(webbrowserWindowTitle);
184+ compare(toAppWindow.application.session.surface.activeFocus, true);
186− var dashWindow = findChild(desktopStage, "decoratedWindow_unity8-dash");
185+ }
187− verify(dashWindow);
188− var dashWindowTitle = findChild(dashWindow, "windowDecorationTitle");
189− verify(dashWindowTitle);
190
186
191− // some sanity check
187+ function test_tappingOnDecorationFocusesApplication_data() {
192− compare(rectsIntersect(dashWindow, webbrowserWindow), false);
188+ return [
189+ {tag: "dash", apps: [ "unity8-dash", "dialer-app", "camera-app" ], focusfrom: 0, focusTo: 1 },
190+ {tag: "dash", apps: [ "unity8-dash", "dialer-app", "camera-app" ], focusfrom: 1, focusTo: 0 },
191+ ]
192+ }
193+
194+ function test_tappingOnDecorationFocusesApplication(data) {
195+ var i;
196+ for (i = 0; i < data.apps.length; i++) {
197+ startApplication(data.apps[i]);
198+ }
193
199
194− tap(dashWindowTitle);
200+ var fromAppDecoration = findChild(desktopStage, "appWindowDecoration_" + data.apps[data.focusfrom]);
195− compare(dashWindow.application.session.surface.activeFocus, true);
201+ verify(fromAppDecoration);
202+ tap(fromAppDecoration);
203+ tryCompare(ApplicationManager.findApplication(data.apps[data.focusfrom]).session.surface, "activeFocus", true);
196
204
197− tap(webbrowserWindowTitle);
205+ var toAppDecoration = findChild(desktopStage, "appWindowDecoration_" + data.apps[data.focusTo]);
198− compare(webbrowserWindow.application.session.surface.activeFocus, true);
206+ verify(toAppDecoration);
207+ tap(toAppDecoration);
208+ tryCompare(ApplicationManager.findApplication(data.apps[data.focusTo]).session.surface, "activeFocus", true);
199 }
209 }
200 }
210 }
201}
211}
tests/qmltests/Stages/tst_PhoneStage.qml+5−58
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright 2014 Canonical Ltd.
2+ * Copyright 2014-2015 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
@@ -33,7 +33,9 @@ Item {
33 dragAreaWidth: units.gu(2)
33 dragAreaWidth: units.gu(2)
34 maximizedAppTopMargin: units.gu(3) + units.dp(2)
34 maximizedAppTopMargin: units.gu(3) + units.dp(2)
35 interactive: true
35 interactive: true
36+ shellOrientation: Qt.PortraitOrientation
37+ shellPrimaryOrientation: Qt.PortraitOrientation
36− orientation: Qt.PortraitOrientation
38+ nativeOrientation: Qt.PortraitOrientation
37 }
39 }
38
40
39 Binding {
41 Binding {
@@ -73,21 +75,6 @@ Item {
73 ApplicationManager.get(appList.selectedAppIndex).setState(ApplicationInfoInterface.Stopped);
75 ApplicationManager.get(appList.selectedAppIndex).setState(ApplicationInfoInterface.Stopped);
74 }
76 }
75 }
77 }
76− Button {
77− anchors { left: parent.left; right: parent.right }
78− text: "Rotate device \u27F3"
79− onClicked: {
80− if (phoneStage.orientation == Qt.PortraitOrientation) {
81− phoneStage.orientation = Qt.LandscapeOrientation;
82− } else if (phoneStage.orientation == Qt.LandscapeOrientation) {
83− phoneStage.orientation = Qt.InvertedPortraitOrientation;
84− } else if (phoneStage.orientation == Qt.InvertedPortraitOrientation) {
85− phoneStage.orientation = Qt.InvertedLandscapeOrientation;
86− } else {
87− phoneStage.orientation = Qt.PortraitOrientation;
88− }
89− }
90− }
91 }
78 }
92 ListView {
79 ListView {
93 id: appList
80 id: appList
@@ -283,46 +270,6 @@ Item {
283 compare(ApplicationManager.focusedApplicationId, selectedApp.appId);
270 compare(ApplicationManager.focusedApplicationId, selectedApp.appId);
284 }
271 }
285
272
286− function test_orientationChangeSentToFocusedApp() {
287− phoneStage.orientation = Qt.PortraitOrientation;
288− addApps(1);
289−
290− var spreadView = findChild(phoneStage, "spreadView");
291− var app = findChild(spreadView, "appDelegate0");
292− tryCompare(app, "orientation", Qt.PortraitOrientation);
293−
294− phoneStage.orientation = Qt.LandscapeOrientation;
295− tryCompare(app, "orientation", Qt.LandscapeOrientation);
296− }
297−
298− function test_orientationChangeNotSentToAppsWhileSpreadOpen() {
299− phoneStage.orientation = Qt.PortraitOrientation;
300− addApps(1);
301−
302− var spreadView = findChild(phoneStage, "spreadView");
303− var app = findChild(spreadView, "appDelegate0");
304− tryCompare(app, "orientation", Qt.PortraitOrientation);
305−
306− goToSpread();
307− phoneStage.orientation = Qt.LandscapeOrientation;
308− tryCompare(app, "orientation", Qt.PortraitOrientation);
309− }
310−
311− function test_orientationChangeNotSentToUnfocusedAppUntilItFocused() {
312− phoneStage.orientation = Qt.PortraitOrientation;
313− addApps(1);
314−
315− var spreadView = findChild(phoneStage, "spreadView");
316− var app = findChild(spreadView, "appDelegate0");
317−
318− goToSpread();
319− phoneStage.orientation = Qt.LandscapeOrientation;
320− tryCompare(app, "orientation", Qt.PortraitOrientation);
321−
322− phoneStage.select(app.application.appId);
323− tryCompare(app, "orientation", Qt.LandscapeOrientation);
324− }
325−
326 function test_backgroundClickCancelsSpread() {
273 function test_backgroundClickCancelsSpread() {
327 addApps(3);
274 addApps(3);
328
275
@@ -347,7 +294,7 @@ Item {
347 ApplicationManager.stopApplication(ApplicationManager.get(closingIndex).appId)
294 ApplicationManager.stopApplication(ApplicationManager.get(closingIndex).appId)
348 tryCompare(ApplicationManager, "count", oldCount - 1)
295 tryCompare(ApplicationManager, "count", oldCount - 1)
349 }
296 }
350− phoneStage.orientation = Qt.PortraitOrientation;
297+ phoneStage.shellOrientationAngle = 0;
351 }
298 }
352
299
353 function test_focusNewTopMostAppAfterFocusedOneClosesItself() {
300 function test_focusNewTopMostAppAfterFocusedOneClosesItself() {
tests/qmltests/Stages/tst_SessionContainer.qml+1−64
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright 2014 Canonical Ltd.
2+ * Copyright 2014-2015 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
@@ -41,7 +41,6 @@ Rectangle {
41 SessionContainer {
41 SessionContainer {
42 id: sessionContainer
42 id: sessionContainer
43 anchors.fill: parent
43 anchors.fill: parent
44− orientation: Qt.PortraitOrientation
45 focus: true
44 focus: true
46 interactive: true
45 interactive: true
47 }
46 }
@@ -117,24 +116,6 @@ Rectangle {
117 session: sessionContainerLoader.item ? sessionContainerLoader.item.session : null
116 session: sessionContainerLoader.item ? sessionContainerLoader.item.session : null
118 }
117 }
119 }
118 }
120−
121− Button {
122− anchors { left: parent.left; right: parent.right }
123− text: "Rotate device \u27F3"
124− onClicked: {
125− var orientation = sessionContainerLoader.item.orientation
126− if (orientation == Qt.PortraitOrientation) {
127− orientation = Qt.LandscapeOrientation;
128− } else if (orientation == Qt.LandscapeOrientation) {
129− orientation = Qt.InvertedPortraitOrientation;
130− } else if (orientation == Qt.InvertedPortraitOrientation) {
131− orientation = Qt.InvertedLandscapeOrientation;
132− } else {
133− orientation = Qt.PortraitOrientation;
134− }
135− sessionContainerLoader.item.orientation = orientation;
136− }
137− }
138 }
119 }
139 }
120 }
140
121
@@ -324,49 +305,5 @@ Rectangle {
324 // wait for animation to end
305 // wait for animation to end
325 tryCompareFunction(function() { return isContainerAnimating(childContainer); }, false);
306 tryCompareFunction(function() { return isContainerAnimating(childContainer); }, false);
326 }
307 }
327−
328− function test_orientationPropagatedToChildren_data() {
329− return [ { tag: "count=1", count: 1 },
330− { tag: "count=4", count: 4 } ];
331− }
332−
333− /* Test orientation changes are propagated to all children immediately */
334− function test_orientationPropagatedToChildren(data) {
335− sessionCheckbox.checked = true;
336− var rootSessionContainer = sessionContainerLoader.item;
337− compare(rootSessionContainer.childSessions.count(), 0);
338−
339− var i;
340− var sessions = [];
341− for (i = 0; i < data.count; i++) {
342− var session = ApplicationTest.addChildSession(rootSessionContainer.session,
343− "gallery");
344− session.createSurface();
345− rootSessionContainer.session.addChildSession(session);
346−
347− // Check child SessionContainer has orientation matching the parent
348− var delegate = findChild(rootSessionContainer, "childDelegate" + i);
349− var childSessionContainer = findChild(delegate, "sessionContainer");
350−
351− tryCompare(rootSessionContainer, "orientation", childSessionContainer.orientation);
352−
353− sessions.push(session);
354− }
355−
356− // Change orientation and verify all children updated
357− rootSessionContainer.orientation = Qt.LandscapeOrientation;
358−
359− for (i = 0; i < data.count; i++) {
360− var delegate = findChild(rootSessionContainer, "childDelegate" + i);
361− var childSessionContainer = findChild(delegate, "sessionContainer");
362−
363− tryCompare(rootSessionContainer, "orientation", childSessionContainer.orientation);
364− }
365−
366− // Clean up
367− for (i = data.count-1; i >= 0; i--) {
368− ApplicationTest.removeSession(sessions[i]);
369− }
370− }
371 }
308 }
372}
309}
tests/qmltests/Stages/tst_SpreadDelegate.qml+172−37
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright 2014 Canonical Ltd.
2+ * Copyright 2014-2015 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
@@ -26,46 +26,89 @@ import Unity.Application 0.1
26Rectangle {
26Rectangle {
27 color: "red"
27 color: "red"
28 id: root
28 id: root
29− width: units.gu(70)
29+ width: fakeShell.shortestDimension + controls.width
30− height: units.gu(70)
30+ height: fakeShell.longestDimension
31
31
32− Component.onCompleted: {
33− root.fakeApplication = ApplicationManager.startApplication("gallery-app");
34− }
35 property QtObject fakeApplication: null
32 property QtObject fakeApplication: null
36
33
37− Component {
34+ Item {
38− id: spreadDelegateComponent
35+ id: fakeShell
36+
37+ readonly property real shortestDimension: units.gu(40)
38+ readonly property real longestDimension: units.gu(70)
39+
40+ width: landscape ? longestDimension : shortestDimension
41+ height: landscape ? shortestDimension : longestDimension
42+
43+ x: landscape ? (height - width) / 2 : 0
44+ y: landscape ? (width - height) / 2 : 0
45+
46+ property bool landscape: orientationAngle == 90 || orientationAngle == 270
47+ property int orientationAngle: shellOrientationAngleSelector.value
48+
49+ rotation: orientationAngle
50+
51+ Loader {
52+ id: spreadDelegateLoader
53+ width: parent.width
54+ height: parent.height
55+
56+ active: false
57+ property bool itemDestroyed: false
39− SpreadDelegate {
58+ sourceComponent: SpreadDelegate {
40− anchors.fill: parent
59+ anchors.fill: parent
41− swipeToCloseEnabled: swipeToCloseCheckbox.checked
60+ swipeToCloseEnabled: swipeToCloseCheckbox.checked
42− closeable: closeableCheckbox.checked
61+ closeable: closeableCheckbox.checked
43− application: fakeApplication
62+ application: fakeApplication
44− }
63+ shellOrientationAngle: shellOrientationAngleSelector.value
45− }
64+ shellOrientation: {
46− Loader {
65+ switch (shellOrientationAngleSelector.value) {
47− id: spreadDelegateLoader
66+ case 0:
48− anchors {
67+ return Qt.PortraitOrientation;
49− top: parent.top
68+ case 90:
50− bottom: parent.bottom
69+ return Qt.InvertedLandscapeOrientation;
51− left: parent.left
70+ case 180:
71+ return Qt.InvertedPortraitOrientation;
72+ default: // 270
73+ return Qt.LandscapeOrientation;
74+ }
75+ }
76+ shellPrimaryOrientation: Qt.PortraitOrientation
77+ nativeOrientation: Qt.PortraitOrientation
78+ maximizedAppTopMargin: units.gu(3)
79+ Component.onDestruction: {
80+ spreadDelegateLoader.itemDestroyed = true;
81+ }
82+ Component.onCompleted: {
83+ spreadDelegateLoader.itemDestroyed = false;
84+ }
85+ }
52 }
86 }
53− width: units.gu(40)
54− sourceComponent: spreadDelegateComponent
55 }
87 }
56
88
57 Rectangle {
89 Rectangle {
90+ id: controls
58 color: "white"
91 color: "white"
92+ x: fakeShell.shortestDimension
93+ width: units.gu(30)
59 anchors {
94 anchors {
60 top: parent.top
95 top: parent.top
61 bottom: parent.bottom
96 bottom: parent.bottom
62− left: spreadDelegateLoader.right
63− right: parent.right
64 }
97 }
65
98
66 Column {
99 Column {
67 anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
100 anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
68 spacing: units.gu(1)
101 spacing: units.gu(1)
102+ Button {
103+ id: loadWithWeatherApp
104+ text: "Load with ubuntu-weather-app"
105+ onClicked: { testCase.restartWithApp("ubuntu-weather-app"); }
106+ }
107+ Button {
108+ id: loadWithGalleryApp
109+ text: "Load with gallery-app"
110+ onClicked: { testCase.restartWithApp("gallery-app"); }
111+ }
69 Row {
112 Row {
70 anchors { left: parent.left; right: parent.right }
113 anchors { left: parent.left; right: parent.right }
71 CheckBox { id: swipeToCloseCheckbox; checked: false; }
114 CheckBox { id: swipeToCloseCheckbox; checked: false; }
@@ -76,6 +119,21 @@ Rectangle {
76 CheckBox { id: closeableCheckbox; checked: false }
119 CheckBox { id: closeableCheckbox; checked: false }
77 Label { text: "closeable" }
120 Label { text: "closeable" }
78 }
121 }
122+ ListItem.ItemSelector {
123+ id: shellOrientationAngleSelector
124+ anchors { left: parent.left; right: parent.right }
125+ text: "shellOrientationAngle"
126+ model: ["0", "90", "180", "270"]
127+ property int value: selectedIndex * 90
128+ }
129+ Button {
130+ text: "matchShellOrientation()"
131+ onClicked: { spreadDelegateLoader.item.matchShellOrientation(); }
132+ }
133+ Button {
134+ text: "animateToShellOrientation()"
135+ onClicked: { spreadDelegateLoader.item.animateToShellOrientation(); }
136+ }
79 }
137 }
80 }
138 }
81
139
@@ -91,18 +149,47 @@ Rectangle {
91 }
149 }
92
150
93 property var dragArea
151 property var dragArea
152+ property Item spreadDelegate: spreadDelegateLoader.item
94
153
95 function init() {
154 function init() {
96− dragArea = findInvisibleChild(spreadDelegateLoader.item, "dragArea");
97− dragArea.__dateTime = fakeDateTime;
98 }
155 }
99
156
100 function cleanup() {
157 function cleanup() {
101− // reload our test subject to get it in a fresh state once again
158+ unloadSpreadDelegate();
159+ spyClosedSignal.clear();
160+ shellOrientationAngleSelector.selectedIndex = 0;
161+ ApplicationManager.stopApplication(root.fakeApplication.appId);
162+ root.fakeApplication = null;
163+ }
164+
165+ function restartWithApp(appId) {
102− spreadDelegateLoader.active = false;
166+ if (spreadDelegateLoader.active) {
167+ unloadSpreadDelegate();
168+ }
169+ if (root.fakeApplication) {
170+ ApplicationManager.stopApplication(root.fakeApplication.appId);
171+ }
172+
173+ root.fakeApplication = ApplicationManager.startApplication(appId);
103 spreadDelegateLoader.active = true;
174 spreadDelegateLoader.active = true;
175+ tryCompare(spreadDelegateLoader, "status", Loader.Ready);
176+
177+ dragArea = findInvisibleChild(spreadDelegate, "dragArea");
178+ dragArea.__dateTime = fakeDateTime;
179+ }
180+
181+ function unloadSpreadDelegate() {
182+ spreadDelegateLoader.active = false;
183+ tryCompare(spreadDelegateLoader, "status", Loader.Null);
184+ tryCompare(spreadDelegateLoader, "item", null);
185+ // Loader.status might be Loader.Null and Loader.item might be null but the Loader
186+ // item might still be alive. So if we set Loader.active back to true
187+ // again right now we will get the very same Shell instance back. So no reload
188+ // actually took place. Likely because Loader waits until the next event loop
189+ // iteration to do its work. So to ensure the reload, we will wait until the
190+ // Shell instance gets destroyed.
191+ tryCompare(spreadDelegateLoader, "itemDestroyed", true);
104
192
105− spyClosedSignal.clear();
106 }
193 }
107
194
108 function test_swipeToClose_data() {
195 function test_swipeToClose_data() {
@@ -119,9 +206,10 @@ Rectangle {
119 }
206 }
120
207
121 function test_swipeToClose(data) {
208 function test_swipeToClose(data) {
209+ loadWithGalleryApp.clicked();
122− var appWindowWithShadow = findChild(spreadDelegateLoader.item, "appWindowWithShadow");
210+ var displacedAppWindowWithShadow = findChild(spreadDelegateLoader.item, "displacedAppWindowWithShadow");
123
211
124− verify(appWindowWithShadow.y === 0);
212+ verify(displacedAppWindowWithShadow.y === 0);
125
213
126 swipeToCloseCheckbox.checked = data.swipeToClose;
214 swipeToCloseCheckbox.checked = data.swipeToClose;
127 closeableCheckbox.checked = data.closeable;
215 closeableCheckbox.checked = data.closeable;
@@ -135,14 +223,14 @@ Rectangle {
135 true /* beginTouch */, false /* endTouch */, dragArea.minSpeedToClose * 1.1 /* speed */);
223 true /* beginTouch */, false /* endTouch */, dragArea.minSpeedToClose * 1.1 /* speed */);
136
224
137 if (data.swipeToClose) {
225 if (data.swipeToClose) {
138− verify(appWindowWithShadow.y < 0);
226+ verify(displacedAppWindowWithShadow.y < 0);
139 var threshold = findChild(spreadDelegateLoader.item, "dragArea").threshold
227 var threshold = findChild(spreadDelegateLoader.item, "dragArea").threshold
140 if (data.closeable) {
228 if (data.closeable) {
141 // Verify that the delegate started moving exactly "threshold" after the finger movement
229 // Verify that the delegate started moving exactly "threshold" after the finger movement
142 // and did not jump up to the finger, but lags the threshold behind
230 // and did not jump up to the finger, but lags the threshold behind
143− compare(Math.abs(Math.abs(appWindowWithShadow.y) - dragDistance), threshold);
231+ compare(Math.abs(Math.abs(displacedAppWindowWithShadow.y) - dragDistance), threshold);
144 } else {
232 } else {
145− verify(Math.abs(Math.abs(appWindowWithShadow.y) - dragDistance) > threshold);
233+ verify(Math.abs(Math.abs(displacedAppWindowWithShadow.y) - dragDistance) > threshold);
146 }
234 }
147
235
148 touchRelease(spreadDelegateLoader.item, touchX, toY - units.gu(1));
236 touchRelease(spreadDelegateLoader.item, touchX, toY - units.gu(1));
@@ -153,16 +241,63 @@ Rectangle {
153 verify(spyClosedSignal.count === 1);
241 verify(spyClosedSignal.count === 1);
154 } else {
242 } else {
155 verify(spyClosedSignal.count === 0);
243 verify(spyClosedSignal.count === 0);
156− tryCompare(appWindowWithShadow, "y", 0);
244+ tryCompare(displacedAppWindowWithShadow, "y", 0);
157 }
245 }
158
246
159 } else {
247 } else {
160− verify(appWindowWithShadow.y === 0);
248+ verify(displacedAppWindowWithShadow.y === 0);
161
249
162 touchRelease(spreadDelegateLoader.item, touchX, toY);
250 touchRelease(spreadDelegateLoader.item, touchX, toY);
163 }
251 }
164 }
252 }
165
253
254+ function test_loadingLandscapeOnlyAppWhenShellInPortrait() {
255+ loadWithWeatherApp.clicked();
256+
257+ var appWindow = findChild(spreadDelegate, "appWindow_ubuntu-weather-app");
258+ verify(appWindow);
259+
260+ // It must have landscape dimensions as it does not support portrait
261+ tryCompare(appWindow, "width", fakeShell.height);
262+ tryCompare(appWindow, "height", fakeShell.width - spreadDelegate.maximizedAppTopMargin);
263+ }
264+
265+ function test_keepsSceneTransformationWhenShellRotates_data() {
266+ return [
267+ {tag: "0", selectedIndex: 0},
268+ {tag: "90", selectedIndex: 1},
269+ {tag: "180", selectedIndex: 2},
270+ {tag: "270", selectedIndex: 3}
271+ ];
272+ }
273+ function test_keepsSceneTransformationWhenShellRotates(data) {
274+ loadWithGalleryApp.clicked();
275+
276+ var appWindowWithShadow = findChild(spreadDelegate, "appWindowWithShadow");
277+ verify(appWindowWithShadow);
278+
279+ // Wait until it reaches the state we are interested on.
280+ // It begins with "startingUp"
281+ tryCompare(appWindowWithShadow, "state", "keepSceneRotation");
282+
283+ shellOrientationAngleSelector.selectedIndex = data.selectedIndex;
284+
285+ // must keep same aspect ratio
286+ compare(appWindowWithShadow.width, fakeShell.shortestDimension);
287+ compare(appWindowWithShadow.height, fakeShell.longestDimension);
288+
289+
290+ // and scene transformation must be the identity (ie, no rotation or translation)
291+ var pointInDelegateCoords = appWindowWithShadow.mapToItem(root, 0, 0);
292+ compare(pointInDelegateCoords.x, 0);
293+ compare(pointInDelegateCoords.y, 0);
294+
295+ pointInDelegateCoords = appWindowWithShadow.mapToItem(root,
296+ fakeShell.shortestDimension, fakeShell.longestDimension);
297+ compare(pointInDelegateCoords.x, fakeShell.shortestDimension);
298+ compare(pointInDelegateCoords.y, fakeShell.longestDimension);
299+ }
300+
166 function waitForCloseAnimationToFinish() {
301 function waitForCloseAnimationToFinish() {
167 var closeAnimation = findInvisibleChild(spreadDelegateLoader.item, "closeAnimation");
302 var closeAnimation = findInvisibleChild(spreadDelegateLoader.item, "closeAnimation");
168 wait(closeAnimation.duration * 1.5);
303 wait(closeAnimation.duration * 1.5);
tests/qmltests/Stages/tst_TabletStage.qml+51
@@ -49,6 +49,11 @@ Rectangle {
49 dragAreaWidth: units.gu(2)
49 dragAreaWidth: units.gu(2)
50 maximizedAppTopMargin: units.gu(3) + units.dp(2)
50 maximizedAppTopMargin: units.gu(3) + units.dp(2)
51 interactive: true
51 interactive: true
52+ shellOrientation: Qt.LandscapeOrientation
53+ shellPrimaryOrientation: Qt.LandscapeOrientation
54+ nativeOrientation: Qt.LandscapeOrientation
55+ nativeWidth: width
56+ nativeHeight: height
52 focus: true
57 focus: true
53 }
58 }
54 }
59 }
@@ -149,6 +154,52 @@ Rectangle {
149 tryCompare(dialerApp.session.surface, "activeFocus", true);
154 tryCompare(dialerApp.session.surface, "activeFocus", true);
150 tryCompare(webbrowserApp.session.surface, "activeFocus", false);
155 tryCompare(webbrowserApp.session.surface, "activeFocus", false);
151 }
156 }
157+
158+
159+ function test_closeAppInSideStage() {
160+ dialerCheckBox.checked = true;
161+ waitUntilAppSurfaceShowsUp(dialerCheckBox.appId);
162+
163+ performEdgeSwipeToShowAppSpread();
164+
165+ var appDelegate = findChild(tabletStage, "tabletSpreadDelegate_" + dialerCheckBox.appId);
166+ verify(appDelegate);
167+ tryCompare(appDelegate, "swipeToCloseEnabled", true);
168+
169+ swipeAppUpwards(dialerCheckBox.appId);
170+
171+ // Check that dialer-app has been closed
172+
173+ tryCompareFunction(function() {
174+ return findChild(tabletStage, "appWindow_" + dialerCheckBox.appId);
175+ }, null);
176+
177+ tryCompareFunction(function() {
178+ return ApplicationManager.findApplication(dialerCheckBox.appId);
179+ }, null);
180+ }
181+
182+ function performEdgeSwipeToShowAppSpread() {
183+ var touchStartY = tabletStage.height / 2;
184+ touchFlick(tabletStage,
185+ tabletStage.width - 1, touchStartY,
186+ 0, touchStartY);
187+
188+ var spreadView = findChild(tabletStage, "spreadView");
189+ verify(spreadView);
190+ tryCompare(spreadView, "phase", 2);
191+ tryCompare(spreadView, "flicking", false);
192+ tryCompare(spreadView, "moving", false);
193+ }
194+
195+ function swipeAppUpwards(appId) {
196+ var appWindow = findChild(tabletStage, "appWindow_" + appId);
197+ verify(appWindow);
198+
199+ touchFlick(appWindow,
200+ appWindow.width / 2, appWindow.height / 2,
201+ appWindow.width / 2, -appWindow.height / 2);
202+ }
152 }
203 }
153
204
154}
205}
tests/qmltests/Tutorial/tst_Tutorial.qml+1
@@ -73,6 +73,7 @@ Item {
73 sourceComponent: Component {
73 sourceComponent: Component {
74 Shell {
74 Shell {
75 property string indicatorProfile: "phone"
75 property string indicatorProfile: "phone"
76+ property string shellMode: "full-greeter" /* default */
76
77
77 Component.onDestruction: {
78 Component.onDestruction: {
78 shellLoader.itemDestroyed = true;
79 shellLoader.itemDestroyed = true;
tests/qmltests/tst_OrientedShell.qmlnew file+1151
@@ -0,0 +1,1151 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import QtQuick.Layouts 1.1
19+import QtTest 1.0
20+import Ubuntu.Components 1.1
21+import Ubuntu.Components.ListItems 1.0 as ListItem
22+import Unity.Application 0.1
23+import Unity.Test 0.1
24+import LightDM 0.1 as LightDM
25+import Powerd 0.1
26+
27+import "../../qml"
28+
29+Rectangle {
30+ id: root
31+ color: "grey"
32+ width: units.gu(160) + controls.width
33+ height: units.gu(100)
34+
35+ QtObject {
36+ id: applicationArguments
37+
38+ function hasGeometry() {
39+ return false;
40+ }
41+
42+ function width() {
43+ return 0;
44+ }
45+
46+ function height() {
47+ return 0;
48+ }
49+ property string deviceName: "mako"
50+ }
51+
52+ QtObject {
53+ id: mockOrientationLock
54+ property int savedOrientation
55+ }
56+
57+ QtObject {
58+ id: mockUsageModeSettings
59+ property string usageMode: usageModeSelector.model[usageModeSelector.selectedIndex]
60+ }
61+
62+ property int physicalOrientation0
63+ property int physicalOrientation90
64+ property int physicalOrientation180
65+ property int physicalOrientation270
66+ property real primaryOrientationAngle
67+
68+ state: applicationArguments.deviceName
69+ states: [
70+ State {
71+ name: "mako"
72+ PropertyChanges {
73+ target: orientedShellLoader
74+ width: units.gu(40)
75+ height: units.gu(71)
76+ }
77+ PropertyChanges {
78+ target: root
79+ physicalOrientation0: Qt.PortraitOrientation
80+ physicalOrientation90: Qt.InvertedLandscapeOrientation
81+ physicalOrientation180: Qt.InvertedPortraitOrientation
82+ physicalOrientation270: Qt.LandscapeOrientation
83+ primaryOrientationAngle: 0
84+ }
85+ },
86+ State {
87+ name: "manta"
88+ PropertyChanges {
89+ target: orientedShellLoader
90+ width: units.gu(160)
91+ height: units.gu(100)
92+ }
93+ PropertyChanges {
94+ target: root
95+ physicalOrientation90: Qt.PortraitOrientation
96+ physicalOrientation180: Qt.InvertedLandscapeOrientation
97+ physicalOrientation270: Qt.InvertedPortraitOrientation
98+ physicalOrientation0: Qt.LandscapeOrientation
99+ primaryOrientationAngle: 0
100+ }
101+ },
102+ State {
103+ name: "flo"
104+ PropertyChanges {
105+ target: orientedShellLoader
106+ width: units.gu(62)
107+ height: units.gu(100)
108+ }
109+ PropertyChanges {
110+ target: root
111+ physicalOrientation270: Qt.PortraitOrientation
112+ physicalOrientation0: Qt.InvertedLandscapeOrientation
113+ physicalOrientation90: Qt.InvertedPortraitOrientation
114+ physicalOrientation180: Qt.LandscapeOrientation
115+ primaryOrientationAngle: 90
116+ }
117+ }
118+ ]
119+
120+ Loader {
121+ id: orientedShellLoader
122+
123+ x: ((root.width - controls.width) - width) / 2
124+ y: (root.height - height) / 2
125+
126+ focus: true
127+
128+ property bool itemDestroyed: false
129+ sourceComponent: Component {
130+ OrientedShell {
131+ anchors.fill: parent
132+ usageModeSettings: mockUsageModeSettings
133+ physicalOrientation: root.physicalOrientation0
134+ orientationLocked: orientationLockedCheckBox.checked
135+ orientationLock: mockOrientationLock
136+ Component.onDestruction: {
137+ orientedShellLoader.itemDestroyed = true;
138+ }
139+ }
140+ }
141+ }
142+
143+ function orientationsToStr(orientations) {
144+ if (orientations === Qt.PrimaryOrientation) {
145+ return "Primary";
146+ } else {
147+ var str = "";
148+ if (orientations & Qt.PortraitOrientation) {
149+ str += " Portrait";
150+ }
151+ if (orientations & Qt.InvertedPortraitOrientation) {
152+ str += " InvertedPortrait";
153+ }
154+ if (orientations & Qt.LandscapeOrientation) {
155+ str += " Landscape";
156+ }
157+ if (orientations & Qt.InvertedLandscapeOrientation) {
158+ str += " InvertedLandscape";
159+ }
160+ return str;
161+ }
162+ }
163+
164+ Rectangle {
165+ width: controls.width
166+ anchors {
167+ top: parent.top
168+ bottom: parent.bottom
169+ right: parent.right
170+ }
171+ color: "darkgrey"
172+ }
173+ Flickable {
174+ id: controls
175+ width: units.gu(30)
176+ anchors {
177+ top: parent.top
178+ bottom: parent.bottom
179+ right: parent.right
180+ }
181+
182+ boundsBehavior: Flickable.StopAtBounds
183+ contentHeight: controlsColumn.height
184+
185+ Column {
186+ id: controlsColumn
187+ anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
188+ spacing: units.gu(1)
189+ Button {
190+ text: "Show Greeter"
191+ activeFocusOnPress: false
192+ onClicked: {
193+ if (orientedShellLoader.status !== Loader.Ready)
194+ return;
195+
196+ LightDM.Greeter.showGreeter();
197+ }
198+ }
199+ Label {
200+ text: "Physical Orientation:"
201+ }
202+ Button {
203+ id: rotate0Button
204+ text: root.orientationsToStr(root.physicalOrientation0) + " (0)"
205+ activeFocusOnPress: false
206+ onClicked: {
207+ orientedShellLoader.item.physicalOrientation = root.physicalOrientation0;
208+ }
209+ }
210+ Button {
211+ id: rotate90Button
212+ text: root.orientationsToStr(root.physicalOrientation90) + " (90)"
213+ activeFocusOnPress: false
214+ onClicked: {
215+ orientedShellLoader.item.physicalOrientation = root.physicalOrientation90;
216+ }
217+ }
218+ Button {
219+ id: rotate180Button
220+ text: root.orientationsToStr(root.physicalOrientation180) + " (180)"
221+ activeFocusOnPress: false
222+ onClicked: {
223+ orientedShellLoader.item.physicalOrientation = root.physicalOrientation180;
224+ }
225+ }
226+ Button {
227+ id: rotate270Button
228+ text: root.orientationsToStr(root.physicalOrientation270) + " (270)"
229+ activeFocusOnPress: false
230+ onClicked: {
231+ orientedShellLoader.item.physicalOrientation = root.physicalOrientation270;
232+ }
233+ }
234+ RowLayout {
235+ Layout.fillWidth: true
236+ CheckBox {
237+ id: orientationLockedCheckBox
238+ checked: false
239+ activeFocusOnPress: false
240+ }
241+ Label {
242+ text: "Orientation Locked"
243+ anchors.verticalCenter: parent.verticalCenter
244+ }
245+ }
246+ Button {
247+ text: "Power dialog"
248+ activeFocusOnPress: false
249+ onClicked: { testCase.showPowerDialog(); }
250+ }
251+ ListItem.ItemSelector {
252+ id: deviceNameSelector
253+ anchors { left: parent.left; right: parent.right }
254+ activeFocusOnPress: false
255+ text: "Device Name"
256+ model: ["mako", "manta", "flo"]
257+ onSelectedIndexChanged: {
258+ testCase.tearDown();
259+ applicationArguments.deviceName = model[selectedIndex];
260+ orientedShellLoader.active = true;
261+ }
262+ }
263+ ListItem.ItemSelector {
264+ id: usageModeSelector
265+ anchors { left: parent.left; right: parent.right }
266+ activeFocusOnPress: false
267+ text: "Usage Mode"
268+ model: ["Staged", "Windowed", "Automatic"]
269+ }
270+ Button {
271+ text: "Switch fullscreen"
272+ activeFocusOnPress: false
273+ onClicked: {
274+ var app = ApplicationManager.findApplication(ApplicationManager.focusedApplicationId);
275+ app.fullscreen = !app.fullscreen;
276+ }
277+ }
278+ RowLayout {
279+ Layout.fillWidth: true
280+ CheckBox {
281+ checked: false
282+ activeFocusOnPress: false
283+ onCheckedChanged: {
284+ var surface = SurfaceManager.inputMethodSurface();
285+ if (checked) {
286+ surface.setState(MirSurfaceItem.Restored);
287+ } else {
288+ surface.setState(MirSurfaceItem.Minimized);
289+ }
290+ }
291+ }
292+ Label {
293+ text: "Input Method"
294+ anchors.verticalCenter: parent.verticalCenter
295+ }
296+ }
297+ Button {
298+ text: Powerd.status === Powerd.On ? "Display ON" : "Display OFF"
299+ activeFocusOnPress: false
300+ onClicked: {
301+ if (Powerd.status === Powerd.On) {
302+ Powerd.status = Powerd.Off;
303+ } else {
304+ Powerd.status = Powerd.On;
305+ }
306+ }
307+ }
308+ }
309+ }
310+
311+ UnityTestCase {
312+ id: testCase
313+ name: "OrientedShell"
314+ when: windowShown
315+
316+ property Item orientedShell: orientedShellLoader.status === Loader.Ready ? orientedShellLoader.item : null
317+ property Item shell
318+
319+ SignalSpy { id: signalSpy }
320+ SignalSpy { id: signalSpy2 }
321+
322+ Connections {
323+ id: spreadRepeaterConnections
324+ ignoreUnknownSignals : true
325+ property var itemAddedCallback: null
326+ onItemAdded: {
327+ if (itemAddedCallback) {
328+ itemAddedCallback(item);
329+ }
330+ }
331+ }
332+
333+ function init() {
334+ if (orientedShellLoader.active) {
335+ // happens for the very first test function as shell
336+ // is loaded by default
337+ tearDown();
338+ }
339+ }
340+
341+ function tearDown() {
342+ orientedShellLoader.itemDestroyed = false;
343+ orientedShellLoader.active = false;
344+
345+ tryCompare(orientedShellLoader, "status", Loader.Null);
346+ tryCompare(orientedShellLoader, "item", null);
347+ // Loader.status might be Loader.Null and Loader.item might be null but the Loader
348+ // actually took place. Likely because Loader waits until the next event loop
349+ // iteration to do its work. So to ensure the reload, we will wait until the
350+ // Shell instance gets destroyed.
351+ tryCompare(orientedShellLoader, "itemDestroyed", true);
352+
353+ // kill all (fake) running apps
354+ killApps();
355+
356+ spreadRepeaterConnections.target = null;
357+ spreadRepeaterConnections.itemAddedCallback = null;
358+ signalSpy.target = null;
359+ signalSpy.signalName = "";
360+
361+ LightDM.Greeter.authenticate(""); // reset greeter
362+ }
363+
364+ function cleanup() {
365+ tryCompare(shell, "enabled", true); // make sure greeter didn't leave us in disabled state
366+ shell = null;
367+
368+ tearDown();
369+ }
370+
371+ function test_appSupportingOnlyPrimaryOrientationMakesShellStayPut_data() {
372+ return [
373+ {tag: "mako", deviceName: "mako"},
374+ {tag: "manta", deviceName: "manta"},
375+ {tag: "flo", deviceName: "flo"}
376+ ];
377+ }
378+ function test_appSupportingOnlyPrimaryOrientationMakesShellStayPut(data) {
379+ loadShell(data.deviceName);
380+
381+ // unity8-dash supports only primary orientation and should be already running
382+ var dashAppWindow = findChild(shell, "appWindow_unity8-dash");
383+ verify(dashAppWindow);
384+ compare(ApplicationManager.focusedApplicationId, "unity8-dash");
385+ var dashApp = dashAppWindow.application
386+ verify(dashApp);
387+ compare(dashApp.rotatesWindowContents, false);
388+ compare(dashApp.supportedOrientations, Qt.PrimaryOrientation);
389+ compare(dashApp.stage, ApplicationInfoInterface.MainStage);
390+
391+ tryCompareFunction(function(){return dashApp.session.surface != null;}, true);
392+ verify(checkAppSurfaceOrientation(dashApp, root.primaryOrientationAngle));
393+
394+ compare(shell.transformRotationAngle, root.primaryOrientationAngle);
395+ rotateTo(90);
396+
397+ verify(checkAppSurfaceOrientation(dashApp, root.primaryOrientationAngle));
398+ compare(shell.transformRotationAngle, root.primaryOrientationAngle);
399+
400+ rotateTo(180);
401+
402+ verify(checkAppSurfaceOrientation(dashApp, root.primaryOrientationAngle));
403+ compare(shell.transformRotationAngle, root.primaryOrientationAngle);
404+
405+ rotateTo(270);
406+
407+ verify(checkAppSurfaceOrientation(dashApp, root.primaryOrientationAngle));
408+ compare(shell.transformRotationAngle, root.primaryOrientationAngle);
409+ }
410+
411+ function test_greeterRemainsInPrimaryOrientation_data() {
412+ return [
413+ {tag: "mako", deviceName: "mako"},
414+ {tag: "manta", deviceName: "manta"},
415+ {tag: "flo", deviceName: "flo"}
416+ ];
417+ }
418+ function test_greeterRemainsInPrimaryOrientation(data) {
419+ loadShell(data.deviceName);
420+
421+ var gmailApp = ApplicationManager.startApplication("gmail-webapp");
422+ verify(gmailApp);
423+
424+ // ensure the mock gmail-webapp is as we expect
425+ compare(gmailApp.rotatesWindowContents, false);
426+ compare(gmailApp.supportedOrientations, Qt.PortraitOrientation | Qt.LandscapeOrientation
427+ | Qt.InvertedPortraitOrientation | Qt.InvertedLandscapeOrientation);
428+ compare(gmailApp.stage, ApplicationInfoInterface.MainStage);
429+
430+ // wait until it's able to rotate
431+ tryCompare(shell, "orientationChangesEnabled", true);
432+
433+ compare(shell.transformRotationAngle, root.primaryOrientationAngle);
434+ rotateTo(90);
435+ tryCompare(shell, "transformRotationAngle", root.primaryOrientationAngle + 90);
436+
437+ showGreeter();
438+
439+ tryCompare(shell, "transformRotationAngle", root.primaryOrientationAngle);
440+ rotateTo(180);
441+ compare(shell.transformRotationAngle, root.primaryOrientationAngle);
442+ rotateTo(270);
443+ compare(shell.transformRotationAngle, root.primaryOrientationAngle);
444+ rotateTo(0);
445+ compare(shell.transformRotationAngle, root.primaryOrientationAngle);
446+ }
447+
448+ function test_appRotatesWindowContents_data() {
449+ return [
450+ {tag: "mako", deviceName: "mako", orientationAngleAfterRotation: 90},
451+ {tag: "manta", deviceName: "manta", orientationAngleAfterRotation: 90},
452+ {tag: "flo", deviceName: "flo", orientationAngleAfterRotation: 180}
453+ ];
454+ }
455+ function test_appRotatesWindowContents(data) {
456+ loadShell(data.deviceName);
457+ var cameraApp = ApplicationManager.startApplication("camera-app");
458+ verify(cameraApp);
459+
460+ // ensure the mock camera-app is as we expect
461+ compare(cameraApp.fullscreen, true);
462+ compare(cameraApp.rotatesWindowContents, true);
463+ compare(cameraApp.supportedOrientations, Qt.PortraitOrientation | Qt.LandscapeOrientation
464+ | Qt.InvertedPortraitOrientation | Qt.InvertedLandscapeOrientation);
465+
466+ waitUntilAppSurfaceShowsUp("camera-app")
467+
468+ var cameraSurface = cameraApp.session.surface;
469+ verify(cameraSurface);
470+
471+ var focusChangedSpy = signalSpy;
472+ focusChangedSpy.clear();
473+ focusChangedSpy.target = cameraSurface;
474+ focusChangedSpy.signalName = "activeFocusChanged";
475+ verify(focusChangedSpy.valid);
476+
477+ verify(cameraSurface.activeFocus);
478+
479+ tryCompare(shell, "orientationChangesEnabled", true);
480+
481+ var rotationStates = findInvisibleChild(orientedShell, "rotationStates");
482+ verify(rotationStates);
483+ var immediateTransition = null
484+ for (var i = 0; i < rotationStates.transitions.length && !immediateTransition; ++i) {
485+ var transition = rotationStates.transitions[i];
486+ if (transition.objectName == "immediateTransition") {
487+ immediateTransition = transition;
488+ }
489+ }
490+ verify(immediateTransition);
491+ var transitionSpy = signalSpy2;
492+ transitionSpy.clear();
493+ transitionSpy.target = immediateTransition;
494+ transitionSpy.signalName = "runningChanged";
495+ verify(transitionSpy.valid);
496+
497+ rotateTo(90);
498+
499+ tryCompare(cameraSurface, "orientationAngle", data.orientationAngleAfterRotation);
500+
501+ // the rotation should have been immediate
502+ // false -> true -> false
503+ compare(transitionSpy.count, 2);
504+
505+ // It should retain native dimensions regardless of its rotation/orientation
506+ compare(cameraSurface.width, orientedShell.width);
507+ compare(cameraSurface.height, orientedShell.height);
508+
509+ // Surface focus shouldn't have been touched because of the rotation
510+ compare(focusChangedSpy.count, 0);
511+ }
512+
513+ /*
514+ Preconditions:
515+ Shell orientation angle matches the screen one.
516+
517+ Use case:
518+ User switches to an app that has an orientation angle different from the
519+ shell one but that also happens to support the current shell orientation
520+ angle.
521+
522+ Expected outcome:
523+ The app should get rotated to match shell's orientation angle
524+ */
525+ function test_switchingToAppWithDifferentRotation_data() {
526+ return [
527+ {tag: "mako", deviceName: "mako", shellAngleAfterRotation: 90},
528+ {tag: "manta", deviceName: "manta", shellAngleAfterRotation: 90},
529+ {tag: "flo", deviceName: "flo", shellAngleAfterRotation: 180}
530+ ];
531+ }
532+ function test_switchingToAppWithDifferentRotation(data) {
533+ loadShell(data.deviceName);
534+ var gmailApp = ApplicationManager.startApplication("gmail-webapp");
535+ verify(gmailApp);
536+
537+ // ensure the mock gmail-webapp is as we expect
538+ compare(gmailApp.rotatesWindowContents, false);
539+ compare(gmailApp.supportedOrientations, Qt.PortraitOrientation | Qt.LandscapeOrientation
540+ | Qt.InvertedPortraitOrientation | Qt.InvertedLandscapeOrientation);
541+ compare(gmailApp.stage, ApplicationInfoInterface.MainStage);
542+
543+ waitUntilAppSurfaceShowsUp("gmail-webapp")
544+
545+ var musicApp = ApplicationManager.startApplication("music-app");
546+ verify(musicApp);
547+
548+ // ensure the mock music-app is as we expect
549+ compare(musicApp.rotatesWindowContents, false);
550+ compare(musicApp.supportedOrientations, Qt.PortraitOrientation | Qt.LandscapeOrientation
551+ | Qt.InvertedPortraitOrientation | Qt.InvertedLandscapeOrientation);
552+ compare(musicApp.stage, ApplicationInfoInterface.MainStage);
553+
554+ waitUntilAppSurfaceShowsUp("music-app")
555+ tryCompare(shell, "orientationChangesEnabled", true);
556+
557+ rotateTo(90);
558+ tryCompare(shell, "transformRotationAngle", data.shellAngleAfterRotation);
559+
560+ performEdgeSwipeToSwitchToPreviousApp();
561+
562+ tryCompare(shell, "mainAppWindowOrientationAngle", data.shellAngleAfterRotation);
563+ compare(shell.transformRotationAngle, data.shellAngleAfterRotation);
564+ }
565+
566+ /*
567+ Preconditions:
568+ - Device supports portrait, landscape and inverted-landscape
569+
570+ Steps:
571+ 1 - Launch app that supports all orientations
572+ 2 - Rotate device to inverted-landscape
573+ 3 - See that shell gets rotated to inverted-landscape accordingly
574+ 4 - Rotate device to inverted-portrait
575+
576+ Expected outcome:
577+ Shell stays at inverted-landscape
578+
579+ Actual outcome:
580+ Shell rotates to landscape
581+
582+ Comments:
583+ Rationale being that shell should be rotated to the closest supported orientation.
584+ In that case, landscape and inverted-landscape are both 90 degrees away from the physical
585+ orientation (Screen.orientation), so they are both equally good alternatives
586+ */
587+ function test_rotateToUnsupportedDeviceOrientation(data) {
588+ loadShell("mako");
589+ var twitterApp = ApplicationManager.startApplication("twitter-webapp");
590+ verify(twitterApp);
591+
592+ // ensure the mock twitter-webapp is as we expect
593+ compare(twitterApp.rotatesWindowContents, false);
594+ compare(twitterApp.supportedOrientations, Qt.PortraitOrientation | Qt.LandscapeOrientation
595+ | Qt.InvertedPortraitOrientation | Qt.InvertedLandscapeOrientation);
596+
597+ waitUntilAppSurfaceShowsUp("twitter-webapp")
598+
599+ rotateTo(data.rotationAngle);
600+ tryCompare(shell, "transformRotationAngle", data.rotationAngle);
601+
602+ rotateTo(180);
603+ tryCompare(shell, "transformRotationAngle", data.rotationAngle);
604+ }
605+ function test_rotateToUnsupportedDeviceOrientation_data() {
606+ return [
607+ {tag: "90", rotationAngle: 90},
608+ {tag: "270", rotationAngle: 270}
609+ ];
610+ }
611+
612+ function test_launchLandscapeOnlyAppFromPortrait() {
613+ loadShell("mako");
614+ var weatherApp = ApplicationManager.startApplication("ubuntu-weather-app");
615+ verify(weatherApp);
616+
617+ // ensure the mock app is as we expect
618+ compare(weatherApp.supportedOrientations, Qt.LandscapeOrientation | Qt.InvertedLandscapeOrientation);
619+
620+ waitUntilAppSurfaceShowsUp("ubuntu-weather-app");
621+
622+ var rotationStates = findInvisibleChild(orientedShell, "rotationStates");
623+ waitUntilTransitionsEnd(rotationStates);
624+
625+ tryCompareFunction(function (){return shell.transformRotationAngle === 90
626+ || shell.transformRotationAngle === 270;}, true);
627+ }
628+
629+ /*
630+ - launch an app that supports all orientations, such as twitter-webapp
631+ - wait a bit until that app is considered to have finished initializing and is thus
632+ ready to get resized/rotated
633+ - switch back to dash
634+ - rotate device to 90 degrees
635+ - Physical orientation is 90 but Shell orientation is kept at 0 because unity8-dash
636+ doesn't support such orientation
637+ - do a long right-edge drag to show the apps spread
638+ - tap on twitter-webapp
639+
640+ Shell will rotate to match the physical orientation.
641+
642+ This is a kind of tricky case as there are a few things happening at the same time:
643+ 1 - Stage switching from apps spread (phase 2) to showing the focused app (phase 0)
644+ 2 - orientation and aspect ratio (ie size) changes
645+
646+ This may trigger some corner case bugs. such as one were
647+ the greeter is not kept completely outside the shell, causing the black rect in Shell.qml
648+ have an opacity > 0.
649+ */
650+ function test_greeterStaysAwayAfterRotation() {
651+ loadShell("mako");
652+ var twitterApp = ApplicationManager.startApplication("twitter-webapp");
653+ verify(twitterApp);
654+
655+ // ensure the mock twitter-webapp is as we expect
656+ compare(twitterApp.rotatesWindowContents, false);
657+ compare(twitterApp.supportedOrientations, Qt.PortraitOrientation | Qt.LandscapeOrientation
658+ | Qt.InvertedPortraitOrientation | Qt.InvertedLandscapeOrientation);
659+
660+ waitUntilAppSurfaceShowsUp("twitter-webapp");
661+ waitUntilAppWindowCanRotate("twitter-webapp");
662+
663+ // go back to unity8-dash
664+ performEdgeSwipeToSwitchToPreviousApp();
665+
666+ rotateTo(90);
667+ wait(1); // spin the event loop to let all bindings do their thing
668+ // should not rotat as unity8-dash doesn't support it
669+ tryCompare(shell, "transformRotationAngle", 0);
670+
671+ performEdgeSwipeToShowAppSpread();
672+
673+ // wait until things have settled
674+ var greeter = findChild(shell, "greeter");
675+ tryCompare(greeter, "animating", false);
676+
677+ var twitterDelegate = findChild(shell, "appDelegate1");
678+ compare(twitterDelegate.application.appId, "twitter-webapp");
679+ twitterDelegate.clicked();
680+
681+ // now it should finally follow the physical orientation
682+ tryCompare(shell, "transformRotationAngle", 90);
683+
684+ // greeter should remaing completely hidden
685+ tryCompare(greeter, "shown", false);
686+ }
687+
688+ function test_appInSideStageDoesntRotateOnStartUp_data() {
689+ return [
690+ {tag: "manta", deviceName: "manta"},
691+ {tag: "flo", deviceName: "flo"}
692+ ];
693+ }
694+ function test_appInSideStageDoesntRotateOnStartUp(data) {
695+ loadShell(data.deviceName);
696+
697+ var twitterDelegate = null;
698+
699+ verify(spreadRepeaterConnections.target);
700+ spreadRepeaterConnections.itemAddedCallback = function(item) {
701+ verify(item.application.appId, "twitter-webapp");
702+ twitterDelegate = item;
703+ signalSpy.target = findInvisibleChild(item, "orientationChangeAnimation");
704+ verify(signalSpy.valid);
705+ }
706+
707+ signalSpy.clear();
708+ signalSpy.target = null;
709+ signalSpy.signalName = "runningChanged";
710+
711+ var twitterApp = ApplicationManager.startApplication("twitter-webapp");
712+ verify(twitterApp);
713+
714+ // ensure the mock twitter-webapp is as we expect
715+ compare(twitterApp.rotatesWindowContents, false);
716+ compare(twitterApp.supportedOrientations, Qt.PortraitOrientation | Qt.LandscapeOrientation
717+ | Qt.InvertedPortraitOrientation | Qt.InvertedLandscapeOrientation);
718+ compare(twitterApp.stage, ApplicationInfoInterface.SideStage);
719+
720+ // Wait until spreadRepeaterConnections hs caught the new SpreadDelegate and
721+ // set up the signalSpy target accordingly.
722+ tryCompareFunction(function(){ return signalSpy.target != null && signalSpy.valid; }, true);
723+
724+ tryCompare(twitterDelegate, "orientationChangesEnabled", true);
725+
726+ var appWindowWithShadow = findChild(twitterDelegate, "appWindowWithShadow");
727+ verify(appWindowWithShadow);
728+ tryCompare(appWindowWithShadow, "state", "keepSceneRotation");
729+
730+ // no reason for any rotation animation to have taken place
731+ compare(signalSpy.count, 0);
732+ }
733+
734+ function test_portraitOnlyAppInSideStage_data() {
735+ return [
736+ {tag: "manta", deviceName: "manta"},
737+ {tag: "flo", deviceName: "flo"}
738+ ];
739+ }
740+ function test_portraitOnlyAppInSideStage(data) {
741+ loadShell(data.deviceName);
742+
743+ var dialerDelegate = null;
744+ verify(spreadRepeaterConnections.target);
745+ spreadRepeaterConnections.itemAddedCallback = function(item) {
746+ dialerDelegate = item;
747+ verify(item.application.appId, "dialer-app");
748+ }
749+
750+ var dialerApp = ApplicationManager.startApplication("dialer-app");
751+ verify(dialerApp);
752+
753+ // ensure the mock dialer-app is as we expect
754+ compare(dialerApp.rotatesWindowContents, false);
755+ compare(dialerApp.supportedOrientations, Qt.PortraitOrientation | Qt.InvertedPortraitOrientation);
756+ compare(dialerApp.stage, ApplicationInfoInterface.SideStage);
757+
758+ tryCompareFunction(function(){ return dialerDelegate != null; }, true);
759+ tryCompare(dialerDelegate, "orientationChangesEnabled", true);
760+
761+ var appWindowWithShadow = findChild(dialerDelegate, "appWindowWithShadow");
762+ verify(appWindowWithShadow);
763+ tryCompare(appWindowWithShadow, "state", "keepSceneRotation");
764+
765+ // app must have portrait aspect ratio
766+ verify(appWindowWithShadow.width < appWindowWithShadow.height);
767+
768+ compare(appWindowWithShadow.rotation, 0);
769+
770+ verifyAppWindowWithinSpreadDelegateBoundaries(dialerDelegate);
771+
772+ // shell should remain in its primery orientation as the app in the main stage
773+ // is the one that dictates its orientation. In this case it's unity8-dash
774+ // which supports only primary orientation
775+ compare(shell.orientation, orientedShell.primaryOrientation);
776+ }
777+
778+ function test_sideStageAppsRemainPortraitInSpread_data() {
779+ return [
780+ {tag: "manta", deviceName: "manta"},
781+ {tag: "flo", deviceName: "flo"}
782+ ];
783+ }
784+ function test_sideStageAppsRemainPortraitInSpread(data) {
785+ loadShell(data.deviceName);
786+
787+
788+ ////
789+ // Launch dialer
790+ var dialerDelegate = null;
791+ verify(spreadRepeaterConnections.target);
792+ spreadRepeaterConnections.itemAddedCallback = function(item) {
793+ dialerDelegate = item;
794+ verify(item.application.appId, "dialer-app");
795+ }
796+
797+ var dialerApp = ApplicationManager.startApplication("dialer-app");
798+ verify(dialerApp);
799+
800+ // ensure the mock dialer-app is as we expect
801+ compare(dialerApp.rotatesWindowContents, false);
802+ compare(dialerApp.supportedOrientations, Qt.PortraitOrientation | Qt.InvertedPortraitOrientation);
803+ compare(dialerApp.stage, ApplicationInfoInterface.SideStage);
804+
805+ tryCompareFunction(function(){ return dialerDelegate != null; }, true);
806+ waitUntilAppDelegateIsFullyInit(dialerDelegate);
807+
808+
809+ ////
810+ // Launch twitter
811+ var twitterDelegate = null;
812+ spreadRepeaterConnections.itemAddedCallback = function(item) {
813+ twitterDelegate = item;
814+ verify(item.application.appId, "twitter-webapp");
815+ }
816+
817+ var twitterApp = ApplicationManager.startApplication("twitter-webapp");
818+ verify(twitterApp);
819+
820+ // ensure the mock twitter-webapp is as we expect
821+ compare(twitterApp.rotatesWindowContents, false);
822+ compare(twitterApp.supportedOrientations, Qt.PortraitOrientation | Qt.LandscapeOrientation
823+ | Qt.InvertedPortraitOrientation | Qt.InvertedLandscapeOrientation);
824+ compare(twitterApp.stage, ApplicationInfoInterface.SideStage);
825+
826+ tryCompareFunction(function(){ return twitterDelegate != null; }, true);
827+ waitUntilAppDelegateIsFullyInit(twitterDelegate);
828+
829+ ////
830+ // Edge swipe to show spread and check orientations
831+
832+ performEdgeSwipeToShowAppSpread();
833+
834+ {
835+ var appWindowWithShadow = findChild(dialerDelegate, "appWindowWithShadow");
836+ verify(appWindowWithShadow);
837+ tryCompare(appWindowWithShadow, "state", "keepSceneRotation");
838+ compare(appWindowWithShadow.width, dialerDelegate.width);
839+ compare(appWindowWithShadow.height, dialerDelegate.height);
840+ compare(appWindowWithShadow.rotation, 0);
841+ }
842+ {
843+ var appWindowWithShadow = findChild(twitterDelegate, "appWindowWithShadow");
844+ verify(appWindowWithShadow);
845+ tryCompare(appWindowWithShadow, "state", "keepSceneRotation");
846+ compare(appWindowWithShadow.width, twitterDelegate.width);
847+ compare(appWindowWithShadow.height, twitterDelegate.height);
848+ compare(appWindowWithShadow.rotation, 0);
849+ }
850+
851+ verifyAppWindowWithinSpreadDelegateBoundaries(dialerDelegate);
852+ verifyAppWindowWithinSpreadDelegateBoundaries(twitterDelegate);
853+ }
854+
855+ function test_launchedAppHasActiveFocus_data() {
856+ return [
857+ {tag: "mako", deviceName: "mako"},
858+ {tag: "manta", deviceName: "manta"},
859+ {tag: "flo", deviceName: "flo"}
860+ ];
861+ }
862+ function test_launchedAppHasActiveFocus(data) {
863+ loadShell(data.deviceName);
864+
865+ var gmailApp = ApplicationManager.startApplication("gmail-webapp");
866+ verify(gmailApp);
867+ waitUntilAppSurfaceShowsUp("gmail-webapp")
868+
869+ verify(gmailApp.session.surface);
870+
871+ tryCompare(gmailApp.session.surface, "activeFocus", true);
872+ }
873+
874+ function test_launchLandscapeOnlyAppOverPortraitOnlyDashThenSwitchToDash() {
875+ loadShell("mako");
876+
877+ // starts as portrait, as unity8-dash is portrait only
878+ tryCompare(shell, "transformRotationAngle", 0);
879+
880+ var weatherApp = ApplicationManager.startApplication("ubuntu-weather-app");
881+ verify(weatherApp);
882+
883+ // ensure the mock app is as we expect
884+ compare(weatherApp.supportedOrientations, Qt.LandscapeOrientation | Qt.InvertedLandscapeOrientation);
885+
886+ waitUntilAppSurfaceShowsUp("ubuntu-weather-app");
887+
888+ // should have rotated to landscape
889+ tryCompareFunction(function () { return shell.transformRotationAngle == 270
890+ || shell.transformRotationAngle == 90; }, true);
891+
892+ var rotationStates = findInvisibleChild(orientedShell, "rotationStates");
893+ waitUntilTransitionsEnd(rotationStates);
894+
895+ performLeftEdgeSwipeToSwitchToDash();
896+
897+ // Should be back to portrait
898+ tryCompare(shell, "transformRotationAngle", 0);
899+ }
900+
901+ // angle - rotation angle in degrees clockwise, relative to the primary orientation.
902+ function rotateTo(angle) {
903+ switch (angle) {
904+ case 0:
905+ rotate0Button.clicked();
906+ break;
907+ case 90:
908+ rotate90Button.clicked();
909+ break;
910+ case 180:
911+ rotate180Button.clicked();
912+ break;
913+ case 270:
914+ rotate270Button.clicked();
915+ break;
916+ default:
917+ verify(false);
918+ }
919+
920+ var rotationStates = findInvisibleChild(orientedShell, "rotationStates");
921+ waitUntilTransitionsEnd(rotationStates);
922+ }
923+
924+ function waitUntilAppDelegateIsFullyInit(spreadDelegate) {
925+ tryCompare(spreadDelegate, "orientationChangesEnabled", true);
926+
927+ var appWindowWithShadow = findChild(spreadDelegate, "appWindowWithShadow");
928+ verify(appWindowWithShadow);
929+ tryCompare(appWindowWithShadow, "state", "keepSceneRotation");
930+
931+ var appWindowStates = findInvisibleChild(appWindowWithShadow, "applicationWindowStateGroup");
932+ verify(appWindowStates);
933+ tryCompare(appWindowStates, "state", "surface");
934+ }
935+
936+ function waitUntilAppSurfaceShowsUp(appId) {
937+ var appWindow = findChild(shell, "appWindow_" + appId);
938+ verify(appWindow);
939+ var appWindowStates = findInvisibleChild(appWindow, "applicationWindowStateGroup");
940+ verify(appWindowStates);
941+ tryCompare(appWindowStates, "state", "surface");
942+ }
943+
944+ function waitUntilAppWindowCanRotate(appId) {
945+ var appWindow = findChild(shell, "appWindow_" + appId);
946+ verify(appWindow);
947+ tryCompare(appWindow, "orientationChangesEnabled", true);
948+ }
949+
950+ function waitUntilShellIsInOrientation(orientation) {
951+ tryCompare(shell, "orientation", orientation);
952+ var rotationStates = findInvisibleChild(orientedShell, "rotationStates");
953+ waitUntilTransitionsEnd(rotationStates);
954+ }
955+
956+ function performLeftEdgeSwipeToSwitchToDash() {
957+ var spreadView = findChild(shell, "spreadView");
958+ var swipeLength = spreadView.width * 0.7;
959+
960+ var touchStartX = 1;
961+ var touchStartY = shell.height / 2;
962+ touchFlick(shell,
963+ touchStartX, touchStartY,
964+ touchStartX + swipeLength, touchStartY);
965+
966+ tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
967+ }
968+
969+ function performEdgeSwipeToSwitchToPreviousApp() {
970+ // swipe just enough to ensure an app switch action.
971+ // If we swipe too much we will trigger the spread mode
972+ // and we don't want that.
973+ var spreadView = findChild(shell, "spreadView");
974+ verify(spreadView);
975+
976+ verify(ApplicationManager.count >= 2);
977+ var previousApp = ApplicationManager.get(1);
978+
979+ var touchStartX = shell.width - 1;
980+ var touchStartY = shell.height / 2;
981+
982+ var condition;
983+ if (applicationArguments.deviceName === "phone") {
984+ condition = function() {
985+ return spreadView.shiftedContentX > units.gu(2) &&
986+ spreadView.shiftedContentX < spreadView.positionMarker1 * spreadView.width;
987+ };
988+ } else {
989+ condition = function() {
990+ return spreadView.shiftedContentX > spreadView.width * spreadView.positionMarker1
991+ && spreadView.shiftedContentX < spreadView.width * spreadView.positionMarker2;
992+ };
993+ }
994+
995+ touchDragUntil(shell,
996+ touchStartX, touchStartY,
997+ -units.gu(1), 0,
998+ condition);
999+
1000+ // ensure the app switch animation has ended
1001+ tryCompare(spreadView, "shiftedContentX", 0);
1002+
1003+ compare(ApplicationManager.get(0).appId, previousApp.appId);
1004+ }
1005+
1006+ function performEdgeSwipeToShowAppSpread() {
1007+ var touchStartY = shell.height / 2;
1008+ touchFlick(shell,
1009+ shell.width - 1, touchStartY,
1010+ 0, touchStartY);
1011+
1012+ var spreadView = findChild(shell, "spreadView");
1013+ verify(spreadView);
1014+ tryCompare(spreadView, "phase", 2);
1015+ tryCompare(spreadView, "flicking", false);
1016+ tryCompare(spreadView, "moving", false);
1017+ }
1018+
1019+ function showPowerDialog() {
1020+ var dialogs = findChild(orientedShell, "dialogs");
1021+ var dialogsPrivate = findInvisibleChild(dialogs, "dialogsPrivate");
1022+ dialogsPrivate.showPowerDialog();
1023+ }
1024+
1025+ function verifyAppWindowWithinSpreadDelegateBoundaries(spreadDelegate) {
1026+ var appWindowWithShadow = findChild(spreadDelegate, "appWindowWithShadow");
1027+ verify(appWindowWithShadow);
1028+
1029+ var windowInDelegateCoords = appWindowWithShadow.mapToItem(spreadDelegate, 0, 0,
1030+ appWindowWithShadow.width, appWindowWithShadow.height);
1031+
1032+ compare(windowInDelegateCoords.x, 0);
1033+ compare(windowInDelegateCoords.y, 0);
1034+ compare(windowInDelegateCoords.width, spreadDelegate.width);
1035+ compare(windowInDelegateCoords.height, spreadDelegate.height);
1036+ }
1037+
1038+ function swipeAwayGreeter() {
1039+ var greeter = findChild(shell, "greeter");
1040+ tryCompare(greeter, "fullyShown", true);
1041+
1042+ var touchX = shell.width - (shell.edgeSize / 2);
1043+ var touchY = shell.height / 2;
1044+ touchFlick(shell, touchX, touchY, shell.width * 0.1, touchY);
1045+
1046+ // wait until the animation has finished
1047+ tryCompare(greeter, "shown", false);
1048+ waitForRendering(greeter);
1049+ }
1050+
1051+ function showGreeter() {
1052+ LightDM.Greeter.showGreeter();
1053+ // wait until the animation has finished
1054+ var greeter = findChild(shell, "greeter");
1055+ tryCompare(greeter, "fullyShown", true);
1056+ }
1057+
1058+ function killApps() {
1059+ while (ApplicationManager.count > 1) {
1060+ var appIndex = ApplicationManager.get(0).appId == "unity8-dash" ? 1 : 0
1061+ ApplicationManager.stopApplication(ApplicationManager.get(appIndex).appId);
1062+ }
1063+ compare(ApplicationManager.count, 1)
1064+ }
1065+
1066+ function loadShell(deviceName) {
1067+ applicationArguments.deviceName = deviceName;
1068+
1069+ // reload our test subject to get it in a fresh state once again
1070+ orientedShellLoader.active = true;
1071+
1072+ tryCompare(orientedShellLoader, "status", Loader.Ready);
1073+ removeTimeConstraintsFromDirectionalDragAreas(orientedShellLoader.item);
1074+
1075+ shell = findChild(orientedShell, "shell");
1076+
1077+ tryCompare(shell, "enabled", true); // enabled by greeter when ready
1078+
1079+ waitUntilShellIsInOrientation(root.physicalOrientation0);
1080+
1081+ waitForGreeterToStabilize();
1082+
1083+ swipeAwayGreeter();
1084+
1085+ var spreadRepeater = findChild(shell, "spreadRepeater");
1086+ if (spreadRepeater) {
1087+ spreadRepeaterConnections.target = spreadRepeater;
1088+ }
1089+ }
1090+
1091+ function waitForGreeterToStabilize() {
1092+ var greeter = findChild(shell, "greeter");
1093+ verify(greeter);
1094+
1095+ var loginList = findChild(greeter, "loginList");
1096+ // Only present in WideView
1097+ if (loginList) {
1098+ var userList = findChild(loginList, "userList");
1099+ verify(userList);
1100+ tryCompare(userList, "movingInternally", false);
1101+ }
1102+ }
1103+
1104+ // expectedAngle is in orientedShell's coordinate system
1105+ function checkAppSurfaceOrientation(app, expectedAngle) {
1106+ var surface = app.session.surface;
1107+ if (!surface) {
1108+ console.warn("no surface");
1109+ return false;
1110+ }
1111+
1112+ if (!itemIsChildOfOrientedShell(surface)) {
1113+ console.warn("surface not a child of OrientedShell");
1114+ return false;
1115+ }
1116+
1117+ var topMargin = 0.;
1118+ if (!app.fullscreen) {
1119+ var appsDisplayLoader = findChild(shell, "applicationsDisplayLoader");
1120+ verify(appsDisplayLoader);
1121+ verify(appsDisplayLoader.item);
1122+ verify(appsDisplayLoader.item.maximizedAppTopMargin !== undefined);
1123+ topMargin = appsDisplayLoader.item.maximizedAppTopMargin;
1124+ }
1125+
1126+ var point = surface.mapToItem(orientedShell, 0, 0);
1127+
1128+ switch (expectedAngle) {
1129+ case 0:
1130+ return point.x === 0. && point.y === topMargin;
1131+ case 90:
1132+ return point.x === orientedShell.width - topMargin && point.y === 0;
1133+ case 180:
1134+ return point.x === orientedShell.width && point.y === orientedShell.height - topMargin;
1135+ default: // 270
1136+ return point.x === topMargin && point.y === orientedShell.height;
1137+ }
1138+ }
1139+
1140+ function itemIsChildOfOrientedShell(item) {
1141+ var parent = item.parent;
1142+ var found = false;
1143+ while (parent && !found) {
1144+ found = parent === orientedShell;
1145+ parent = parent.parent;
1146+ }
1147+ return found;
1148+ }
1149+ }
1150+
1151+}
tests/qmltests/tst_Shell.qml+152−107
@@ -1,9 +1,6 @@
1/*
1/*
2 * Copyright (C) 2013-2015 Canonical, Ltd.
2 * Copyright (C) 2013-2015 Canonical, Ltd.
3 *
3 *
4− * Authors:
5− * Daniel d'Andrada <daniel.dandrada@canonical.com>
6− *
7 * 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
8 * 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
9 * the Free Software Foundation; version 3.
6 * the Free Software Foundation; version 3.
@@ -34,6 +31,7 @@ import Powerd 0.1
34import Wizard 0.1 as Wizard
31import Wizard 0.1 as Wizard
35
32
36import "../../qml"
33import "../../qml"
34+import "Stages"
37
35
38Rectangle {
36Rectangle {
39 id: root
37 id: root
@@ -48,22 +46,6 @@ Rectangle {
48 shellLoader.active = true;
46 shellLoader.active = true;
49 }
47 }
50
48
51− QtObject {
52− id: applicationArguments
53−
54− function hasGeometry() {
55− return false;
56− }
57−
58− function width() {
59− return 0;
60− }
61−
62− function height() {
63− return 0;
64− }
65− }
66−
67 Item {
49 Item {
68 anchors.left: root.left
50 anchors.left: root.left
69 anchors.right: controls.left
51 anchors.right: controls.left
@@ -99,8 +81,12 @@ Rectangle {
99 property bool itemDestroyed: false
81 property bool itemDestroyed: false
100 sourceComponent: Component {
82 sourceComponent: Component {
101 Shell {
83 Shell {
102− property string indicatorProfile: "phone"
84+ property string shellMode: "full-greeter" /* default */
103
85
86+ usageScenario: "phone"
87+ orientation: Qt.PortraitOrientation
88+ primaryOrientation: Qt.PortraitOrientation
89+ nativeOrientation: Qt.PortraitOrientation
104 Component.onDestruction: {
90 Component.onDestruction: {
105 shellLoader.itemDestroyed = true;
91 shellLoader.itemDestroyed = true;
106 }
92 }
@@ -109,19 +95,25 @@ Rectangle {
109 }
95 }
110 }
96 }
111
97
112− Rectangle {
98+ Flickable {
113 id: controls
99 id: controls
114− color: "darkgrey"
100+ contentHeight: controlRect.height
115− width: units.gu(30)
101+
116 anchors.top: root.top
102 anchors.top: root.top
117 anchors.bottom: root.bottom
103 anchors.bottom: root.bottom
118 anchors.right: root.right
104 anchors.right: root.right
105+ width: units.gu(30)
106+
107+ Rectangle {
108+ id: controlRect
109+ anchors { left: parent.left; right: parent.right }
110+ color: "darkgrey"
111+ height: childrenRect.height + units.gu(2)
112+
113+ Column {
114+ anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
115+ spacing: units.gu(1)
119
116
120− Column {
121− anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
122− spacing: units.gu(1)
123− Row {
124− anchors { left: parent.left; right: parent.right }
125 Button {
117 Button {
126 text: "Show Greeter"
118 text: "Show Greeter"
127 activeFocusOnPress: false
119 activeFocusOnPress: false
@@ -135,30 +127,54 @@ Rectangle {
135 }
127 }
136 }
128 }
137 }
129 }
138− }
139− ListItem.ItemSelector {
130+ ListItem.ItemSelector {
140− anchors { left: parent.left; right: parent.right }
131+ anchors { left: parent.left; right: parent.right }
141− activeFocusOnPress: false
132+ activeFocusOnPress: false
142− text: "LightDM mock mode"
133+ text: "LightDM mock mode"
143− model: ["single", "single-passphrase", "single-pin", "full"]
134+ model: ["single", "single-passphrase", "single-pin", "full"]
144− onSelectedIndexChanged: {
135+ onSelectedIndexChanged: {
145− shellLoader.active = false;
136+ shellLoader.active = false;
146− LightDM.Greeter.mockMode = model[selectedIndex];
137+ LightDM.Greeter.mockMode = model[selectedIndex];
147− LightDM.Users.mockMode = model[selectedIndex];
138+ LightDM.Users.mockMode = model[selectedIndex];
148− shellLoader.active = true;
139+ shellLoader.active = true;
140+ }
149 }
141 }
150− }
151− ListItem.ItemSelector {
142+ ListItem.ItemSelector {
152− anchors { left: parent.left; right: parent.right }
143+ anchors { left: parent.left; right: parent.right }
153− activeFocusOnPress: false
144+ activeFocusOnPress: false
154− text: "Size"
145+ text: "Size"
155− model: ["phone", "tablet"]
146+ model: ["phone", "tablet"]
156− onSelectedIndexChanged: {
147+ onSelectedIndexChanged: {
157− shellLoader.active = false;
148+ shellLoader.active = false;
158− shellLoader.state = model[selectedIndex];
149+ shellLoader.state = model[selectedIndex];
159− shellLoader.active = true;
150+ shellLoader.active = true;
151+ }
152+ }
153+ ListItem.ItemSelector {
154+ id: usageModeSelector
155+ anchors { left: parent.left; right: parent.right }
156+ activeFocusOnPress: false
157+ text: "Usage mode"
158+ model: ["Staged", "Windowed"]
159+ onSelectedIndexChanged: {
160+ GSettingsController.setUsageMode(model[selectedIndex]);
161+ }
162+ }
163+ MouseTouchEmulationCheckbox {
164+ id: mouseEmulation
165+ checked: true
166+ color: "white"
167+ }
168+
169+ Label { text: "Applications"; font.bold: true }
170+
171+ Repeater {
172+ id: appRepeater
173+ model: ApplicationManager.availableApplications
174+ ApplicationCheckBox {
175+ appId: modelData
176+ }
160 }
177 }
161− MouseTouchEmulationCheckbox { color: "white" }
162 }
178 }
163 }
179 }
164 }
180 }
@@ -239,6 +255,7 @@ Rectangle {
239 function cleanup() {
255 function cleanup() {
240 tryCompare(shell, "enabled", true); // make sure greeter didn't leave us in disabled state
256 tryCompare(shell, "enabled", true); // make sure greeter didn't leave us in disabled state
241 tearDown();
257 tearDown();
258+ GSettingsController.setUsageMode("Staged");
242 }
259 }
243
260
244 function loadShell(formFactor) {
261 function loadShell(formFactor) {
@@ -632,15 +649,6 @@ Rectangle {
632 tryCompare(item, "visible", false);
649 tryCompare(item, "visible", false);
633 }
650 }
634
651
635− // wait until any transition animation has finished
636− function waitUntilTransitionsEnd(stateGroup) {
637− var transitions = stateGroup.transitions;
638− for (var i = 0; i < transitions.length; ++i) {
639− var transition = transitions[i];
640− tryCompare(transition, "running", false, 2000);
641− }
642− }
643−
644 // Wait until the ApplicationWindow for the given Application object is fully loaded
652 // Wait until the ApplicationWindow for the given Application object is fully loaded
645 // (ie, the real surface has replaced the splash screen)
653 // (ie, the real surface has replaced the splash screen)
646 function waitUntilAppWindowIsFullyLoaded(app) {
654 function waitUntilAppWindowIsFullyLoaded(app) {
@@ -685,22 +693,57 @@ Rectangle {
685
693
686 function test_launchedAppHasActiveFocus_data() {
694 function test_launchedAppHasActiveFocus_data() {
687 return [
695 return [
688− {tag:"phone", formFactor:"phone"},
696+ {tag: "phone", formFactor: "phone", usageMode: "Staged"},
689− {tag:"tablet", formFactor:"tablet"},
697+ {tag: "tablet", formFactor: "tablet", usageMode: "Staged"},
698+ {tag: "desktop", formFactor: "tablet", usageMode: "Windowed"}
690− ];
699+ ]
691 }
700 }
692
701
693 function test_launchedAppHasActiveFocus(data) {
702 function test_launchedAppHasActiveFocus(data) {
703+ GSettingsController.setUsageMode(data.usageMode);
694 loadShell(data.formFactor);
704 loadShell(data.formFactor);
695 swipeAwayGreeter();
705 swipeAwayGreeter();
696
706
697− var dialerApp = ApplicationManager.startApplication("webbrowser-app");
707+ var webApp = ApplicationManager.startApplication("webbrowser-app");
698− verify(dialerApp);
708+ verify(webApp);
699 waitUntilAppSurfaceShowsUp("webbrowser-app")
709 waitUntilAppSurfaceShowsUp("webbrowser-app")
700
710
701− verify(dialerApp.session.surface);
711+ verify(webApp.session.surface);
712+
713+ tryCompare(webApp.session.surface, "activeFocus", true);
714+ }
715+
716+ function test_launchedAppKeepsActiveFocusOnUsageModeChange() {
717+ loadShell("tablet");
718+ swipeAwayGreeter();
719+
720+ var webApp = ApplicationManager.startApplication("webbrowser-app");
721+ verify(webApp);
722+ waitUntilAppSurfaceShowsUp("webbrowser-app")
723+
724+ verify(webApp.session.surface);
725+
726+ tryCompare(webApp.session.surface, "activeFocus", true);
727+
728+ GSettingsController.setUsageMode("Windowed");
702
729
730+ // check that the desktop stage and window have been loaded
731+ {
732+ var desktopWindow = findChild(shell, "decoratedWindow_webbrowser-app");
733+ verify(desktopWindow);
734+ }
735+
736+ tryCompare(webApp.session.surface, "activeFocus", true);
737+
738+ GSettingsController.setUsageMode("Staged");
739+
740+ // check that the tablet stage and app surface delegate have been loaded
741+ {
742+ var desktopWindow = findChild(shell, "tabletSpreadDelegate_webbrowser-app");
743+ verify(desktopWindow);
744+ }
745+
703− tryCompare(dialerApp.session.surface, "activeFocus", true);
746+ tryCompare(webApp.session.surface, "activeFocus", true);
704 }
747 }
705
748
706 function waitUntilAppSurfaceShowsUp(appId) {
749 function waitUntilAppSurfaceShowsUp(appId) {
@@ -798,37 +841,6 @@ Rectangle {
798 removeTimeConstraintsFromDirectionalDragAreas(greeter);
841 removeTimeConstraintsFromDirectionalDragAreas(greeter);
799 }
842 }
800
843
801− function test_greeterDoesNotChangeIndicatorProfile() {
802− loadShell("phone");
803− swipeAwayGreeter();
804− var panel = findChild(shell, "panel");
805− tryCompare(panel.indicators.indicatorsModel, "profile", shell.indicatorProfile);
806−
807− showGreeter();
808− tryCompare(panel.indicators.indicatorsModel, "profile", shell.indicatorProfile);
809−
810− LightDM.Greeter.hideGreeter();
811− tryCompare(panel.indicators.indicatorsModel, "profile", shell.indicatorProfile);
812− }
813−
814− function test_shellProfileChangesReachIndicators() {
815− loadShell("phone");
816− swipeAwayGreeter();
817− var panel = findChild(shell, "panel");
818−
819− shell.indicatorProfile = "test1";
820− for (var i = 0; i < panel.indicators.indicatorsModel.count; ++i) {
821− var properties = panel.indicators.indicatorsModel.data(i, IndicatorsModelRole.IndicatorProperties);
822− verify(properties["menuObjectPath"].substr(-5), "test1");
823− }
824−
825− shell.indicatorProfile = "test2";
826− for (var i = 0; i < panel.indicators.indicatorsModel.count; ++i) {
827− var properties = panel.indicators.indicatorsModel.data(i, IndicatorsModelRole.IndicatorProperties);
828− verify(properties["menuObjectPath"].substr(-5), "test2");
829− }
830− }
831−
832 function test_focusRequestedHidesGreeter() {
844 function test_focusRequestedHidesGreeter() {
833 loadShell("phone");
845 loadShell("phone");
834 swipeAwayGreeter();
846 swipeAwayGreeter();
@@ -1003,9 +1015,14 @@ Rectangle {
1003 loadShell("phone");
1015 loadShell("phone");
1004 swipeAwayGreeter();
1016 swipeAwayGreeter();
1005 var topmostSpreadDelegate = findChild(shell, "appDelegate0");
1017 var topmostSpreadDelegate = findChild(shell, "appDelegate0");
1018+ verify(topmostSpreadDelegate);
1019+
1020+ waitUntilFocusedApplicationIsShowingItsSurface();
1021+
1006 var topmostSurface = findChild(topmostSpreadDelegate, "surfaceContainer").surface;
1022 var topmostSurface = findChild(topmostSpreadDelegate, "surfaceContainer").surface;
1007− var rightEdgeDragArea = findChild(shell, "spreadDragArea");
1023+ verify(topmostSurface);
1008
1024
1025+ var rightEdgeDragArea = findChild(shell, "spreadDragArea");
1009 topmostSurface.touchPressCount = 0;
1026 topmostSurface.touchPressCount = 0;
1010 topmostSurface.touchReleaseCount = 0;
1027 topmostSurface.touchReleaseCount = 0;
1011
1028
@@ -1092,13 +1109,11 @@ Rectangle {
1092 // left edge drag area.
1109 // left edge drag area.
1093 {
1110 {
1094 var buttonShowDashHome = findChild(launcher, "buttonShowDashHome");
1111 var buttonShowDashHome = findChild(launcher, "buttonShowDashHome");
1095− var startPos = buttonShowDashHome.mapToItem(shell,
1112+ touchFlick(buttonShowDashHome,
1096− buttonShowDashHome.width * 0.2,
1113+ buttonShowDashHome.width * 0.2, /* startPos.x */
1097− buttonShowDashHome.height * 0.8);
1114+ buttonShowDashHome.height * 0.8, /* startPos.y */
1098− var endPos = buttonShowDashHome.mapToItem(shell,
1115+ buttonShowDashHome.width * 0.8, /* endPos.x */
1099− buttonShowDashHome.width * 0.8,
1116+ buttonShowDashHome.height * 0.2 /* endPos.y */);
1100− buttonShowDashHome.height * 0.2);
1101− touchFlick(shell, startPos.x, startPos.y, endPos.x, endPos.y);
1102 }
1117 }
1103
1118
1104 compare(launcherShowDashHomeSpy.count, 1);
1119 compare(launcherShowDashHomeSpy.count, 1);
@@ -1130,8 +1145,7 @@ Rectangle {
1130 loadShell("phone");
1145 loadShell("phone");
1131 swipeAwayGreeter();
1146 swipeAwayGreeter();
1132 AccountsService.backgroundFile = data.accounts;
1147 AccountsService.backgroundFile = data.accounts;
1133− var backgroundSettings = findInvisibleChild(shell, "backgroundSettings");
1148+ GSettingsController.setPictureUri(data.gsettings);
1134− backgroundSettings.pictureUri = data.gsettings;
1135
1149
1136 if (data.output === "defaultBackground") {
1150 if (data.output === "defaultBackground") {
1137 tryCompare(shell, "background", shell.defaultBackground);
1151 tryCompare(shell, "background", shell.defaultBackground);
@@ -1188,5 +1202,36 @@ Rectangle {
1188 tryCompare(passwordInput, "focus", true)
1202 tryCompare(passwordInput, "focus", true)
1189 }
1203 }
1190 }
1204 }
1205+
1206+ function test_stageLoader_data() {
1207+ return [
1208+ {tag: "phone", source: "Stages/PhoneStage.qml", formFactor: "phone", usageMode: "Staged"},
1209+ {tag: "tablet", source: "Stages/TabletStage.qml", formFactor: "tablet", usageMode: "Staged"},
1210+ {tag: "desktop", source: "Stages/DesktopStage.qml", formFactor: "tablet", usageMode: "Windowed"}
1211+ ]
1212+ }
1213+
1214+ function test_stageLoader(data) {
1215+ GSettingsController.setUsageMode(data.usageMode);
1216+ loadShell(data.formFactor);
1217+ var stageLoader = findChild(shell, "applicationsDisplayLoader");
1218+ verify(String(stageLoader.source).indexOf(data.source) >= 0);
1219+ }
1220+
1221+ function test_launcherInverted_data() {
1222+ return [
1223+ {tag: "phone", formFactor: "phone", usageMode: "Staged", launcherInverted: true},
1224+ {tag: "tablet", formFactor: "tablet", usageMode: "Staged", launcherInverted: true},
1225+ {tag: "desktop", formFactor: "tablet", usageMode: "Windowed", launcherInverted: false}
1226+ ]
1227+ }
1228+
1229+ function test_launcherInverted(data) {
1230+ GSettingsController.setUsageMode(data.usageMode);
1231+ loadShell(data.formFactor);
1232+
1233+ var launcher = findChild(shell, "launcher");
1234+ compare(launcher.inverted, data.launcherInverted);
1235+ }
1191 }
1236 }
1192}
1237}
tests/qmltests/tst_ShellWithPin.qml+7−9
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2014 Canonical, Ltd.
2+ * Copyright (C) 2014-2015 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
@@ -69,7 +69,7 @@ Item {
69 property bool itemDestroyed: false
69 property bool itemDestroyed: false
70 sourceComponent: Component {
70 sourceComponent: Component {
71 Shell {
71 Shell {
72− property string indicatorProfile: "phone"
72+ property string shellMode: "full-greeter" /* default */
73
73
74 Component.onDestruction: {
74 Component.onDestruction: {
75 shellLoader.itemDestroyed = true
75 shellLoader.itemDestroyed = true
@@ -397,24 +397,22 @@ Item {
397 var applicationsDisplayLoader = findChild(shell, "applicationsDisplayLoader")
397 var applicationsDisplayLoader = findChild(shell, "applicationsDisplayLoader")
398
398
399 // We start in phone mode
399 // We start in phone mode
400− tryCompare(shell, "sideStageEnabled", false)
400+ compare(shell.usageScenario, "phone");
401− tryCompare(applicationsDisplayLoader, "tabletMode", false)
401+ compare(applicationsDisplayLoader.usageScenario, "phone");
402
402
403 var lockscreen = findChild(shell, "lockscreen")
403 var lockscreen = findChild(shell, "lockscreen")
404 lockscreen.emergencyCall()
404 lockscreen.emergencyCall()
405 confirmLockedApp("dialer-app")
405 confirmLockedApp("dialer-app")
406
406
407 // OK, we're in. Now try (but fail) to switch to tablet mode
407 // OK, we're in. Now try (but fail) to switch to tablet mode
408− shell.tablet = true
408+ shell.usageScenario = "tablet";
409− tryCompare(shell, "sideStageEnabled", true)
410− tryCompare(applicationsDisplayLoader, "tabletMode", false)
409+ compare(applicationsDisplayLoader.usageScenario, "phone");
411
410
412 // And when we kill the app, we go back to locked tablet mode
411 // And when we kill the app, we go back to locked tablet mode
413 killApps()
412 killApps()
414 var greeter = findChild(shell, "greeter")
413 var greeter = findChild(shell, "greeter")
415 tryCompare(greeter, "fullyShown", true)
414 tryCompare(greeter, "fullyShown", true)
416− tryCompare(shell, "sideStageEnabled", true)
417− tryCompare(applicationsDisplayLoader, "tabletMode", true)
415+ compare(applicationsDisplayLoader.usageScenario, "tablet");
418 }
416 }
419
417
420 function test_emergencyDialerIncoming() {
418 function test_emergencyDialerIncoming() {
tests/uqmlscene/main.cpp−10
@@ -63,9 +63,6 @@
63#include <QtCore/QTranslator>
63#include <QtCore/QTranslator>
64#include <QtCore/QLibraryInfo>
64#include <QtCore/QLibraryInfo>
65
65
66−// UbuntuGestures lib
67−#include <TouchRegistry.h>
68−
69#define UQMLSCENE_DEBUG_ACTIVE_FOCUS 0
66#define UQMLSCENE_DEBUG_ACTIVE_FOCUS 0
70
67
71#if UQMLSCENE_DEBUG_ACTIVE_FOCUS
68#if UQMLSCENE_DEBUG_ACTIVE_FOCUS
@@ -434,11 +431,6 @@ int main(int argc, char ** argv)
434 app.setOrganizationName("Qt Project");
431 app.setOrganizationName("Qt Project");
435 app.setOrganizationDomain("qt-project.org");
432 app.setOrganizationDomain("qt-project.org");
436
433
437− // Create it before loading the module, so that TestUtil
438− // doesn't create one with a fake timer factory.
439− // When interacting manually with a test we want the real deal.
440− new TouchRegistry;
441−
442#ifndef QT_NO_TRANSLATION
434#ifndef QT_NO_TRANSLATION
443 QTranslator translator;
435 QTranslator translator;
444 QTranslator qtTranslator;
436 QTranslator qtTranslator;
@@ -512,8 +504,6 @@ int main(int argc, char ** argv)
512 #if UQMLSCENE_DEBUG_ACTIVE_FOCUS
504 #if UQMLSCENE_DEBUG_ACTIVE_FOCUS
513 activeFocusLogger.setWindow(qxView);
505 activeFocusLogger.setWindow(qxView);
514 #endif
506 #endif
515− TouchRegistry::instance()->setParent(qxView);
516− qxView->installEventFilter(TouchRegistry::instance());
517 window = qxView;
507 window = qxView;
518 // Set window default properties; the qml can still override them
508 // Set window default properties; the qml can still override them
519 QString oname = contentItem->objectName();
509 QString oname = contentItem->objectName();
tests/utils/modules/Unity/Test/MouseTouchEmulationCheckbox.qml+1
@@ -22,6 +22,7 @@ import Unity.Test 0.1
22RowLayout {
22RowLayout {
23 id: root
23 id: root
24 property alias color: label.color
24 property alias color: label.color
25+ property alias checked: checkbox.checked
25
26
26 Binding {
27 Binding {
27 target: MouseTouchAdaptor
28 target: MouseTouchAdaptor
tests/utils/modules/Unity/Test/UnityTestCase.qml+53−3
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright 2013 Canonical Ltd.
2+ * Copyright 2013-2015 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
@@ -308,6 +308,48 @@ TestCase {
308 }
308 }
309 }
309 }
310
310
311+ // perform a drag in the given direction until the given condition is true
312+ // The condition is a function to be evaluated after every step
313+ function touchDragUntil(item, startX, startY, stepX, stepY, condition) {
314+
315+ var root = fetchRootItem(item);
316+ var pos = item.mapToItem(root, startX, startY);
317+
318+ // convert step to scene coords
319+ {
320+ var stepStart = item.mapToItem(root, 0, 0);
321+ var stepEnd = item.mapToItem(root, stepX, stepY);
322+ }
323+ stepX = stepEnd.x - stepStart.x;
324+ stepY = stepEnd.y - stepStart.y;
325+
326+ var event = touchEvent(item)
327+ event.press(0 /* touchId */, pos.x, pos.y)
328+ event.commit()
329+
330+ // we have to stop at some point
331+ var maxSteps = 100;
332+ var stepsDone = 0;
333+
334+ while (!condition() && stepsDone < maxSteps) {
335+ wait(25);
336+ fakeDateTime.currentTimeMs += 25;
337+
338+ pos.x += stepX;
339+ pos.y += stepY;
340+
341+ event = touchEvent(item);
342+ event.move(0 /* touchId */, pos.x, pos.y);
343+ event.commit();
344+
345+ stepsDone += 1;
346+ }
347+
348+ event = touchEvent(item)
349+ event.release(0 /* touchId */, pos.x, pos.y)
350+ event.commit()
351+ }
352+
311 function touchPinch(item, x1Start, y1Start, x1End, y1End, x2Start, y2Start, x2End, y2End) {
353 function touchPinch(item, x1Start, y1Start, x1End, y1End, x2Start, y2Start, x2End, y2End) {
312 // Make sure the item is rendered
354 // Make sure the item is rendered
313 waitForRendering(item);
355 waitForRendering(item);
@@ -382,8 +424,6 @@ TestCase {
382 }
424 }
383
425
384 Component.onCompleted: {
426 Component.onCompleted: {
385− UT.Util.ensureTouchRegistryInstalled();
386−
387 var rootItem = parent;
427 var rootItem = parent;
388 while (rootItem.parent != undefined) {
428 while (rootItem.parent != undefined) {
389 rootItem = rootItem.parent;
429 rootItem = rootItem.parent;
@@ -421,4 +461,14 @@ TestCase {
421 return qtest_results.waitForRendering(item, timeout);
461 return qtest_results.waitForRendering(item, timeout);
422 }
462 }
423
463
464+ /*
465+ Wait until any transition animation has finished for the given StateGroup or Item
466+ */
467+ function waitUntilTransitionsEnd(stateGroup) {
468+ var transitions = stateGroup.transitions;
469+ for (var i = 0; i < transitions.length; ++i) {
470+ var transition = transitions[i];
471+ tryCompare(transition, "running", false, 2000);
472+ }
473+ }
424}
474}
tests/utils/modules/Unity/Test/plugin.h+1−1
@@ -26,7 +26,7 @@ class UnityTestPlugin : public QQmlExtensionPlugin
26 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
27
27
28public:
28public:
29− void registerTypes(const char *uri);
29+ void registerTypes(const char *uri) override;
30};
30};
31
31
32#endif // UNITY_TEST_PLUGIN_H
32#endif // UNITY_TEST_PLUGIN_H
tests/utils/modules/Unity/Test/testutil.cpp+8−20
@@ -31,6 +31,7 @@ TestUtil::TestUtil(QObject *parent)
31 : QObject(parent)
31 : QObject(parent)
32 , m_targetWindow(0)
32 , m_targetWindow(0)
33 , m_touchDevice(0)
33 , m_touchDevice(0)
34+ , m_putFakeTimerFactoryInTouchRegistry(false)
34{
35{
35}
36}
36
37
@@ -59,7 +60,13 @@ TouchEventSequenceWrapper *TestUtil::touchEvent(QQuickItem *item)
59{
60{
60 ensureTargetWindow();
61 ensureTargetWindow();
61 ensureTouchDevice();
62 ensureTouchDevice();
62− ensureTouchRegistryInstalled();
63+
64+ // Tests can be *very* slow to run and we don't want things timing out because
65+ // of that. So give it fake timers to use (they will never time out)
66+ if (!m_putFakeTimerFactoryInTouchRegistry) {
67+ TouchRegistry::instance()->setTimerFactory(new FakeTimerFactory);
68+ m_putFakeTimerFactoryInTouchRegistry = true;
69+ }
63
70
64 return new TouchEventSequenceWrapper(
71 return new TouchEventSequenceWrapper(
65 QTest::touchEvent(m_targetWindow, m_touchDevice, /* autoCommit */ false), item);
72 QTest::touchEvent(m_targetWindow, m_touchDevice, /* autoCommit */ false), item);
@@ -79,22 +86,3 @@ void TestUtil::ensureTouchDevice()
79 QWindowSystemInterface::registerTouchDevice(m_touchDevice);
86 QWindowSystemInterface::registerTouchDevice(m_touchDevice);
80 }
87 }
81}
88}
82−
83−void TestUtil::ensureTouchRegistryInstalled()
84−{
85− if (TouchRegistry::instance())
86− return;
87−
88− if (!m_targetWindow)
89− return;
90−
91− // Tests can be *very* slow to run and we don't want things timing out because
92− // of that. So give it fake timers to use (they will never time out)
93− TouchRegistry *touchRegistry = new TouchRegistry(this, new FakeTimerFactory);
94−
95− QQuickView *view = qobject_cast<QQuickView*>(m_targetWindow);
96− if (view) {
97− view->installEventFilter(touchRegistry);
98− touchRegistry->setParent(view);
99− }
100−}
tests/utils/modules/Unity/Test/testutil.h+1−1
@@ -34,7 +34,6 @@ public:
34
34
35 Q_INVOKABLE bool isInstanceOf(QObject*, QString);
35 Q_INVOKABLE bool isInstanceOf(QObject*, QString);
36 Q_INVOKABLE TouchEventSequenceWrapper *touchEvent(QQuickItem *item);
36 Q_INVOKABLE TouchEventSequenceWrapper *touchEvent(QQuickItem *item);
37− Q_INVOKABLE void ensureTouchRegistryInstalled();
38
37
39private:
38private:
40 void ensureTargetWindow();
39 void ensureTargetWindow();
@@ -42,6 +41,7 @@ private:
42
41
43 QWindow *m_targetWindow;
42 QWindow *m_targetWindow;
44 QTouchDevice *m_touchDevice;
43 QTouchDevice *m_touchDevice;
44+ bool m_putFakeTimerFactoryInTouchRegistry;
45};
45};
46
46
47QML_DECLARE_TYPE(TestUtil)
47QML_DECLARE_TYPE(TestUtil)