on xenial help sign in
Merge from trunk
567f2a3Michael Terry
CMakeLists.txt+5−5
@@ -48,11 +48,11 @@ add_custom_target(cppcheck COMMAND cppcheck --enable=all -q --error-exitcode=2
48 ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/tests)
48 ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/tests)
49
49
50include(FindPkgConfig)
50include(FindPkgConfig)
51−find_package(Qt5Core)
51+find_package(Qt5Core 5.2 REQUIRED)
52−find_package(Qt5Qml)
52+find_package(Qt5Qml 5.2 REQUIRED)
53−find_package(Qt5Quick)
53+find_package(Qt5Quick 5.2 REQUIRED)
54−find_package(Qt5Gui)
54+find_package(Qt5Gui 5.2 REQUIRED)
55−find_package(Qt5DBus)
55+find_package(Qt5DBus 5.2 REQUIRED)
56
56
57# Standard install paths
57# Standard install paths
58include(GNUInstallDirs)
58include(GNUInstallDirs)
CODING+11−11
@@ -20,7 +20,7 @@ install dependencies
20If its your first time, install build dependencies
20If its your first time, install build dependencies
21
21
22$ cd ~/unity8/trunk
22$ cd ~/unity8/trunk
23−$ ./build --setup
23+$ ./build.sh --setup
24
24
25 this will:
25 this will:
26 - install the required dependencies to build, as well as run on the desktop
26 - install the required dependencies to build, as well as run on the desktop
@@ -31,7 +31,7 @@ build Unity 8
31-------------
31-------------
32
32
33$ cd ~/unity8/trunk
33$ cd ~/unity8/trunk
34−$ ./build
34+$ ./build.sh
35
35
36You may also rebuild with the -c for clean, which just deletes the build
36You may also rebuild with the -c for clean, which just deletes the build
37directory.
37directory.
@@ -43,10 +43,10 @@ Running Unity 8 on your desktop
43run the Unity 8 shell
43run the Unity 8 shell
44---------------------
44---------------------
45$ cd ~/unity8/trunk
45$ cd ~/unity8/trunk
46−$ ./run
46+$ ./run.sh
47
47
48Options can be passed to test the lock screen
48Options can be passed to test the lock screen
49−$ ./run -p OR -k
49+$ ./run.sh -p OR -k
50
50
51-p is for pin lock, for which the default prompt answer is "1234"
51-p is for pin lock, for which the default prompt answer is "1234"
52-k is for keylock passphrase, for which the default prompt answer is "password"
52-k is for keylock passphrase, for which the default prompt answer is "password"
@@ -78,19 +78,19 @@ Running Unity 8 on devices
78 on the device yourself)
78 on the device yourself)
79
79
80$ cd ~/unity/trunk
80$ cd ~/unity/trunk
81−$ ./run_on_device --setup
81+$ ./run_on_device.sh --setup
82 this will:
82 this will:
83 - install your public SSH key on the device
83 - install your public SSH key on the device
84 - install the needed dependencies
84 - install the needed dependencies
85
85
86−$ ./run_on_device
86+$ ./run_on_device.sh
87 this will:
87 this will:
88 - rsync the code to the device
88 - rsync the code to the device
89 - build on the device
89 - build on the device
90 - replace the running shell
90 - replace the running shell
91
91
92Options can be passed to test the lock screen
92Options can be passed to test the lock screen
93−$ ./run_on_device -p OR -k
93+$ ./run_on_device.sh -p OR -k
94
94
95-p is for pin lock, for which the default prompt answer is "1234"
95-p is for pin lock, for which the default prompt answer is "1234"
96-k is for keylock passphrase, for which the default prompt answer is "password"
96-k is for keylock passphrase, for which the default prompt answer is "password"
@@ -107,9 +107,9 @@ Notes
107- exporting ANDROID_SERIAL=$your_device_serial or
107- exporting ANDROID_SERIAL=$your_device_serial or
108 ANDROID_SERIAL=$your_device_ip:5555 will make adb not complain about
108 ANDROID_SERIAL=$your_device_ip:5555 will make adb not complain about
109 multiple devices
109 multiple devices
110−- you can export TARGET_IP=$your_device_ip TARGET_SSH_PORT=22 for run_on_device
110+- you can export TARGET_IP=$your_device_ip TARGET_SSH_PORT=22 for run_on_device.sh
111 to not use adb forwarding - useful if you use multiple devices
111 to not use adb forwarding - useful if you use multiple devices
112−- using Ninja (package ninja-build - run_on_device -s installs this now)
112+- using Ninja (package ninja-build - run_on_device.sh -s installs this now)
113 will improve build times (especially in the nothing-to-build case)
113 will improve build times (especially in the nothing-to-build case)
114
114
115
115
@@ -131,7 +131,7 @@ Running tests
131=============
131=============
132
132
133Tests are run from the build directory (which will be ./builddir if you used
133Tests are run from the build directory (which will be ./builddir if you used
134−the ./build script).
134+the ./build.sh script).
135
135
136To run the tests that do not require any graphical capability and therefore
136To run the tests that do not require any graphical capability and therefore
137are pretty fast run:
137are pretty fast run:
@@ -171,7 +171,7 @@ Running autopilot tests
171=======================
171=======================
172
172
173Autopilot tests are run from the build directory (which will be ./builddir if you used
173Autopilot tests are run from the build directory (which will be ./builddir if you used
174−the ./build script).
174+the ./build.sh script).
175
175
176$ make autopilot
176$ make autopilot
177
177
build → build.shrenamed+1−2
@@ -43,13 +43,12 @@ install_dependencies() {
43 gsettings-desktop-schemas \
43 gsettings-desktop-schemas \
44 gsettings-ubuntu-schemas \
44 gsettings-ubuntu-schemas \
45 qmenumodel-qml \
45 qmenumodel-qml \
46− qtdeclarative5-dee-plugin \
46+ qml-module-qtquick-xmllistmodel \
47 qtdeclarative5-gsettings1.0 \
47 qtdeclarative5-gsettings1.0 \
48 qtdeclarative5-ubuntu-ui-toolkit-plugin \
48 qtdeclarative5-ubuntu-ui-toolkit-plugin \
49 qtdeclarative5-ubuntu-settings-components \
49 qtdeclarative5-ubuntu-settings-components \
50 qtdeclarative5-ubuntu-thumbnailer0.1 \
50 qtdeclarative5-ubuntu-thumbnailer0.1 \
51 unity-notifications-impl \
51 unity-notifications-impl \
52− qtdeclarative5-xmllistmodel-plugin \
53 ubuntu-mobile-icons \
52 ubuntu-mobile-icons \
54 unity-scope-home \
53 unity-scope-home \
55 unity-lens-applications \
54 unity-lens-applications \
debian/changelog+30
@@ -1,3 +1,33 @@
1+unity8 (7.86+14.10.20140505-0ubuntu1) utopic; urgency=low
2+
3+ [ Ted Gould ]
4+ * Provide a dbus interface for setting the count and countVisible
5+ properties. (LP: #1301400)
6+
7+ [ Michał Sawicz ]
8+ * Pass env variables to initctl start.
9+ * Suffix .sh to our scripts and clean up debian/rules.
10+ * Adapt to Debian Qt package renames and drop unneeded Dee plugin
11+ dependency.
12+
13+ [ Ying-Chun Liu ]
14+ * Add Zoomable Image for Preview widgets.
15+
16+ [ Albert Astals ]
17+ * Remove support for Qt <= 5.2.1
18+
19+ [ Mirco Müller ]
20+ * Implemented feature-request from Design for modal snap-decision
21+ notifications on the phone. See LP #1285712 (LP: #1285712)
22+
23+ [ Andrea Cimitan ]
24+ * Make progressbas in preview widget big as the button
25+
26+ [ CI bot ]
27+ * Resync trunk
28+
29+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 05 May 2014 12:09:43 +0000
30+
1unity8 (7.86+14.10.20140502.6-0ubuntu1) utopic; urgency=low
31unity8 (7.86+14.10.20140502.6-0ubuntu1) utopic; urgency=low
2
32
3 [ tpeeters ]
33 [ tpeeters ]
debian/control+9−10
@@ -27,19 +27,19 @@ Build-Depends: cmake,
27 python3-all:any,
27 python3-all:any,
28 python3-setuptools,
28 python3-setuptools,
29 python:any (>= 2.7),
29 python:any (>= 2.7),
30+ qml-module-qtquick-xmllistmodel,
31+ qml-module-qtquick2,
32+ qml-module-qttest,
30 qt5-default,
33 qt5-default,
31− qtbase5-dev,
34+ qtbase5-dev (>= 5.2.1),
32 qtbase5-dev-tools,
35 qtbase5-dev-tools,
33− qtbase5-private-dev,
36+ qtbase5-private-dev (>= 5.2.1),
34− qtdeclarative5-dev,
37+ qtdeclarative5-dev (>= 5.2.1),
35 qtdeclarative5-dev-tools,
38 qtdeclarative5-dev-tools,
36− qtdeclarative5-private-dev,
39+ qtdeclarative5-private-dev (>= 5.2.1),
37 qtdeclarative5-qtmultimedia-plugin,
40 qtdeclarative5-qtmultimedia-plugin,
38− qtdeclarative5-qtquick2-plugin,
39− qtdeclarative5-test-plugin,
40 qtdeclarative5-ubuntu-settings-components,
41 qtdeclarative5-ubuntu-settings-components,
41 qtdeclarative5-ubuntu-ui-toolkit-plugin,
42 qtdeclarative5-ubuntu-ui-toolkit-plugin,
42− qtdeclarative5-xmllistmodel-plugin,
43 ttf-ubuntu-font-family,
43 ttf-ubuntu-font-family,
44Standards-Version: 3.9.4
44Standards-Version: 3.9.4
45Homepage: http://launchpad.net/unity
45Homepage: http://launchpad.net/unity
@@ -77,10 +77,9 @@ Depends: gsettings-desktop-schemas,
77 libglib2.0-bin,
77 libglib2.0-bin,
78 libunity-mir1 (>= 0.4),
78 libunity-mir1 (>= 0.4),
79 qmenumodel-qml (>= 0.2.7),
79 qmenumodel-qml (>= 0.2.7),
80− qtdeclarative5-dee-plugin,
80+ qml-module-qtquick-xmllistmodel,
81 qtdeclarative5-gsettings1.0,
81 qtdeclarative5-gsettings1.0,
82 qtdeclarative5-ubuntu-settings-components,
82 qtdeclarative5-ubuntu-settings-components,
83− qtdeclarative5-xmllistmodel-plugin,
84 unity-greeter-session-broadcast,
83 unity-greeter-session-broadcast,
85 unity-launcher-impl-3,
84 unity-launcher-impl-3,
86 unity8-common (= ${source:Version}),
85 unity8-common (= ${source:Version}),
@@ -117,7 +116,7 @@ Depends: qtdeclarative5-ubuntu-thumbnailer0.1 | ubuntu-thumbnailer-impl,
117 qtdeclarative5-unity-notifications-plugin | unity-notifications-impl,
116 qtdeclarative5-unity-notifications-plugin | unity-notifications-impl,
118 ubuntu-thumbnailer-impl-0,
117 ubuntu-thumbnailer-impl-0,
119 unity-application-impl-2,
118 unity-application-impl-2,
120− unity-notifications-impl-2,
119+ unity-notifications-impl-3,
121 unity-plugin-scopes | unity-scopes-impl,
120 unity-plugin-scopes | unity-scopes-impl,
122 unity-scopes-impl-0,
121 unity-scopes-impl-0,
123 unity8-fake-env | unity-application-impl,
122 unity8-fake-env | unity-application-impl,
debian/rules+1−2
@@ -6,8 +6,7 @@
6export DPKG_GENSYMBOLS_CHECK_LEVEL=4
6export DPKG_GENSYMBOLS_CHECK_LEVEL=4
7export NO_PNG_PKG_MANGLE=1
7export NO_PNG_PKG_MANGLE=1
8
8
9−.PHONY: build
10−build %:
9+%:
11 dh $@ --parallel --fail-missing --with python2,python3
10 dh $@ --parallel --fail-missing --with python2,python3
12
11
13override_dh_auto_clean:
12override_dh_auto_clean:
plugins/DashViews/abstractdashview.cpp−34
@@ -46,17 +46,10 @@ void AbstractDashView::setModel(QAbstractItemModel *model)
46 if (!m_delegateModel) {
46 if (!m_delegateModel) {
47 createDelegateModel();
47 createDelegateModel();
48 } else {
48 } else {
49−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
50− disconnect(m_delegateModel, SIGNAL(modelUpdated(QQuickChangeSet,bool)), this, SLOT(onModelUpdated(QQuickChangeSet,bool)));
51− }
52− m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
53− connect(m_delegateModel, SIGNAL(modelUpdated(QQuickChangeSet,bool)), this, SLOT(onModelUpdated(QQuickChangeSet,bool)));
54−#else
55 disconnect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
49 disconnect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
56 }
50 }
57 m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
51 m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
58 connect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
52 connect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
59−#endif
60
53
61 cleanupExistingItems();
54 cleanupExistingItems();
62
55
@@ -181,13 +174,8 @@ void AbstractDashView::resetDelegateCreationEnd()
181
174
182void AbstractDashView::createDelegateModel()
175void AbstractDashView::createDelegateModel()
183{
176{
184−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
185− m_delegateModel = new QQuickVisualDataModel(qmlContext(this), this);
186− connect(m_delegateModel, SIGNAL(createdItem(int,QQuickItem*)), this, SLOT(itemCreated(int,QQuickItem*)));
187−#else
188 m_delegateModel = new QQmlDelegateModel(qmlContext(this), this);
177 m_delegateModel = new QQmlDelegateModel(qmlContext(this), this);
189 connect(m_delegateModel, SIGNAL(createdItem(int,QObject*)), this, SLOT(itemCreated(int,QObject*)));
178 connect(m_delegateModel, SIGNAL(createdItem(int,QObject*)), this, SLOT(itemCreated(int,QObject*)));
190−#endif
191 if (isComponentComplete())
179 if (isComponentComplete())
192 m_delegateModel->componentComplete();
180 m_delegateModel->componentComplete();
193}
181}
@@ -253,16 +241,9 @@ QQuickItem *AbstractDashView::createItem(int modelIndex, bool asynchronous)
253 return nullptr;
241 return nullptr;
254
242
255 m_asyncRequestedIndex = -1;
243 m_asyncRequestedIndex = -1;
256−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
257− QQuickItem *item = m_delegateModel->item(modelIndex, asynchronous);
258−#else
259 QObject* object = m_delegateModel->object(modelIndex, asynchronous);
244 QObject* object = m_delegateModel->object(modelIndex, asynchronous);
260 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
245 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
261−#endif
262 if (!item) {
246 if (!item) {
263−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
264− m_asyncRequestedIndex = modelIndex;
265−#else
266 if (object) {
247 if (object) {
267 m_delegateModel->release(object);
248 m_delegateModel->release(object);
268 if (!m_delegateValidated) {
249 if (!m_delegateValidated) {
@@ -273,7 +254,6 @@ QQuickItem *AbstractDashView::createItem(int modelIndex, bool asynchronous)
273 } else {
254 } else {
274 m_asyncRequestedIndex = modelIndex;
255 m_asyncRequestedIndex = modelIndex;
275 }
256 }
276−#endif
277 return nullptr;
257 return nullptr;
278 } else {
258 } else {
279 addItemToView(modelIndex, item);
259 addItemToView(modelIndex, item);
@@ -283,13 +263,8 @@ QQuickItem *AbstractDashView::createItem(int modelIndex, bool asynchronous)
283
263
284void AbstractDashView::releaseItem(QQuickItem *item)
264void AbstractDashView::releaseItem(QQuickItem *item)
285{
265{
286−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
287− QQuickVisualModel::ReleaseFlags flags = m_delegateModel->release(item);
288− if (flags & QQuickVisualModel::Destroyed) {
289−#else
290 QQmlDelegateModel::ReleaseFlags flags = m_delegateModel->release(item);
266 QQmlDelegateModel::ReleaseFlags flags = m_delegateModel->release(item);
291 if (flags & QQmlDelegateModel::Destroyed) {
267 if (flags & QQmlDelegateModel::Destroyed) {
292−#endif
293 item->setParentItem(nullptr);
268 item->setParentItem(nullptr);
294 }
269 }
295}
270}
@@ -299,10 +274,6 @@ void AbstractDashView::setImplicitHeightDirty()
299 m_implicitHeightDirty = true;
274 m_implicitHeightDirty = true;
300}
275}
301
276
302−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
303−void AbstractDashView::itemCreated(int modelIndex, QQuickItem *item)
304−{
305−#else
306void AbstractDashView::itemCreated(int modelIndex, QObject *object)
277void AbstractDashView::itemCreated(int modelIndex, QObject *object)
307{
278{
308 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
279 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
@@ -310,7 +281,6 @@ void AbstractDashView::itemCreated(int modelIndex, QObject *object)
310 qWarning() << "AbstractDashView::itemCreated got a non item for index" << modelIndex;
281 qWarning() << "AbstractDashView::itemCreated got a non item for index" << modelIndex;
311 return;
282 return;
312 }
283 }
313−#endif
314 item->setParentItem(this);
284 item->setParentItem(this);
315
285
316 // We only need to call createItem if we are here because of an asynchronous generation
286 // We only need to call createItem if we are here because of an asynchronous generation
@@ -325,11 +295,7 @@ void AbstractDashView::itemCreated(int modelIndex, QObject *object)
325 }
295 }
326}
296}
327
297
328−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
329−void AbstractDashView::onModelUpdated(const QQuickChangeSet &changeSet, bool reset)
330−#else
331void AbstractDashView::onModelUpdated(const QQmlChangeSet &changeSet, bool reset)
298void AbstractDashView::onModelUpdated(const QQmlChangeSet &changeSet, bool reset)
332−#endif
333{
299{
334 if (reset) {
300 if (reset) {
335 cleanupExistingItems();
301 cleanupExistingItems();
plugins/DashViews/abstractdashview.h−17
@@ -23,12 +23,8 @@ class QAbstractItemModel;
23class QQmlComponent;
23class QQmlComponent;
24#pragma GCC diagnostic push
24#pragma GCC diagnostic push
25#pragma GCC diagnostic ignored "-pedantic"
25#pragma GCC diagnostic ignored "-pedantic"
26−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
27−#include <private/qquickvisualdatamodel_p.h>
28−#else
29#include <private/qqmldelegatemodel_p.h>
26#include <private/qqmldelegatemodel_p.h>
30#include <qqmlinfo.h>
27#include <qqmlinfo.h>
31−#endif
32#pragma GCC diagnostic pop
28#pragma GCC diagnostic pop
33
29
34class AbstractDashView : public QQuickItem
30class AbstractDashView : public QQuickItem
@@ -94,13 +90,8 @@ protected:
94 void setImplicitHeightDirty();
90 void setImplicitHeightDirty();
95
91
96private Q_SLOTS:
92private Q_SLOTS:
97−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
98− void itemCreated(int modelIndex, QQuickItem *item);
99− void onModelUpdated(const QQuickChangeSet &changeSet, bool reset);
100−#else
101 void itemCreated(int modelIndex, QObject *object);
93 void itemCreated(int modelIndex, QObject *object);
102 void onModelUpdated(const QQmlChangeSet &changeSet, bool reset);
94 void onModelUpdated(const QQmlChangeSet &changeSet, bool reset);
103−#endif
104 void onHeightChanged();
95 void onHeightChanged();
105
96
106private:
97private:
@@ -117,17 +108,9 @@ private:
117 virtual void doRelayout() = 0;
108 virtual void doRelayout() = 0;
118 virtual void updateItemCulling(qreal visibleFromY, qreal visibleToY) = 0;
109 virtual void updateItemCulling(qreal visibleFromY, qreal visibleToY) = 0;
119 virtual void calculateImplicitHeight() = 0;
110 virtual void calculateImplicitHeight() = 0;
120−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
121− virtual void processModelRemoves(const QVector<QQuickChangeSet::Remove> &removes) = 0;
122−#else
123 virtual void processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes) = 0;
111 virtual void processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes) = 0;
124−#endif
125
112
126−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
127− QQuickVisualDataModel *m_delegateModel;
128−#else
129 QQmlDelegateModel *m_delegateModel;
113 QQmlDelegateModel *m_delegateModel;
130−#endif
131
114
132 // Index we are waiting because we requested it asynchronously
115 // Index we are waiting because we requested it asynchronously
133 int m_asyncRequestedIndex;
116 int m_asyncRequestedIndex;
plugins/DashViews/horizontaljournal.cpp−12
@@ -28,12 +28,8 @@
28#include <qqmlengine.h>
28#include <qqmlengine.h>
29#pragma GCC diagnostic push
29#pragma GCC diagnostic push
30#pragma GCC diagnostic ignored "-pedantic"
30#pragma GCC diagnostic ignored "-pedantic"
31−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
32−#include <private/qquickvisualdatamodel_p.h>
33−#else
34#include <private/qqmldelegatemodel_p.h>
31#include <private/qqmldelegatemodel_p.h>
35#include <qqmlinfo.h>
32#include <qqmlinfo.h>
36−#endif
37#include <private/qquickitem_p.h>
33#include <private/qquickitem_p.h>
38#pragma GCC diagnostic pop
34#pragma GCC diagnostic pop
39
35
@@ -188,17 +184,9 @@ void HorizontalJournal::calculateImplicitHeight()
188 }
184 }
189}
185}
190
186
191−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
192−void HorizontalJournal::processModelRemoves(const QVector<QQuickChangeSet::Remove> &removes)
193−#else
194void HorizontalJournal::processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes)
187void HorizontalJournal::processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes)
195−#endif
196{
188{
197−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
198− Q_FOREACH(const QQuickChangeSet::Remove &remove, removes) {
199−#else
200 Q_FOREACH(const QQmlChangeSet::Remove &remove, removes) {
189 Q_FOREACH(const QQmlChangeSet::Remove &remove, removes) {
201−#endif
202 for (int i = remove.count - 1; i >= 0; --i) {
190 for (int i = remove.count - 1; i >= 0; --i) {
203 const int indexToRemove = remove.index + i;
191 const int indexToRemove = remove.index + i;
204 // We only support removing from the end so
192 // We only support removing from the end so
plugins/DashViews/horizontaljournal.h−4
@@ -52,11 +52,7 @@ private:
52 void calculateImplicitHeight() override;
52 void calculateImplicitHeight() override;
53 void doRelayout() override;
53 void doRelayout() override;
54 void updateItemCulling(qreal visibleFromY, qreal visibleToY) override;
54 void updateItemCulling(qreal visibleFromY, qreal visibleToY) override;
55−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
56− void processModelRemoves(const QVector<QQuickChangeSet::Remove> &removes) override;
57−#else
58 void processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes) override;
55 void processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes) override;
59−#endif
60
56
61 int m_firstVisibleIndex;
57 int m_firstVisibleIndex;
62 QList<QQuickItem*> m_visibleItems;
58 QList<QQuickItem*> m_visibleItems;
plugins/DashViews/listviewwithpageheader.cpp−50
@@ -97,11 +97,7 @@
97#include <qqmlengine.h>
97#include <qqmlengine.h>
98#pragma GCC diagnostic push
98#pragma GCC diagnostic push
99#pragma GCC diagnostic ignored "-pedantic"
99#pragma GCC diagnostic ignored "-pedantic"
100−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
101−#include <private/qquickvisualdatamodel_p.h>
102−#else
103#include <private/qqmldelegatemodel_p.h>
100#include <private/qqmldelegatemodel_p.h>
104−#endif
105#include <private/qqmlglobal_p.h>
101#include <private/qqmlglobal_p.h>
106#include <private/qquickitem_p.h>
102#include <private/qquickitem_p.h>
107#include <private/qquickanimation_p.h>
103#include <private/qquickanimation_p.h>
@@ -191,17 +187,10 @@ void ListViewWithPageHeader::setModel(QAbstractItemModel *model)
191 if (!m_delegateModel) {
187 if (!m_delegateModel) {
192 createDelegateModel();
188 createDelegateModel();
193 } else {
189 } else {
194−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
195− disconnect(m_delegateModel, SIGNAL(modelUpdated(QQuickChangeSet,bool)), this, SLOT(onModelUpdated(QQuickChangeSet,bool)));
196− }
197− m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
198− connect(m_delegateModel, SIGNAL(modelUpdated(QQuickChangeSet,bool)), this, SLOT(onModelUpdated(QQuickChangeSet,bool)));
199−#else
200 disconnect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
190 disconnect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
201 }
191 }
202 m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
192 m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
203 connect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
193 connect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
204−#endif
205 Q_EMIT modelChanged();
194 Q_EMIT modelChanged();
206 polish();
195 polish();
207 // TODO?
196 // TODO?
@@ -570,13 +559,8 @@ void ListViewWithPageHeader::viewportMoved(Qt::Orientations orient)
570
559
571void ListViewWithPageHeader::createDelegateModel()
560void ListViewWithPageHeader::createDelegateModel()
572{
561{
573−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
574− m_delegateModel = new QQuickVisualDataModel(qmlContext(this), this);
575− connect(m_delegateModel, SIGNAL(createdItem(int,QQuickItem*)), this, SLOT(itemCreated(int,QQuickItem*)));
576−#else
577 m_delegateModel = new QQmlDelegateModel(qmlContext(this), this);
562 m_delegateModel = new QQmlDelegateModel(qmlContext(this), this);
578 connect(m_delegateModel, SIGNAL(createdItem(int,QObject*)), this, SLOT(itemCreated(int,QObject*)));
563 connect(m_delegateModel, SIGNAL(createdItem(int,QObject*)), this, SLOT(itemCreated(int,QObject*)));
579−#endif
580 if (isComponentComplete())
564 if (isComponentComplete())
581 m_delegateModel->componentComplete();
565 m_delegateModel->componentComplete();
582 updateWatchedRoles();
566 updateWatchedRoles();
@@ -657,13 +641,8 @@ bool ListViewWithPageHeader::addVisibleItems(qreal fillFrom, qreal fillTo, bool
657void ListViewWithPageHeader::reallyReleaseItem(ListItem *listItem)
641void ListViewWithPageHeader::reallyReleaseItem(ListItem *listItem)
658{
642{
659 QQuickItem *item = listItem->m_item;
643 QQuickItem *item = listItem->m_item;
660−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
661− QQuickVisualModel::ReleaseFlags flags = m_delegateModel->release(item);
662− if (flags & QQuickVisualModel::Destroyed) {
663−#else
664 QQmlDelegateModel::ReleaseFlags flags = m_delegateModel->release(item);
644 QQmlDelegateModel::ReleaseFlags flags = m_delegateModel->release(item);
665 if (flags & QQmlDelegateModel::Destroyed) {
645 if (flags & QQmlDelegateModel::Destroyed) {
666−#endif
667 item->setParentItem(nullptr);
646 item->setParentItem(nullptr);
668 }
647 }
669 delete listItem->m_sectionItem;
648 delete listItem->m_sectionItem;
@@ -796,16 +775,9 @@ ListViewWithPageHeader::ListItem *ListViewWithPageHeader::createItem(int modelIn
796 return nullptr;
775 return nullptr;
797
776
798 m_asyncRequestedIndex = -1;
777 m_asyncRequestedIndex = -1;
799−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
800− QQuickItem *item = m_delegateModel->item(modelIndex, asynchronous);
801−#else
802 QObject* object = m_delegateModel->object(modelIndex, asynchronous);
778 QObject* object = m_delegateModel->object(modelIndex, asynchronous);
803 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
779 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
804−#endif
805 if (!item) {
780 if (!item) {
806−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
807− m_asyncRequestedIndex = modelIndex;
808−#else
809 if (object) {
781 if (object) {
810 m_delegateModel->release(object);
782 m_delegateModel->release(object);
811 if (!m_delegateValidated) {
783 if (!m_delegateValidated) {
@@ -816,7 +788,6 @@ ListViewWithPageHeader::ListItem *ListViewWithPageHeader::createItem(int modelIn
816 } else {
788 } else {
817 m_asyncRequestedIndex = modelIndex;
789 m_asyncRequestedIndex = modelIndex;
818 }
790 }
819−#endif
820 return 0;
791 return 0;
821 } else {
792 } else {
822// qDebug() << "ListViewWithPageHeader::createItem::We have the item" << modelIndex << item;
793// qDebug() << "ListViewWithPageHeader::createItem::We have the item" << modelIndex << item;
@@ -872,10 +843,6 @@ ListViewWithPageHeader::ListItem *ListViewWithPageHeader::createItem(int modelIn
872 }
843 }
873}
844}
874
845
875−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
876−void ListViewWithPageHeader::itemCreated(int modelIndex, QQuickItem *item)
877−{
878−#else
879void ListViewWithPageHeader::itemCreated(int modelIndex, QObject *object)
846void ListViewWithPageHeader::itemCreated(int modelIndex, QObject *object)
880{
847{
881 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
848 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
@@ -883,7 +850,6 @@ void ListViewWithPageHeader::itemCreated(int modelIndex, QObject *object)
883 qWarning() << "ListViewWithPageHeader::itemCreated got a non item for index" << modelIndex;
850 qWarning() << "ListViewWithPageHeader::itemCreated got a non item for index" << modelIndex;
884 return;
851 return;
885 }
852 }
886−#endif
887// qDebug() << "ListViewWithPageHeader::itemCreated" << modelIndex << item;
853// qDebug() << "ListViewWithPageHeader::itemCreated" << modelIndex << item;
888 // Check we are not being taken down and don't paint anything
854 // Check we are not being taken down and don't paint anything
889 // TODO Check if we still need this in 5.2
855 // TODO Check if we still need this in 5.2
@@ -924,21 +890,13 @@ void ListViewWithPageHeader::onHeightChanged()
924}
890}
925
891
926
892
927−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
928−void ListViewWithPageHeader::onModelUpdated(const QQuickChangeSet &changeSet, bool /*reset*/)
929−#else
930void ListViewWithPageHeader::onModelUpdated(const QQmlChangeSet &changeSet, bool /*reset*/)
893void ListViewWithPageHeader::onModelUpdated(const QQmlChangeSet &changeSet, bool /*reset*/)
931−#endif
932{
894{
933 // TODO Do something with reset
895 // TODO Do something with reset
934// qDebug() << "ListViewWithPageHeader::onModelUpdated" << changeSet << reset;
896// qDebug() << "ListViewWithPageHeader::onModelUpdated" << changeSet << reset;
935 const auto oldFirstVisibleIndex = m_firstVisibleIndex;
897 const auto oldFirstVisibleIndex = m_firstVisibleIndex;
936
898
937−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
938− Q_FOREACH(const QQuickChangeSet::Remove &remove, changeSet.removes()) {
939−#else
940 Q_FOREACH(const QQmlChangeSet::Remove &remove, changeSet.removes()) {
899 Q_FOREACH(const QQmlChangeSet::Remove &remove, changeSet.removes()) {
941−#endif
942// qDebug() << "ListViewWithPageHeader::onModelUpdated Remove" << remove.index << remove.count;
900// qDebug() << "ListViewWithPageHeader::onModelUpdated Remove" << remove.index << remove.count;
943 if (remove.index + remove.count > m_firstVisibleIndex && remove.index < m_firstVisibleIndex + m_visibleItems.count()) {
901 if (remove.index + remove.count > m_firstVisibleIndex && remove.index < m_firstVisibleIndex + m_visibleItems.count()) {
944 const qreal oldFirstValidIndexPos = m_visibleItems.first()->y();
902 const qreal oldFirstValidIndexPos = m_visibleItems.first()->y();
@@ -992,11 +950,7 @@ void ListViewWithPageHeader::onModelUpdated(const QQmlChangeSet &changeSet, bool
992 }
950 }
993 }
951 }
994
952
995−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
996− Q_FOREACH(const QQuickChangeSet::Insert &insert, changeSet.inserts()) {
997−#else
998 Q_FOREACH(const QQmlChangeSet::Insert &insert, changeSet.inserts()) {
953 Q_FOREACH(const QQmlChangeSet::Insert &insert, changeSet.inserts()) {
999−#endif
1000// qDebug() << "ListViewWithPageHeader::onModelUpdated Insert" << insert.index << insert.count;
954// qDebug() << "ListViewWithPageHeader::onModelUpdated Insert" << insert.index << insert.count;
1001 const bool insertingInValidIndexes = insert.index > m_firstVisibleIndex && insert.index < m_firstVisibleIndex + m_visibleItems.count();
955 const bool insertingInValidIndexes = insert.index > m_firstVisibleIndex && insert.index < m_firstVisibleIndex + m_visibleItems.count();
1002 const bool firstItemWithViewOnTop = insert.index == 0 && m_firstVisibleIndex == 0 && m_visibleItems.first()->y() + m_clipItem->y() > contentY();
956 const bool firstItemWithViewOnTop = insert.index == 0 && m_firstVisibleIndex == 0 && m_visibleItems.first()->y() + m_clipItem->y() > contentY();
@@ -1054,11 +1008,7 @@ void ListViewWithPageHeader::onModelUpdated(const QQmlChangeSet &changeSet, bool
1054 }
1008 }
1055 }
1009 }
1056
1010
1057−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
1058− Q_FOREACH(const QQuickChangeSet::Change &change, changeSet.changes()) {
1059−#else
1060 Q_FOREACH(const QQmlChangeSet::Change &change, changeSet.changes()) {
1011 Q_FOREACH(const QQmlChangeSet::Change &change, changeSet.changes()) {
1061−#endif
1062// qDebug() << "ListViewWithPageHeader::onModelUpdated Change" << change.index << change.count;
1012// qDebug() << "ListViewWithPageHeader::onModelUpdated Change" << change.index << change.count;
1063 for (int i = change.index; i < change.count; ++i) {
1013 for (int i = change.index; i < change.count; ++i) {
1064 ListItem *item = itemAtIndex(i);
1014 ListItem *item = itemAtIndex(i);
plugins/DashViews/listviewwithpageheader.h−20
@@ -17,21 +17,13 @@
17#ifndef LISTVIEWWITHPAGEHEADER_H
17#ifndef LISTVIEWWITHPAGEHEADER_H
18#define LISTVIEWWITHPAGEHEADER_H
18#define LISTVIEWWITHPAGEHEADER_H
19
19
20−#pragma GCC diagnostic push
21−#pragma GCC diagnostic ignored "-pedantic"
22#include <private/qquickitemchangelistener_p.h>
20#include <private/qquickitemchangelistener_p.h>
23#include <private/qquickflickable_p.h>
21#include <private/qquickflickable_p.h>
24−#pragma GCC diagnostic pop
25
22
26class QAbstractItemModel;
23class QAbstractItemModel;
27class QQuickNumberAnimation;
24class QQuickNumberAnimation;
28−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
29−class QQuickChangeSet;
30−class QQuickVisualDataModel;
31−#else
32class QQmlChangeSet;
25class QQmlChangeSet;
33class QQmlDelegateModel;
26class QQmlDelegateModel;
34−#endif
35
27
36
28
37/**
29/**
@@ -117,19 +109,11 @@ protected:
117 void updatePolish();
109 void updatePolish();
118
110
119private Q_SLOTS:
111private Q_SLOTS:
120−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
121− void itemCreated(int modelIndex, QQuickItem *item);
122−#else
123 void itemCreated(int modelIndex, QObject *object);
112 void itemCreated(int modelIndex, QObject *object);
124−#endif
125 void onContentHeightChanged();
113 void onContentHeightChanged();
126 void onContentWidthChanged();
114 void onContentWidthChanged();
127 void onHeightChanged();
115 void onHeightChanged();
128−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
129− void onModelUpdated(const QQuickChangeSet &changeSet, bool reset);
130−#else
131 void onModelUpdated(const QQmlChangeSet &changeSet, bool reset);
116 void onModelUpdated(const QQmlChangeSet &changeSet, bool reset);
132−#endif
133 void onShowHeaderAnimationFinished();
117 void onShowHeaderAnimationFinished();
134
118
135private:
119private:
@@ -168,11 +152,7 @@ private:
168 QQuickItem *getSectionItem(int modelIndex, bool alreadyInserted);
152 QQuickItem *getSectionItem(int modelIndex, bool alreadyInserted);
169 QQuickItem *getSectionItem(const QString &sectionText);
153 QQuickItem *getSectionItem(const QString &sectionText);
170
154
171−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
172− QQuickVisualDataModel *m_delegateModel;
173−#else
174 QQmlDelegateModel *m_delegateModel;
155 QQmlDelegateModel *m_delegateModel;
175−#endif
176
156
177 // Index we are waiting because we requested it asynchronously
157 // Index we are waiting because we requested it asynchronously
178 int m_asyncRequestedIndex;
158 int m_asyncRequestedIndex;
plugins/DashViews/organicgrid.cpp−8
@@ -237,17 +237,9 @@ void OrganicGrid::calculateImplicitHeight()
237 }
237 }
238}
238}
239
239
240−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
241−void OrganicGrid::processModelRemoves(const QVector<QQuickChangeSet::Remove> &removes)
242−#else
243void OrganicGrid::processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes)
240void OrganicGrid::processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes)
244−#endif
245{
241{
246−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
247− Q_FOREACH(const QQuickChangeSet::Remove &remove, removes) {
248−#else
249 Q_FOREACH(const QQmlChangeSet::Remove &remove, removes) {
242 Q_FOREACH(const QQmlChangeSet::Remove &remove, removes) {
250−#endif
251 for (int i = remove.count - 1; i >= 0; --i) {
243 for (int i = remove.count - 1; i >= 0; --i) {
252 const int indexToRemove = remove.index + i;
244 const int indexToRemove = remove.index + i;
253 // We only support removing from the end
245 // We only support removing from the end
plugins/DashViews/organicgrid.h−4
@@ -79,11 +79,7 @@ private:
79 void doRelayout() override;
79 void doRelayout() override;
80 void updateItemCulling(qreal visibleFromY, qreal visibleToY) override;
80 void updateItemCulling(qreal visibleFromY, qreal visibleToY) override;
81 void calculateImplicitHeight() override;
81 void calculateImplicitHeight() override;
82−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
83− void processModelRemoves(const QVector<QQuickChangeSet::Remove> &removes) override;
84−#else
85 void processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes) override;
82 void processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes) override;
86−#endif
87
83
88 QSizeF m_smallDelegateSize;
84 QSizeF m_smallDelegateSize;
89 QSizeF m_bigDelegateSize;
85 QSizeF m_bigDelegateSize;
plugins/DashViews/verticaljournal.cpp−8
@@ -239,17 +239,9 @@ void VerticalJournal::updateItemCulling(qreal visibleFromY, qreal visibleToY)
239 }
239 }
240}
240}
241
241
242−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
243−void VerticalJournal::processModelRemoves(const QVector<QQuickChangeSet::Remove> &removes)
244−#else
245void VerticalJournal::processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes)
242void VerticalJournal::processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes)
246−#endif
247{
243{
248−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
249− Q_FOREACH(const QQuickChangeSet::Remove &remove, removes) {
250−#else
251 Q_FOREACH(const QQmlChangeSet::Remove &remove, removes) {
244 Q_FOREACH(const QQmlChangeSet::Remove &remove, removes) {
252−#endif
253 for (int i = remove.count - 1; i >= 0; --i) {
245 for (int i = remove.count - 1; i >= 0; --i) {
254 const int indexToRemove = remove.index + i;
246 const int indexToRemove = remove.index + i;
255 // Since we only support removing from the end, indexToRemove
247 // Since we only support removing from the end, indexToRemove
plugins/DashViews/verticaljournal.h−4
@@ -90,11 +90,7 @@ private:
90 void calculateImplicitHeight() override;
90 void calculateImplicitHeight() override;
91 void doRelayout() override;
91 void doRelayout() override;
92 void updateItemCulling(qreal visibleFromY, qreal visibleToY) override;
92 void updateItemCulling(qreal visibleFromY, qreal visibleToY) override;
93−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
94− void processModelRemoves(const QVector<QQuickChangeSet::Remove> &removes) override;
95−#else
96 void processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes) override;
93 void processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes) override;
97−#endif
98
94
99 QVector<QList<ViewItem>> m_columnVisibleItems;
95 QVector<QList<ViewItem>> m_columnVisibleItems;
100 QHash<int, int> m_indexColumnMap;
96 QHash<int, int> m_indexColumnMap;
plugins/Unity/Launcher/backend/launcherbackend.cpp+266−16
@@ -34,10 +34,12 @@ public:
34 QString desktopFile;
34 QString desktopFile;
35 QString displayName;
35 QString displayName;
36 QString icon;
36 QString icon;
37+ int count;
38+ bool countVisible;
37};
39};
38
40
39LauncherBackend::LauncherBackend(QObject *parent):
41LauncherBackend::LauncherBackend(QObject *parent):
40− QObject(parent),
42+ QDBusVirtualObject(parent),
41 m_accounts(nullptr)
43 m_accounts(nullptr)
42{
44{
43#ifndef LAUNCHER_TESTING
45#ifndef LAUNCHER_TESTING
@@ -45,10 +47,25 @@ LauncherBackend::LauncherBackend(QObject *parent):
45#endif
47#endif
46 m_user = qgetenv("USER");
48 m_user = qgetenv("USER");
47 syncFromAccounts();
49 syncFromAccounts();
50+
51+ /* Set up ourselves on DBus */
52+ QDBusConnection con = QDBusConnection::sessionBus();
53+ if (!con.registerService("com.canonical.Unity.Launcher")) {
54+ qDebug() << "Unable to register launcher name";
55+ }
56+ if (!con.registerVirtualObject("/com/canonical/Unity/Launcher", this, QDBusConnection::VirtualObjectRegisterOption::SubPath)) {
57+ qDebug() << "Unable to register launcher object";
58+ }
48}
59}
49
60
50LauncherBackend::~LauncherBackend()
61LauncherBackend::~LauncherBackend()
51{
62{
63+ /* Remove oursevles from DBus */
64+ QDBusConnection con = QDBusConnection::sessionBus();
65+ con.unregisterService("com.canonical.Unity.Launcher");
66+ con.unregisterObject("/com/canonical/Unity/Launcher");
67+
68+ /* Clear data */
52 m_storedApps.clear();
69 m_storedApps.clear();
53
70
54 Q_FOREACH(LauncherBackendItem *item, m_itemCache) {
71 Q_FOREACH(LauncherBackendItem *item, m_itemCache) {
@@ -90,7 +107,7 @@ void LauncherBackend::setStoredApplications(const QStringList &appIds)
90
107
91QString LauncherBackend::desktopFile(const QString &appId) const
108QString LauncherBackend::desktopFile(const QString &appId) const
92{
109{
93− LauncherBackendItem *item = m_itemCache.value(appId);
110+ LauncherBackendItem *item = m_itemCache.value(appId, nullptr);
94 if (item) {
111 if (item) {
95 return item->desktopFile;
112 return item->desktopFile;
96 }
113 }
@@ -100,7 +117,7 @@ QString LauncherBackend::desktopFile(const QString &appId) const
100
117
101QString LauncherBackend::displayName(const QString &appId) const
118QString LauncherBackend::displayName(const QString &appId) const
102{
119{
103− LauncherBackendItem *item = m_itemCache.value(appId);
120+ LauncherBackendItem *item = m_itemCache.value(appId, nullptr);
104 if (item) {
121 if (item) {
105 return item->displayName;
122 return item->displayName;
106 }
123 }
@@ -118,16 +135,9 @@ QString LauncherBackend::displayName(const QString &appId) const
118QString LauncherBackend::icon(const QString &appId) const
135QString LauncherBackend::icon(const QString &appId) const
119{
136{
120 QString iconName;
137 QString iconName;
121− LauncherBackendItem *item = m_itemCache.value(appId);
138+ LauncherBackendItem *item = getItem(appId);
122 if (item) {
139 if (item) {
123 iconName = item->icon;
140 iconName = item->icon;
124− } else {
125− QString df = findDesktopFile(appId);
126− if (!df.isEmpty()) {
127− LauncherBackendItem *item = parseDesktopFile(df);
128− m_itemCache.insert(appId, item);
129− iconName = item->icon;
130− }
131 }
141 }
132
142
133 return iconName;
143 return iconName;
@@ -153,10 +163,70 @@ int LauncherBackend::progress(const QString &appId) const
153
163
154int LauncherBackend::count(const QString &appId) const
164int LauncherBackend::count(const QString &appId) const
155{
165{
156− // TODO: Return value for count emblem.
166+ int count = -1;
157− // TODO: emit countChanged() when this value changes.
167+ LauncherBackendItem *item = getItem(appId);
158− Q_UNUSED(appId)
168+
169+ if (item) {
170+ if (item->countVisible) {
171+ count = item->count;
172+ }
173+ }
174+
175+ return count;
176+}
177+
178+void LauncherBackend::setCount(const QString &appId, int count) const
179+{
180+ LauncherBackendItem *item = getItem(appId);
181+
182+ bool emitchange = false;
183+ if (item) {
184+ emitchange = (item->count != count);
185+ item->count = count;
186+ }
187+
188+ if (emitchange) {
189+ /* TODO: This needs to use the accessor to handle the visibility
190+ correctly, but when we have the two properties we can just use
191+ the local value */
192+ Q_EMIT countChanged(appId, this->count(appId));
193+ QVariant vcount(item->count);
194+ emitPropChangedDbus(appId, "count", vcount);
195+ }
196+}
197+
198+bool LauncherBackend::countVisible(const QString &appId) const
199+{
200+ bool visible = false;
201+ LauncherBackendItem *item = getItem(appId);
202+
203+ if (item) {
204+ visible = item->countVisible;
205+ }
206+
159− return 0;
207+ return visible;
208+}
209+
210+void LauncherBackend::setCountVisible(const QString &appId, bool visible) const
211+{
212+ LauncherBackendItem *item = getItem(appId);
213+
214+ bool emitchange = false;
215+ if (item) {
216+ emitchange = (item->countVisible != visible);
217+ item->countVisible = visible;
218+ } else {
219+ qDebug() << "Unable to find:" << appId;
220+ }
221+
222+ if (emitchange) {
223+ /* TODO: Because we're using visible in determining the
224+ count we need to emit a count changed as well */
225+ Q_EMIT countChanged(appId, this->count(appId));
226+ Q_EMIT countVisibleChanged(appId, item->countVisible);
227+ QVariant vCountVisible(item->countVisible);
228+ emitPropChangedDbus(appId, "countVisible", vCountVisible);
229+ }
160}
230}
161
231
162void LauncherBackend::setUser(const QString &username)
232void LauncherBackend::setUser(const QString &username)
@@ -275,6 +345,35 @@ LauncherBackendItem* LauncherBackend::parseDesktopFile(const QString &desktopFil
275 } else {
345 } else {
276 item->icon = "image://theme/" + iconString;
346 item->icon = "image://theme/" + iconString;
277 }
347 }
348+
349+ /* TODO: These should be looked up in a cache somewhere */
350+ item->count = 0;
351+ item->countVisible = false;
352+
353+ return item;
354+}
355+
356+/* Gets an item, and tries to create a new one if we need it to */
357+LauncherBackendItem* LauncherBackend::getItem(const QString &appId) const
358+{
359+ LauncherBackendItem *item = m_itemCache.value(appId, nullptr);
360+ if (!item) {
361+ QString df = findDesktopFile(appId);
362+ if (!df.isEmpty()) {
363+ item = parseDesktopFile(df);
364+ if (item) {
365+ m_itemCache[appId] = item;
366+ } else {
367+ qWarning() << "Unable to parse desktop file for" << appId << "path" << df;
368+ }
369+ } else {
370+ qDebug() << "Unable to find desktop file for:" << appId;
371+ }
372+ }
373+
374+ if (!item)
375+ qWarning() << "Unable to find item for: " << appId;
376+
278 return item;
377 return item;
279}
378}
280
379
@@ -285,7 +384,7 @@ void LauncherBackend::loadFromVariant(const QVariantMap &details)
285 }
384 }
286 QString appId = details.value("id").toString();
385 QString appId = details.value("id").toString();
287
386
288− LauncherBackendItem *item = m_itemCache.value(appId);
387+ LauncherBackendItem *item = m_itemCache.value(appId, nullptr);
289 if (item) {
388 if (item) {
290 delete item;
389 delete item;
291 }
390 }
@@ -295,6 +394,8 @@ void LauncherBackend::loadFromVariant(const QVariantMap &details)
295 item->desktopFile = details.value("desktopFile").toString();
394 item->desktopFile = details.value("desktopFile").toString();
296 item->displayName = details.value("name").toString();
395 item->displayName = details.value("name").toString();
297 item->icon = details.value("icon").toString();
396 item->icon = details.value("icon").toString();
397+ item->count = details.value("count").toInt();
398+ item->countVisible = details.value("countVisible").toBool();
298
399
299 m_itemCache.insert(appId, item);
400 m_itemCache.insert(appId, item);
300 m_storedApps.append(appId);
401 m_storedApps.append(appId);
@@ -308,6 +409,8 @@ QVariantMap LauncherBackend::itemToVariant(const QString &appId) const
308 details.insert("name", item->displayName);
409 details.insert("name", item->displayName);
309 details.insert("icon", item->icon);
410 details.insert("icon", item->icon);
310 details.insert("desktopFile", item->desktopFile);
411 details.insert("desktopFile", item->desktopFile);
412+ details.insert("count", item->count);
413+ details.insert("countVisible", item->countVisible);
311 return details;
414 return details;
312}
415}
313
416
@@ -318,3 +421,150 @@ bool LauncherBackend::isDefaultsItem(const QList<QVariantMap> &apps) const
318 // list of one item with the 'defaults' field set to true.
421 // list of one item with the 'defaults' field set to true.
319 return (apps.size() == 1 && apps[0].value("defaults").toBool());
422 return (apps.size() == 1 && apps[0].value("defaults").toBool());
320}
423}
424+
425+bool LauncherBackend::handleMessage(const QDBusMessage& message, const QDBusConnection& connection)
426+{
427+ /* Check to make sure we're getting properties on our interface */
428+ if (message.type() != QDBusMessage::MessageType::MethodCallMessage) {
429+ return false;
430+ }
431+ if (message.interface() != "org.freedesktop.DBus.Properties") {
432+ return false;
433+ }
434+ if (message.arguments()[0].toString() != "com.canonical.Unity.Launcher.Item") {
435+ return false;
436+ }
437+
438+ /* Break down the path to just the app id */
439+ QString pathtemp = message.path();
440+ if (!pathtemp.startsWith("/com/canonical/Unity/Launcher/")) {
441+ return false;
442+ }
443+ pathtemp.remove("/com/canonical/Unity/Launcher/");
444+ if (pathtemp.indexOf('/') >= 0) {
445+ return false;
446+ }
447+
448+ /* Find ourselves an appid */
449+ QString appid = decodeAppId(pathtemp);
450+ QVariantList retval;
451+
452+ if (message.member() == "Get") {
453+ if (message.arguments()[1].toString() == "count") {
454+ retval.append(QVariant::fromValue(QDBusVariant(this->count(appid))));
455+ } else if (message.arguments()[1].toString() == "countVisible") {
456+ retval.append(QVariant::fromValue(QDBusVariant(this->countVisible(appid))));
457+ }
458+ } else if (message.member() == "Set") {
459+ if (message.arguments()[1].toString() == "count") {
460+ this->setCount(appid, message.arguments()[2].value<QDBusVariant>().variant().toInt());
461+ } else if (message.arguments()[1].toString() == "countVisible") {
462+ this->setCountVisible(appid, message.arguments()[2].value<QDBusVariant>().variant().toBool());
463+ }
464+ } else if (message.member() == "GetAll") {
465+ retval.append(this->itemToVariant(appid));
466+ } else {
467+ return false;
468+ }
469+
470+ QDBusMessage reply = message.createReply(retval);
471+ return connection.send(reply);
472+}
473+
474+QString LauncherBackend::introspect(const QString &path) const
475+{
476+ /* This case we should just list the nodes */
477+ if (path == "/com/canonical/Unity/Launcher/" || path == "/com/canonical/Unity/Launcher") {
478+ QString nodes;
479+
480+ Q_FOREACH(const QString &appId, m_itemCache.keys()) {
481+ nodes.append("<node name=\"");
482+ nodes.append(encodeAppId(appId));
483+ nodes.append("\"/>\n");
484+ }
485+
486+ return nodes;
487+ }
488+
489+ /* Should not happen, but let's handle it */
490+ if (!path.startsWith("/com/canonical/Unity/Launcher")) {
491+ return "";
492+ }
493+
494+ /* Now we should be looking at a node */
495+ QString nodeiface =
496+ "<interface name=\"com.canonical.Unity.Launcher.Item\">"
497+ "<property name=\"count\" type=\"i\" access=\"readwrite\" />"
498+ "<property name=\"countVisible\" type=\"b\" access=\"readwrite\" />"
499+ "</interface>";
500+ return nodeiface;
501+}
502+
503+QString LauncherBackend::decodeAppId(const QString& path)
504+{
505+ QByteArray bytes = path.toUtf8();
506+ QByteArray decoded;
507+
508+ for (int i = 0; i < bytes.size(); ++i) {
509+ char chr = bytes.at(i);
510+
511+ if (chr == '_') {
512+ QString number;
513+ number.append(bytes.at(i+1));
514+ number.append(bytes.at(i+2));
515+
516+ bool okay;
517+ char newchar = number.toUInt(&okay, 16);
518+ if (okay)
519+ decoded.append(newchar);
520+
521+ i += 2;
522+ } else {
523+ decoded.append(chr);
524+ }
525+ }
526+
527+ return QString::fromUtf8(decoded);
528+}
529+
530+QString LauncherBackend::encodeAppId(const QString& appId)
531+{
532+ QByteArray bytes = appId.toUtf8();
533+ QString encoded;
534+
535+ for (int i = 0; i < bytes.size(); ++i) {
536+ uchar chr = bytes.at(i);
537+
538+ if ((chr >= 'a' && chr <= 'z') ||
539+ (chr >= 'A' && chr <= 'Z') ||
540+ (chr >= '0' && chr <= '9'&& i != 0)) {
541+ encoded.append(chr);
542+ } else {
543+ QString hexval = QString("_%1").arg(chr, 2, 16, QChar('0'));
544+ encoded.append(hexval.toUpper());
545+ }
546+ }
547+
548+ return encoded;
549+}
550+
551+void LauncherBackend::emitPropChangedDbus(const QString& appId, const QString& property, QVariant &value) const
552+{
553+ QString path("/com/canonical/Unity/Launcher/");
554+ path.append(encodeAppId(appId));
555+
556+ QDBusMessage message = QDBusMessage::createSignal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged");
557+
558+ QList<QVariant> arguments;
559+ QVariantHash changedprops;
560+ changedprops[property] = QVariant::fromValue(QDBusVariant(value));
561+ QVariantList deletedprops;
562+
563+ arguments.append(changedprops);
564+ arguments.append(deletedprops);
565+
566+ message.setArguments(arguments);
567+
568+ QDBusConnection con = QDBusConnection::sessionBus();
569+ con.send(message);
570+}
plugins/Unity/Launcher/backend/launcherbackend.h+52−4
@@ -24,6 +24,7 @@
24#include <QObject>
24#include <QObject>
25#include <QSettings>
25#include <QSettings>
26#include <QStringList>
26#include <QStringList>
27+#include <QDBusVirtualObject>
27
28
28class AccountsServiceDBusAdaptor;
29class AccountsServiceDBusAdaptor;
29
30
@@ -32,11 +33,13 @@ class AccountsServiceDBusAdaptor;
32 */
33 */
33
34
34class LauncherBackendItem;
35class LauncherBackendItem;
36+class LauncherBackendTest;
35
37
36−class LauncherBackend : public QObject
38+class LauncherBackend : public QDBusVirtualObject
37{
39{
38 Q_OBJECT
40 Q_OBJECT
39
41
42+ friend LauncherBackendTest;
40
43
41public:
44public:
42 LauncherBackend(QObject *parent = 0);
45 LauncherBackend(QObject *parent = 0);
@@ -116,16 +119,53 @@ public:
116 */
119 */
117 int count(const QString &appId) const;
120 int count(const QString &appId) const;
118
121
122+ /**
123+ * @brief Set the count on an item
124+ * @param appId The ID of the application
125+ * @param count Count to show on the application
126+ */
127+ void setCount(const QString &appId, int count) const;
128+
129+ /**
130+ * @brief Get whether the count should be visible
131+ * @param appId The ID of the application.
132+ * @returns Whether to show a count on the launcher
133+ */
134+ bool countVisible(const QString &appId) const;
135+
136+ /**
137+ * @brief Set the visibility of the count item
138+ * @param appId The ID of the application
139+ * @param visible Whether the count should be visible
140+ */
141+ void setCountVisible(const QString &appId, bool visible) const;
142+
119 /**
143 /**
120 * @brief Sets the username for which to look up launcher items.
144 * @brief Sets the username for which to look up launcher items.
121 * @param username The username to use.
145 * @param username The username to use.
122 */
146 */
123 void setUser(const QString &username);
147 void setUser(const QString &username);
124
148
149+ /**
150+ * @brief Handle a message to an application node
151+ * @param message DBus message to handle
152+ * @param connection DBus connection that we're using
153+ * @returns whether the message was handled
154+ */
155+ virtual bool handleMessage(const QDBusMessage& message, const QDBusConnection& connection);
156+
157+ /**
158+ * @brief Get introspection information on the objects we're exporting
159+ * @param path the dbus path containing the appid
160+ * @returns Introspection information for that node in the tree
161+ */
162+ virtual QString introspect (const QString &path) const;
163+
125Q_SIGNALS:
164Q_SIGNALS:
126− void quickListChanged(const QString &appId, const QList<QuickListEntry> &quickList);
165+ void quickListChanged(const QString &appId, const QList<QuickListEntry> &quickList) const;
127− void progressChanged(const QString &appId, int progress);
166+ void progressChanged(const QString &appId, int progress) const;
128− void countChanged(const QString &appId, int count);
167+ void countChanged(const QString &appId, int count) const;
168+ void countVisibleChanged(const QString &appId, bool visible) const;
129
169
130private:
170private:
131 QString findDesktopFile(const QString &appId) const;
171 QString findDesktopFile(const QString &appId) const;
@@ -143,6 +183,14 @@ private:
143
183
144 AccountsServiceDBusAdaptor *m_accounts;
184 AccountsServiceDBusAdaptor *m_accounts;
145 QString m_user;
185 QString m_user;
186+
187+ void emitPropChangedDbus(const QString& appId, const QString& property, QVariant &value) const;
188+
189+protected: /* Protected to allow testing */
190+ LauncherBackendItem* getItem(const QString& appId) const;
191+
192+ static QString decodeAppId(const QString& path);
193+ static QString encodeAppId(const QString& appId);
146};
194};
147
195
148#endif // LAUNCHERBACKEND_H
196#endif // LAUNCHERBACKEND_H
qml/Components/LazyImage.qml+1
@@ -36,6 +36,7 @@ Item {
36 property alias cache: image.cache
36 property alias cache: image.cache
37 property alias horizontalAlignment: image.horizontalAlignment
37 property alias horizontalAlignment: image.horizontalAlignment
38 property alias verticalAlignment: image.verticalAlignment
38 property alias verticalAlignment: image.verticalAlignment
39+ property alias sourceImage: image
39
40
40 state: "default"
41 state: "default"
41
42
qml/Components/ZoomableImage.qmlnew file+153
@@ -0,0 +1,153 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import Ubuntu.Components 0.1
19+import "../Components"
20+
21+/*! \brief Zoomable for image.
22+
23+ This widget shows image contained in source,
24+ can be zoomable accordingly with zoomable.
25+ */
26+
27+Item {
28+ id: root
29+ property alias source: lazyImage.source
30+ property var zoomable: false
31+ property alias imageState: lazyImage.state
32+ property alias scaleTo: lazyImage.scaleTo
33+ property alias asynchronous: lazyImage.asynchronous
34+
35+ Flickable {
36+ id: flickable
37+ objectName: "flickable"
38+ clip: true
39+ contentHeight: imageContainer.height
40+ contentWidth: imageContainer.width
41+
42+ onHeightChanged: image.resetScale()
43+ onWidthChanged: image.resetScale()
44+ anchors.fill: parent
45+
46+ Item {
47+ id: imageContainer
48+ objectName: "imageContainer"
49+ width: Math.max(image.width * image.scale, flickable.width)
50+ height: Math.max(image.height * image.scale, flickable.height)
51+
52+ Item {
53+ id: image
54+ objectName: "image"
55+ property alias imageState: lazyImage.state
56+ property var prevScale
57+ anchors.centerIn: parent
58+
59+ signal imageReloaded
60+
61+ LazyImage {
62+ id: lazyImage
63+ objectName: "lazyImage"
64+ smooth: !flickable.movingVertically
65+ anchors.fill: parent
66+ fillMode: Image.PreserveAspectFit
67+ scaleTo: "fit"
68+
69+ onStateChanged: {
70+ if (state == "ready") {
71+ image.imageReloaded();
72+ }
73+ }
74+ }
75+
76+ onImageReloaded: {
77+ image.height = lazyImage.sourceImage.implicitHeight
78+ image.width = lazyImage.sourceImage.implicitWidth
79+ image.resetScale();
80+ }
81+
82+ function resetScale() {
83+ image.scale = Math.min(flickable.width / image.width, flickable.height / image.height);
84+ pinchArea.minScale = image.scale;
85+ prevScale = Math.min(image.scale, 1);
86+ }
87+
88+ onScaleChanged: {
89+ var currentWidth = width * scale
90+ var currentHeight = height * scale
91+ var scaleRatio = scale / prevScale
92+ if (currentWidth > flickable.width) {
93+ var xpos = flickable.width / 2 + flickable.contentX;
94+ var xoff = xpos * scaleRatio;
95+ flickable.contentX = xoff - flickable.width / 2;
96+ }
97+ if (currentHeight > flickable.height) {
98+ var ypos = flickable.height / 2 + flickable.contentY;
99+ var yoff = ypos * scaleRatio;
100+ flickable.contentY = yoff - flickable.height / 2;
101+ }
102+ prevScale = scale;
103+ }
104+ }
105+ }
106+
107+ PinchArea {
108+ id: pinchArea
109+ objectName: "pinchArea"
110+ property real minScale: 1.0
111+ anchors.fill: parent
112+ enabled: zoomable ? zoomable : false
113+
114+ pinch.target: image
115+ pinch.minimumScale: minScale
116+ pinch.maximumScale: 10
117+
118+ onPinchFinished: flickable.returnToBounds()
119+ }
120+
121+ MouseArea {
122+ id: mouseArea
123+ objectName: "mouseArea"
124+
125+ anchors.fill: parent
126+ enabled: zoomable ? zoomable : false
127+
128+ onWheel: {
129+ var startScale = image.scale;
130+ if (wheel.angleDelta.y > 0) {
131+ image.scale = startScale + 0.1;
132+ } else if (wheel.angleDelta.y < 0) {
133+ if (image.scale > 0.1 && image.scale > pinchArea.minScale) {
134+ image.scale = startScale - 0.1;
135+ }
136+ }
137+ wheel.accepted = true;
138+ }
139+
140+ onPressed: {
141+ mouse.accepted = false;
142+ }
143+
144+ onReleased: {
145+ mouse.accepted = false;
146+ }
147+
148+ onClicked: {
149+ mouse.accepted = false;
150+ }
151+ }
152+ }
153+}
qml/Dash/Previews/PreviewProgress.qml+3−2
@@ -34,11 +34,12 @@ PreviewWidget {
34 ProgressBar {
34 ProgressBar {
35 id: progressBar
35 id: progressBar
36 objectName: "progressBar"
36 objectName: "progressBar"
37+ anchors.right: parent.right
37 value: 0
38 value: 0
38 maximumValue: 100
39 maximumValue: 100
39− implicitHeight: units.gu(5)
40+ implicitHeight: units.gu(4)
40 height: parent.height
41 height: parent.height
41− width: parent.width
42+ width: (root.width - units.gu(1)) / 2
42
43
43 property var source: widgetData["source"]
44 property var source: widgetData["source"]
44 // TODO Eventually we will need to support more sources other
45 // TODO Eventually we will need to support more sources other
qml/Dash/Previews/PreviewZoomableImage.qml+4−7
@@ -28,14 +28,11 @@ PreviewWidget {
28 id: root
28 id: root
29 implicitHeight: units.gu(22)
29 implicitHeight: units.gu(22)
30
30
31− LazyImage {
31+ ZoomableImage {
32+ id: image
32 objectName: "image"
33 objectName: "image"
33− anchors {
34− top: parent.top
35− bottom: parent.bottom
36− }
37− scaleTo: "height"
38 source: widgetData["source"]
34 source: widgetData["source"]
39− initialWidth: units.gu(13)
35+ zoomable: widgetData["zoomable"] ? widgetData["zoomable"] : false
36+ anchors.fill: parent
40 }
37 }
41}
38}
qml/Notifications/Notifications.qml+11
@@ -16,6 +16,8 @@
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19+import Unity.Notifications 1.0 as UnityNotifications
20+import Utils 0.1
19import "../Components"
21import "../Components"
20
22
21ListView {
23ListView {
@@ -25,6 +27,15 @@ ListView {
25 interactive: false
27 interactive: false
26
28
27 property real margin
29 property real margin
30+ property bool useModal: snapDecisionProxyModel.count > 0
31+
32+ SortFilterProxyModel {
33+ id: snapDecisionProxyModel
34+
35+ model: notificationList.model
36+ filterRole: UnityNotifications.ModelInterface.RoleType
37+ filterRegExp: RegExp(UnityNotifications.Notification.SnapDecision)
38+ }
28 spacing: delegate.fullscreen ? 0 : units.gu(.5)
39 spacing: delegate.fullscreen ? 0 : units.gu(.5)
29
40
30 currentIndex: (currentIndex < 1 && count > 1) ? 1 : -1
41 currentIndex: (currentIndex < 1 && count > 1) ? 1 : -1
qml/Shell.qml+18
@@ -440,6 +440,24 @@ BasicShell {
440 }
440 }
441 }
441 }
442
442
443+ Rectangle {
444+ id: modalNotificationBackground
445+
446+ visible: notifications.useModal && !greeter.shown && (notifications.state == "narrow")
447+ color: "#000000"
448+ anchors.fill: parent
449+ opacity: 0.5
450+
451+ MouseArea {
452+ anchors.fill: parent
453+ }
454+
455+ InputFilterArea {
456+ anchors.fill: parent
457+ blockInput: modalNotificationBackground.visible
458+ }
459+ }
460+
443 Notifications {
461 Notifications {
444 id: notifications
462 id: notifications
445
463
run → run.shrenamed+1−1
@@ -86,6 +86,6 @@ else
86 echo "Unity8 is already running, please stop it first"
86 echo "Unity8 is already running, please stop it first"
87 exit 1
87 exit 1
88 fi
88 fi
89− /sbin/initctl start unity8 BINARY="`readlink -f $QML_PHONE_SHELL_PATH` $QML_PHONE_SHELL_ARGS $@"
89+ /sbin/initctl start unity8 BINARY="`readlink -f $QML_PHONE_SHELL_PATH` $QML_PHONE_SHELL_ARGS $@" QML2_IMPORT_PATH=$QML2_IMPORT_PATH LD_LIBRARY_PATH=$LD_LIBRARY_PATH
90 tailf -n 0 ~/.cache/upstart/unity8.log
90 tailf -n 0 ~/.cache/upstart/unity8.log
91fi
91fi
run_on_device → run_on_device.shrenamed+2−2
@@ -88,7 +88,7 @@ sync_code() {
88}
88}
89
89
90build() {
90build() {
91− exec_with_ssh PATH=/usr/lib/ccache:$PATH "cd $CODE_DIR/ && PATH=/usr/lib/ccache:$PATH ./build"
91+ exec_with_ssh PATH=/usr/lib/ccache:$PATH "cd $CODE_DIR/ && PATH=/usr/lib/ccache:$PATH ./build.sh"
92}
92}
93
93
94run() {
94run() {
@@ -105,7 +105,7 @@ run() {
105
105
106 exec_with_ssh "stop unity8"
106 exec_with_ssh "stop unity8"
107 exec_with_ssh "start maliit-server"
107 exec_with_ssh "start maliit-server"
108− exec_with_ssh "cd $CODE_DIR/ && ./run $ARGS -- $RUN_OPTIONS"
108+ exec_with_ssh "cd $CODE_DIR/ && ./run.sh $ARGS -- $RUN_OPTIONS"
109 exec_with_ssh "stop maliit-server"
109 exec_with_ssh "stop maliit-server"
110 exec_with_ssh "start unity8"
110 exec_with_ssh "start unity8"
111}
111}
tests/autopilot/unity8/shell/tests/test_notifications.py+83
@@ -208,6 +208,89 @@ class InteractiveNotificationBase(NotificationsBase):
208 self.touch.tap_object(notification.select_single(objectName="button4"))
208 self.touch.tap_object(notification.select_single(objectName="button4"))
209 self.assert_notification_action_id_was_called("action_decline_4")
209 self.assert_notification_action_id_was_called("action_decline_4")
210
210
211+ def test_modal_sd_without_greeter (self):
212+ """A snap-decision on a phone should block input to shell beneath it when there's no greeter."""
213+ unity_proxy = self.launch_unity()
214+ unlock_unity(unity_proxy)
215+
216+ summary = "Incoming file"
217+ body = "Frank would like to send you the file: essay.pdf"
218+ icon_path = "sync-idle"
219+ hints = [
220+ ("x-canonical-snap-decisions", "true"),
221+ ("x-canonical-non-shaped-icon", "true"),
222+ ]
223+
224+ actions = [
225+ ('action_accept', 'Accept'),
226+ ('action_decline_1', 'Decline'),
227+ ]
228+
229+ self._create_interactive_notification(
230+ summary,
231+ body,
232+ icon_path,
233+ "NORMAL",
234+ actions,
235+ hints
236+ )
237+
238+ # verify that we cannot reveal the launcher (no longer interact with the shell)
239+ time.sleep(1)
240+ self.main_window.show_dash_swiping()
241+ launcher = self.main_window.get_launcher()
242+ self.assertThat(launcher.shown, Eventually(Equals(False)))
243+
244+ # verify and interact with the triggered snap-decision notification
245+ notify_list = self._get_notifications_list()
246+ get_notification = lambda: notify_list.wait_select_single(
247+ 'Notification', objectName='notification1')
248+ notification = get_notification()
249+ self._assert_notification(notification, summary, body, True, False, 1.0)
250+ self.touch.tap_object(notification.select_single(objectName="button0"))
251+ self.assert_notification_action_id_was_called("action_accept")
252+
253+ def test_modal_sd_with_greeter (self):
254+ """A snap-decision on a phone should not block input to the greeter beneath it."""
255+ unity_proxy = self.launch_unity()
256+
257+ summary = "Incoming file"
258+ body = "Frank would like to send you the file: essay.pdf"
259+ icon_path = "sync-idle"
260+ hints = [
261+ ("x-canonical-snap-decisions", "true"),
262+ ("x-canonical-non-shaped-icon", "true"),
263+ ]
264+
265+ actions = [
266+ ('action_accept', 'Accept'),
267+ ('action_decline_1', 'Decline'),
268+ ]
269+
270+ self._create_interactive_notification(
271+ summary,
272+ body,
273+ icon_path,
274+ "NORMAL",
275+ actions,
276+ hints
277+ )
278+
279+ # verify that we can swipe away the greeter (interact with the "shell")
280+ time.sleep(1)
281+ self.main_window.show_dash_swiping()
282+ greeter = self.main_window.get_greeter()
283+ self.assertThat(greeter.shown, Eventually(Equals(False)))
284+
285+ # verify and interact with the triggered snap-decision notification
286+ notify_list = self._get_notifications_list()
287+ get_notification = lambda: notify_list.wait_select_single(
288+ 'Notification', objectName='notification1')
289+ notification = get_notification()
290+ self._assert_notification(notification, summary, body, True, False, 1.0)
291+ self.touch.tap_object(notification.select_single(objectName="button0"))
292+ self.assert_notification_action_id_was_called("action_accept")
293+
211 def _create_interactive_notification(
294 def _create_interactive_notification(
212 self,
295 self,
213 summary="",
296 summary="",
tests/plugins/DashViews/listviewwithpageheadersectionexternalmodeltest.cpp−4
@@ -24,11 +24,7 @@
24#include <QtTestGui>
24#include <QtTestGui>
25#pragma GCC diagnostic push
25#pragma GCC diagnostic push
26#pragma GCC diagnostic ignored "-pedantic"
26#pragma GCC diagnostic ignored "-pedantic"
27−#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
28−#include <private/qquicklistmodel_p.h>
29−#else
30#include <private/qqmllistmodel_p.h>
27#include <private/qqmllistmodel_p.h>
31−#endif
32#include <private/qquickanimation_p.h>
28#include <private/qquickanimation_p.h>
33#include <private/qquickitem_p.h>
29#include <private/qquickitem_p.h>
34#pragma GCC diagnostic pop
30#pragma GCC diagnostic pop
tests/plugins/DashViews/listviewwithpageheadersectiontest.cpp−12
@@ -23,11 +23,7 @@
23#include <QtTestGui>
23#include <QtTestGui>
24#pragma GCC diagnostic push
24#pragma GCC diagnostic push
25#pragma GCC diagnostic ignored "-pedantic"
25#pragma GCC diagnostic ignored "-pedantic"
26−#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
27−#include <private/qquicklistmodel_p.h>
28−#else
29#include <private/qqmllistmodel_p.h>
26#include <private/qqmllistmodel_p.h>
30−#endif
31#include <private/qquickanimation_p.h>
27#include <private/qquickanimation_p.h>
32#include <private/qquickitem_p.h>
28#include <private/qquickitem_p.h>
33#pragma GCC diagnostic pop
29#pragma GCC diagnostic pop
@@ -135,11 +131,7 @@ private Q_SLOTS:
135 view->engine()->addImportPath(BUILT_PLUGINS_DIR);
131 view->engine()->addImportPath(BUILT_PLUGINS_DIR);
136 view->setSource(QUrl::fromLocalFile(DASHVIEWSTEST_FOLDER "/listviewwithpageheadertestsection.qml"));
132 view->setSource(QUrl::fromLocalFile(DASHVIEWSTEST_FOLDER "/listviewwithpageheadertestsection.qml"));
137 lvwph = dynamic_cast<ListViewWithPageHeader*>(view->rootObject()->findChild<QQuickFlickable*>());
133 lvwph = dynamic_cast<ListViewWithPageHeader*>(view->rootObject()->findChild<QQuickFlickable*>());
138−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
139− model = view->rootObject()->findChild<QQuickListModel*>();
140−#else
141 model = view->rootObject()->findChild<QQmlListModel*>();
134 model = view->rootObject()->findChild<QQmlListModel*>();
142−#endif
143 otherDelegate = view->rootObject()->findChild<QQmlComponent*>();
135 otherDelegate = view->rootObject()->findChild<QQmlComponent*>();
144 QVERIFY(lvwph);
136 QVERIFY(lvwph);
145 QVERIFY(model);
137 QVERIFY(model);
@@ -2156,11 +2148,7 @@ private Q_SLOTS:
2156private:
2148private:
2157 QQuickView *view;
2149 QQuickView *view;
2158 ListViewWithPageHeader *lvwph;
2150 ListViewWithPageHeader *lvwph;
2159−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
2160− QQuickListModel *model;
2161−#else
2162 QQmlListModel *model;
2151 QQmlListModel *model;
2163−#endif
2164 QQmlComponent *otherDelegate;
2152 QQmlComponent *otherDelegate;
2165};
2153};
2166
2154
tests/plugins/DashViews/listviewwithpageheadertest.cpp−15
@@ -23,11 +23,7 @@
23#include <QtTestGui>
23#include <QtTestGui>
24#pragma GCC diagnostic push
24#pragma GCC diagnostic push
25#pragma GCC diagnostic ignored "-pedantic"
25#pragma GCC diagnostic ignored "-pedantic"
26−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
27−#include <private/qquicklistmodel_p.h>
28−#else
29#include <private/qqmllistmodel_p.h>
26#include <private/qqmllistmodel_p.h>
30−#endif
31#include <private/qquickanimation_p.h>
27#include <private/qquickanimation_p.h>
32#include <private/qquickitem_p.h>
28#include <private/qquickitem_p.h>
33#pragma GCC diagnostic pop
29#pragma GCC diagnostic pop
@@ -124,11 +120,7 @@ private Q_SLOTS:
124 view->engine()->addImportPath(BUILT_PLUGINS_DIR);
120 view->engine()->addImportPath(BUILT_PLUGINS_DIR);
125 view->setSource(QUrl::fromLocalFile(DASHVIEWSTEST_FOLDER "/listviewwithpageheadertest.qml"));
121 view->setSource(QUrl::fromLocalFile(DASHVIEWSTEST_FOLDER "/listviewwithpageheadertest.qml"));
126 lvwph = dynamic_cast<ListViewWithPageHeader*>(view->rootObject()->findChild<QQuickFlickable*>());
122 lvwph = dynamic_cast<ListViewWithPageHeader*>(view->rootObject()->findChild<QQuickFlickable*>());
127−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
128− model = view->rootObject()->findChild<QQuickListModel*>();
129−#else
130 model = view->rootObject()->findChild<QQmlListModel*>();
123 model = view->rootObject()->findChild<QQmlListModel*>();
131−#endif
132 otherDelegate = view->rootObject()->findChild<QQmlComponent*>();
124 otherDelegate = view->rootObject()->findChild<QQmlComponent*>();
133 QVERIFY(lvwph);
125 QVERIFY(lvwph);
134 QVERIFY(model);
126 QVERIFY(model);
@@ -1747,9 +1739,6 @@ private Q_SLOTS:
1747
1739
1748 void testMaximizeVisibleAreaMoveUpAndShowHeader()
1740 void testMaximizeVisibleAreaMoveUpAndShowHeader()
1749 {
1741 {
1750−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
1751− QSKIP("This test is extremely unstable in 5.0.x");
1752−#endif
1753 model->setProperty(0, "size", 800);
1742 model->setProperty(0, "size", 800);
1754 verifyItem(0, 50., 800., false);
1743 verifyItem(0, 50., 800., false);
1755
1744
@@ -1913,11 +1902,7 @@ private Q_SLOTS:
1913private:
1902private:
1914 QQuickView *view;
1903 QQuickView *view;
1915 ListViewWithPageHeader *lvwph;
1904 ListViewWithPageHeader *lvwph;
1916−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
1917− QQuickListModel *model;
1918−#else
1919 QQmlListModel *model;
1905 QQmlListModel *model;
1920−#endif
1921 QQmlComponent *otherDelegate;
1906 QQmlComponent *otherDelegate;
1922};
1907};
1923
1908
tests/plugins/Unity/Launcher/CMakeLists.txt+3−3
@@ -15,9 +15,9 @@ add_definitions(-DSRCDIR="${CMAKE_CURRENT_SOURCE_DIR}")
15add_definitions(-DLAUNCHER_TESTING)
15add_definitions(-DLAUNCHER_TESTING)
16
16
17### LauncherBackendTest
17### LauncherBackendTest
18−set(testBackendCommand ${CMAKE_CURRENT_BINARY_DIR}/launcherbackendtestExec
18+set(testBackendCommand dbus-test-runner --task ${CMAKE_CURRENT_BINARY_DIR}/launcherbackendtestExec
19− -o ${CMAKE_BINARY_DIR}/launcherbackendtest.xml,xunitxml
19+ --parameter -o --parameter ${CMAKE_BINARY_DIR}/launcherbackendtest.xml,xunitxml
20− -o -,txt)
20+ --parameter -o --parameter -,txt)
21add_test(NAME launcherbackendtest COMMAND ${testBackendCommand})
21add_test(NAME launcherbackendtest COMMAND ${testBackendCommand})
22add_custom_target(launcherbackendtest ${testBackendCommand})
22add_custom_target(launcherbackendtest ${testBackendCommand})
23add_executable(launcherbackendtestExec
23add_executable(launcherbackendtestExec
tests/plugins/Unity/Launcher/launcherbackendtest.cpp+167
@@ -20,6 +20,10 @@
20#include "launcherbackend.h"
20#include "launcherbackend.h"
21
21
22#include <QtTest>
22#include <QtTest>
23+#include <QDBusConnection>
24+#include <QDBusMessage>
25+#include <QDBusVariant>
26+
23
27
24class LauncherBackendTest : public QObject
28class LauncherBackendTest : public QObject
25{
29{
@@ -66,6 +70,169 @@ private Q_SLOTS:
66
70
67 QCOMPARE(backend.icon(appId), expectedIcon);
71 QCOMPARE(backend.icon(appId), expectedIcon);
68 }
72 }
73+
74+ void testGetItem_data() {
75+ QTest::addColumn<QString>("appId");
76+ QTest::addColumn<bool>("exists");
77+
78+ QTest::newRow("Exists") << "rel-icon" << true;
79+ QTest::newRow("Doesn't Exist") << "does-not-exist" << false;
80+ }
81+
82+ void testGetItem() {
83+ QFETCH(QString, appId);
84+ QFETCH(bool, exists);
85+
86+ LauncherBackend backend;
87+ auto item = backend.getItem(appId);
88+
89+ if (exists) {
90+ QVERIFY(item != nullptr);
91+ } else {
92+ QVERIFY(item == nullptr);
93+ }
94+ }
95+
96+ void testCount_data() {
97+ QTest::addColumn<QString>("appId");
98+ QTest::addColumn<bool>("setCount");
99+ QTest::addColumn<int>("inCount");
100+ QTest::addColumn<bool>("countVisible");
101+ QTest::addColumn<int>("expectedCount");
102+
103+ /* Get baseline data on things working */
104+ QTest::newRow("Baseline") << "rel-icon" << false << 0 << false << -1;
105+
106+ /* Valid count, but not visible */
107+ QTest::newRow("Not visible") << "rel-icon" << true << 42 << false << -1;
108+
109+ /* Turn it on */
110+ QTest::newRow("Visible Count") << "rel-icon" << true << 42 << true << 42;
111+
112+ /* Invalide app to load */
113+ QTest::newRow("Invalid App ID") << "this-app-doesnt-exist" << true << 42 << true << -1;
114+ }
115+
116+ void testCount() {
117+ QFETCH(QString, appId);
118+ QFETCH(bool, setCount);
119+ QFETCH(int, inCount);
120+ QFETCH(bool, countVisible);
121+ QFETCH(int, expectedCount);
122+
123+ LauncherBackend backend;
124+
125+ if (setCount)
126+ backend.setCount(appId, inCount);
127+ backend.setCountVisible(appId, countVisible);
128+
129+ QCOMPARE(backend.count(appId), expectedCount);
130+ }
131+
132+ void testDbusName_data() {
133+ QTest::addColumn<QString>("decoded");
134+ QTest::addColumn<QString>("encoded");
135+
136+ /* Passthrough test */
137+ QTest::newRow("Passthrough") << "fine" << "fine";
138+
139+ /* Number as first characeter */
140+ QTest::newRow("Number first") << "31337" << "_331337";
141+
142+ /* Underscore test */
143+ QTest::newRow("Underscore test") << "this_is_c_style_namespacing" << "this_5Fis_5Fc_5Fstyle_5Fnamespacing";
144+
145+ /* Hyphen test */
146+ QTest::newRow("Hyphen test") << "typical-application" << "typical_2Dapplication";
147+
148+ /* Japanese test */
149+ QTest::newRow("日本語 test") << "日本語" << "_E6_97_A5_E6_9C_AC_E8_AA_9E";
150+ }
151+
152+ void testDbusName() {
153+ QFETCH(QString, decoded);
154+ QFETCH(QString, encoded);
155+
156+ QString encodeOut = LauncherBackend::encodeAppId(decoded);
157+ QCOMPARE(encoded, encodeOut);
158+
159+ QString decodeOut = LauncherBackend::decodeAppId(encoded);
160+ QCOMPARE(decoded, decodeOut);
161+ }
162+
163+ void testDbusIface_data() {
164+ QTest::addColumn<QString>("appId");
165+ QTest::addColumn<bool>("setCount");
166+ QTest::addColumn<int>("inCount");
167+ QTest::addColumn<bool>("countVisible");
168+ QTest::addColumn<int>("expectedCount");
169+
170+ /* Get baseline data on things working */
171+ QTest::newRow("Baseline") << "rel-icon" << false << 0 << false << -1;
172+
173+ /* Turn it on */
174+ QTest::newRow("Visible Count") << "rel-icon" << true << 42 << true << 42;
175+
176+ /* Invalide app to load */
177+ QTest::newRow("Invalid App ID") << "this-app-doesnt-exist" << true << 42 << true << -1;
178+ }
179+
180+ void testDbusIface() {
181+ QFETCH(QString, appId);
182+ QFETCH(bool, setCount);
183+ QFETCH(int, inCount);
184+ QFETCH(bool, countVisible);
185+ QFETCH(int, expectedCount);
186+
187+ QDBusConnection con = QDBusConnection::sessionBus();
188+ QDBusMessage message;
189+ QDBusMessage reply;
190+
191+ LauncherBackend backend;
192+
193+ if (setCount) {
194+ message = QDBusMessage::createMethodCall("com.canonical.Unity.Launcher",
195+ "/com/canonical/Unity/Launcher/" + LauncherBackend::encodeAppId(appId),
196+ "org.freedesktop.DBus.Properties",
197+ "Set");
198+ QVariantList cargs;
199+ cargs.append(QString("com.canonical.Unity.Launcher.Item"));
200+ cargs.append(QString("count"));
201+ cargs.append(QVariant::fromValue(QDBusVariant(inCount)));
202+
203+ message.setArguments(cargs);
204+ reply = con.call(message);
205+ QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);
206+ }
207+
208+ /* Set countVisible */
209+ message = QDBusMessage::createMethodCall("com.canonical.Unity.Launcher",
210+ "/com/canonical/Unity/Launcher/" + LauncherBackend::encodeAppId(appId),
211+ "org.freedesktop.DBus.Properties",
212+ "Set");
213+ QVariantList cvargs;
214+ cvargs.append(QString("com.canonical.Unity.Launcher.Item"));
215+ cvargs.append(QString("countVisible"));
216+ cvargs.append(QVariant::fromValue(QDBusVariant(countVisible)));
217+
218+ message.setArguments(cvargs);
219+ reply = con.call(message);
220+ QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);
221+
222+ /* Get value */
223+ message = QDBusMessage::createMethodCall("com.canonical.Unity.Launcher",
224+ "/com/canonical/Unity/Launcher/" + LauncherBackend::encodeAppId(appId),
225+ "org.freedesktop.DBus.Properties",
226+ "Get");
227+ QVariantList getargs;
228+ getargs.append(QString("com.canonical.Unity.Launcher.Item"));
229+ getargs.append(QString("count"));
230+
231+ message.setArguments(getargs);
232+ reply = con.call(message);
233+ QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);
234+ QCOMPARE(reply.arguments()[0].value<QDBusVariant>().variant().toInt(), expectedCount);
235+ }
69};
236};
70
237
71QTEST_GUILESS_MAIN(LauncherBackendTest)
238QTEST_GUILESS_MAIN(LauncherBackendTest)
tests/qmltests/CMakeLists.txt+1
@@ -33,6 +33,7 @@ add_qml_test(Components Revealer)
33add_qml_test(Components SeeMore)
33add_qml_test(Components SeeMore)
34add_qml_test(Components Showable)
34add_qml_test(Components Showable)
35add_qml_test(Components PageHeaderLabel)
35add_qml_test(Components PageHeaderLabel)
36+add_qml_test(Components ZoomableImage)
36add_qml_test(Dash Dash)
37add_qml_test(Dash Dash)
37add_qml_test(Dash DashContent)
38add_qml_test(Dash DashContent)
38add_qml_test(Dash Card)
39add_qml_test(Dash Card)
tests/qmltests/Components/tst_ZoomableImage.qmlnew file+192
@@ -0,0 +1,192 @@
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 "../../../qml/Components"
20+import Unity.Test 0.1 as UT
21+
22+Rectangle {
23+ id: root
24+ width: units.gu(30)
25+ height: units.gu(60)
26+ color: "lightgrey"
27+
28+ property var widgetData0: {
29+ "source": "",
30+ "zoomable": false
31+ }
32+
33+ property var widgetData1: {
34+ "source": "../../../qml/graphics/phone_background.jpg",
35+ "zoomable": false
36+ }
37+
38+ property var widgetData2: {
39+ "source": "../../../qml/Dash/graphics/phone/screenshots/gallery@12.png",
40+ "zoomable": true
41+ }
42+
43+ ZoomableImage {
44+ id: zoomableImage
45+ width: parent.width
46+ anchors.fill: parent
47+ asynchronous: false
48+ }
49+
50+ SignalSpy {
51+ id: signalSpy
52+ }
53+
54+ UT.UnityTestCase {
55+ name: "ZoomableImageTest"
56+ when: windowShown
57+
58+ function test_loadImage() {
59+ var lazyImage = findChild(zoomableImage, "lazyImage");
60+
61+ zoomableImage.source = widgetData0["source"];
62+ zoomableImage.zoomable = widgetData0["zoomable"];
63+ waitForRendering(zoomableImage);
64+ tryCompare(zoomableImage, "imageState", "default");
65+
66+ signalSpy.signalName = "onStateChanged";
67+ signalSpy.target = lazyImage;
68+ signalSpy.clear();
69+
70+ zoomableImage.source = widgetData1["source"];
71+ zoomableImage.zoomable = widgetData1["zoomable"];
72+ waitForRendering(lazyImage);
73+ tryCompareFunction(function() { return get_filename(lazyImage.source.toString()) === get_filename(widgetData1["source"]); }, true);
74+ waitForRendering(zoomableImage);
75+ tryCompare(zoomableImage, "imageState", "ready");
76+ compare (signalSpy.count, 1);
77+ }
78+
79+ function get_filename(a) {
80+ var wordsA = a.split("/");
81+ var filenameA = wordsA[wordsA.length-1];
82+ return filenameA;
83+ }
84+
85+ function test_mousewheel() {
86+ var image = findChild(zoomableImage, "image");
87+ var lazyImage = findChild(zoomableImage, "lazyImage");
88+ var flickable = findChild(zoomableImage, "flickable");
89+
90+ zoomableImage.source = widgetData2["source"];
91+ zoomableImage.zoomable = true;
92+ waitForRendering(zoomableImage);
93+
94+ tryCompare(zoomableImage, "imageState", "ready");
95+ tryCompareFunction(function() { return get_filename(lazyImage.source.toString()) === get_filename(widgetData2["source"]); }, true);
96+ waitForRendering(image);
97+
98+ // move mouse to center
99+ mouseMove(zoomableImage, zoomableImage.width / 2, zoomableImage.height / 2);
100+
101+ // Test Zoom-in Zoom-out twice.
102+ for (var c=0; c<2; c++) {
103+ // zoom in
104+ for (var i=0; i<10; i++) {
105+ mouseWheel(zoomableImage, zoomableImage.width / 2, zoomableImage.height / 2, 0, 10);
106+ tryCompare(image, "scale", 1.0 + (i + 1) * 0.1);
107+ compare(flickable.contentWidth, lazyImage.width * image.scale);
108+ compare(flickable.contentHeight, lazyImage.height * image.scale);
109+ }
110+
111+ // zoom out
112+ for (var i=0; i<10; i++) {
113+ mouseWheel(zoomableImage, zoomableImage.width / 2, zoomableImage.height / 2, 0, -10);
114+ tryCompare(image, "scale", 2.0 - (i + 1) * 0.1);
115+ compare(flickable.contentWidth, lazyImage.width * image.scale);
116+ compare(flickable.contentHeight, lazyImage.height * image.scale);
117+ }
118+ }
119+ }
120+
121+ function test_pinch_data() {
122+ return [ { source:widgetData2["source"],
123+ zoomable:false,
124+ answer1: true,
125+ answer2: false,
126+ answer3: true,
127+ answer4: 1.0,
128+ answer5: 1.0 },
129+ { source:widgetData2["source"],
130+ zoomable:true,
131+ answer1: false,
132+ answer2: true,
133+ answer3: false,
134+ answer4: 1.7740461882048026,
135+ answer5: 1.0 }
136+ ]
137+ }
138+
139+ function test_pinch(data) {
140+ var image = findChild(zoomableImage, "image");
141+ var lazyImage = findChild(zoomableImage, "lazyImage");
142+ var flickable = findChild(zoomableImage, "flickable");
143+
144+ signalSpy.signalName = "onScaleChanged";
145+ signalSpy.target = image;
146+ signalSpy.clear();
147+
148+ zoomableImage.source = data.source;
149+ zoomableImage.zoomable = data.zoomable;
150+ waitForRendering(zoomableImage);
151+
152+ tryCompare(zoomableImage, "imageState", "ready");
153+ tryCompareFunction(function() { return get_filename(lazyImage.source.toString()) === get_filename(data.source); }, true);
154+ waitForRendering(image);
155+
156+ var x1Start = zoomableImage.width * 2 / 6;
157+ var y1Start = zoomableImage.height * 2 / 6;
158+ var x1End = zoomableImage.width * 1 / 6;
159+ var y1End = zoomableImage.height * 1 / 6;
160+ var x2Start = zoomableImage.width * 4 / 6;
161+ var y2Start = zoomableImage.height * 4 / 6;
162+ var x2End = zoomableImage.width * 5 / 6;
163+ var y2End = zoomableImage.height * 5 / 6;
164+
165+ var oldScale = image.scale;
166+
167+ // move mouse to center
168+ mouseMove(zoomableImage, zoomableImage.width / 2, zoomableImage.height / 2);
169+
170+ // Test Zoom-in Zoom-out twice.
171+ for (var c=0; c<2; c++) {
172+ wait(3000); // have to delay between two consequent pinch event.
173+ // pinch zoom-in
174+ touchPinch(zoomableImage, x1Start, y1Start, x1End, y1End, x2Start, y2Start, x2End, y2End);
175+
176+ tryCompare(image, "scale", data.answer4);
177+ var newScale = image.scale;
178+ compare(newScale == oldScale, data.answer1, "scale factor not equal: "+ oldScale + "=?" + newScale);
179+ compare(newScale > oldScale, data.answer2, "scale factor didn't changed");
180+ compare(signalSpy.count == 0, data.answer3, "scale signal count error");
181+ compare(newScale, data.answer4, "scale factor error");
182+ compare(flickable.contentWidth, lazyImage.width * image.scale);
183+ compare(flickable.contentHeight, lazyImage.height * image.scale);
184+
185+ wait(3000); // have to delay between two consequent pinch event.
186+ // pinch zoom-out
187+ touchPinch(zoomableImage, x1End, y1End, x1Start, y1Start, x2End, y2End, x2Start, y2Start);
188+ tryCompare(image, "scale", data.answer5);
189+ }
190+ }
191+ }
192+}
tests/qmltests/Dash/Previews/tst_PreviewZoomableImage.qml+6−3
@@ -36,7 +36,8 @@ Rectangle {
36
36
37 PreviewZoomableImage {
37 PreviewZoomableImage {
38 id: zoomableImage
38 id: zoomableImage
39− width: parent.width
39+ anchors.fill: parent
40+ widgetData: widgetData1
40 }
41 }
41
42
42 UT.UnityTestCase {
43 UT.UnityTestCase {
@@ -47,10 +48,12 @@ Rectangle {
47 var image = findChild(zoomableImage, "image");
48 var image = findChild(zoomableImage, "image");
48
49
49 zoomableImage.widgetData = widgetData0;
50 zoomableImage.widgetData = widgetData0;
51+ waitForRendering(zoomableImage);
50− tryCompare(image, "state", "default");
52+ tryCompare(image, "imageState", "default");
51
53
52 zoomableImage.widgetData = widgetData1;
54 zoomableImage.widgetData = widgetData1;
55+ waitForRendering(zoomableImage);
53− tryCompare(image, "state", "ready");
56+ tryCompare(image, "imageState", "ready");
54 }
57 }
55 }
58 }
56}
59}
tests/utils/modules/Unity/Test/UnityTestCase.qml+26
@@ -260,6 +260,32 @@ TestCase {
260 }
260 }
261 }
261 }
262
262
263+ function touchPinch(item, x1Start, y1Start, x1End, y1End, x2Start, y2Start, x2End, y2End) {
264+ // Make sure the item is rendered
265+ waitForRendering(item);
266+
267+ var event1 = touchEvent();
268+ // first finger
269+ event1.press(0, x1Start, y1Start);
270+ event1.commit();
271+ // second finger
272+ event1.stationary(0);
273+ event1.press(1, x2Start, y2Start);
274+ event1.commit();
275+
276+ // pinch
277+ for (var i = 0.0; i < 1.0; i += 0.02) {
278+ event1.move(0, x1Start + (x1End - x1Start) * i, y1Start + (y1End - y1Start) * i);
279+ event1.move(1, x2Start + (x2End - x2Start) * i, y2Start + (y2End - y2Start) * i);
280+ event1.commit();
281+ }
282+
283+ // release
284+ event1.release(0, x1End, y1End);
285+ event1.release(1, x2End, y2End);
286+ event1.commit();
287+ }
288+
263 function fetchRootItem(item) {
289 function fetchRootItem(item) {
264 if (item.parent)
290 if (item.parent)
265 return fetchRootItem(item.parent)
291 return fetchRootItem(item.parent)