Merge lp:~zsombi/ubuntu-ui-toolkit/statesaver-vs-urihandler into lp:ubuntu-ui-toolkit/staging

Proposed by Zsombor Egri
Status: Work in progress
Proposed branch: lp:~zsombi/ubuntu-ui-toolkit/statesaver-vs-urihandler
Merge into: lp:ubuntu-ui-toolkit/staging
Diff against target: 433 lines (+175/-42)
8 files modified
modules/Ubuntu/Components/plugin/statesaverbackend_p.cpp (+41/-22)
modules/Ubuntu/Components/plugin/statesaverbackend_p.h (+6/-6)
modules/Ubuntu/Components/plugin/ucstatesaver.cpp (+8/-9)
modules/Ubuntu/Components/plugin/ucurihandler.cpp (+38/-2)
modules/Ubuntu/Components/plugin/ucurihandler.h (+6/-1)
tests/unit_x11/tst_statesaver/UriHandlerApp.qml (+41/-0)
tests/unit_x11/tst_statesaver/tst_statesaver.cpp (+33/-1)
tests/unit_x11/tst_statesaver/tst_statesaver.pro (+2/-1)
To merge this branch: bzr merge lp:~zsombi/ubuntu-ui-toolkit/statesaver-vs-urihandler
Reviewer Review Type Date Requested Status
Ubuntu SDK team Pending
Review via email: mp+256485@code.launchpad.net

Commit message

StateSaver should reset its database when the application is launched by url-dispatcher using --uri=%u argument. UriHandler should cache the received URIs till StateSaver restores the application state.

To post a comment you must log in.
1479. By Zsombor Egri

test added, more to come

1480. By Zsombor Egri

staging merge

Unmerged revisions

1480. By Zsombor Egri

staging merge

1479. By Zsombor Egri

test added, more to come

1478. By Zsombor Egri

StateSaver to be reset when --uri=%u Exec line is applied on application launching, UriHandler to queue URIs received until StateSaver::completed() arrives.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'modules/Ubuntu/Components/plugin/statesaverbackend_p.cpp'
2--- modules/Ubuntu/Components/plugin/statesaverbackend_p.cpp 2015-02-26 13:35:57 +0000
3+++ modules/Ubuntu/Components/plugin/statesaverbackend_p.cpp 2015-04-17 07:52:46 +0000
4@@ -1,5 +1,5 @@
5 /*
6- * Copyright 2013 Canonical Ltd.
7+ * Copyright 2015 Canonical Ltd.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published by
11@@ -34,7 +34,6 @@
12 StateSaverBackend::StateSaverBackend(QObject *parent)
13 : QObject(parent)
14 , m_archive(0)
15- , m_globalEnabled(true)
16 {
17 // connect to application quit signal so when that is called, we can clean the states saved
18 QObject::connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit,
19@@ -54,6 +53,12 @@
20 UnixSignalHandler::instance().connectSignal(UnixSignalHandler::Interrupt);
21 QObject::connect(&UnixSignalHandler::instance(), SIGNAL(signalTriggered(int)),
22 this, SLOT(signalHandler(int)));
23+
24+ // check arguments the application is launched with
25+ if (!waitForStateRestored()) {
26+ // need to reset the states file
27+ reset();
28+ }
29 }
30
31 StateSaverBackend::~StateSaverBackend()
32@@ -100,7 +105,11 @@
33 void StateSaverBackend::cleanup()
34 {
35 reset();
36- m_archive.clear();
37+ // remove file as well
38+ if (m_archive) {
39+ QFile archiveFile(m_archive.data()->fileName());
40+ archiveFile.remove();
41+ }
42 }
43
44 void StateSaverBackend::signalHandler(int type)
45@@ -114,21 +123,6 @@
46 QCoreApplication::quit();
47 }
48
49-bool StateSaverBackend::enabled() const
50-{
51- return m_globalEnabled;
52-}
53-void StateSaverBackend::setEnabled(bool enabled)
54-{
55- if (m_globalEnabled != enabled) {
56- m_globalEnabled = enabled;
57- Q_EMIT enabledChanged(m_globalEnabled);
58- if (!m_globalEnabled) {
59- reset();
60- }
61- }
62-}
63-
64 bool StateSaverBackend::registerId(const QString &id)
65 {
66 if (m_register.contains(id)) {
67@@ -193,6 +187,10 @@
68 if (restorePreviousGroup) {
69 m_archive->beginGroup(m_groupStack.pop());
70 }
71+ // if the archive got empty, emit completed()
72+ if (m_archive->allKeys().isEmpty()) {
73+ Q_EMIT completed();
74+ }
75 return result;
76 }
77
78@@ -233,14 +231,35 @@
79 /*
80 * The method resets the register and the state archive for the application.
81 */
82-bool StateSaverBackend::reset()
83+void StateSaverBackend::reset()
84 {
85 m_register.clear();
86 if (m_archive) {
87+ m_archive->clear();
88+ m_archive->sync();
89+ // trunkate the file
90 QFile archiveFile(m_archive.data()->fileName());
91- return archiveFile.remove();
92+ if (archiveFile.exists() && archiveFile.open(QFile::ReadOnly | QFile::Truncate)) {
93+ archiveFile.close();
94+ }
95+ }
96+}
97+
98+/*
99+ * The method returns the state database state.
100+ */
101+bool StateSaverBackend::isDatabaseEmpty()
102+{
103+ return !m_archive || m_archive->allKeys().isEmpty();
104+}
105+
106+bool StateSaverBackend::waitForStateRestored()
107+{
108+ QStringList args = QCoreApplication::arguments();
109+ Q_FOREACH(const QString &argument, args) {
110+ if (argument.startsWith("--uri")) {
111+ return false;
112+ }
113 }
114 return true;
115 }
116-
117-
118
119=== modified file 'modules/Ubuntu/Components/plugin/statesaverbackend_p.h'
120--- modules/Ubuntu/Components/plugin/statesaverbackend_p.h 2014-02-13 10:21:49 +0000
121+++ modules/Ubuntu/Components/plugin/statesaverbackend_p.h 2015-04-17 07:52:46 +0000
122@@ -1,5 +1,5 @@
123 /*
124- * Copyright 2013 Canonical Ltd.
125+ * Copyright 2015 Canonical Ltd.
126 *
127 * This program is free software; you can redistribute it and/or modify
128 * it under the terms of the GNU Lesser General Public License as published by
129@@ -37,21 +37,22 @@
130 return instance;
131 }
132
133- bool enabled() const;
134- void setEnabled(bool enabled);
135-
136 bool registerId(const QString &id);
137 void removeId(const QString &id);
138
139 int load(const QString &id, QObject *item, const QStringList &properties);
140 int save(const QString &id, QObject *item, const QStringList &properties);
141
142+ bool isDatabaseEmpty();
143+ static bool waitForStateRestored();
144+
145 public Q_SLOTS:
146- bool reset();
147+ void reset();
148
149 Q_SIGNALS:
150 void enabledChanged(bool enabled);
151 void initiateStateSaving();
152+ void completed();
153
154 protected:
155 explicit StateSaverBackend(QObject *parent = 0);
156@@ -65,7 +66,6 @@
157 QPointer<QSettings> m_archive;
158 QSet<QString> m_register;
159 QStack<QString> m_groupStack;
160- bool m_globalEnabled;
161 };
162
163 #endif // STATESAVERBACKEND_P_H
164
165=== modified file 'modules/Ubuntu/Components/plugin/ucstatesaver.cpp'
166--- modules/Ubuntu/Components/plugin/ucstatesaver.cpp 2015-03-03 13:47:48 +0000
167+++ modules/Ubuntu/Components/plugin/ucstatesaver.cpp 2015-04-17 07:52:46 +0000
168@@ -1,5 +1,5 @@
169 /*
170- * Copyright 2013 Canonical Ltd.
171+ * Copyright 2015 Canonical Ltd.
172 *
173 * This program is free software; you can redistribute it and/or modify
174 * it under the terms of the GNU Lesser General Public License as published by
175@@ -66,7 +66,7 @@
176 */
177 void UCStateSaverAttachedPrivate::_q_save()
178 {
179- if (m_enabled && StateSaverBackend::instance().enabled() && !m_properties.isEmpty() && !m_absoluteId.isEmpty()) {
180+ if (m_enabled && !m_properties.isEmpty() && !m_absoluteId.isEmpty()) {
181 StateSaverBackend::instance().save(m_absoluteId, m_attachee, m_properties);
182 }
183 }
184@@ -154,9 +154,10 @@
185 * \note The application name must be set correctly to the package name so that
186 * state saving can work (e.g. com.ubuntu.calendar) through \l MainView::applicationName.
187 *
188- * States saved are discarded when the application is closed properly. The state
189- * loading is ignored (but not discarded) when the application is launched through
190- * UriHandler.
191+ * States saved are discarded when the application is closed properly, as well as
192+ * when the application is launched by the url-dispatcher and the application's
193+ * desktop Exec line contains \c {--uri=%u} argument passing.
194+ * \sa UriHandler
195 *
196 * Example:
197 * \qml
198@@ -280,9 +281,7 @@
199 if (d->m_enabled != v) {
200 d->m_enabled = v;
201 // make sure next time we sync properties
202- if (StateSaverBackend::instance().enabled()) {
203- d->watchComponent(d->m_enabled);
204- }
205+ d->watchComponent(d->m_enabled);
206 Q_EMIT enabledChanged();
207 }
208 }
209@@ -292,7 +291,7 @@
210 * List of properties to be serialized, separated with commas. Properties must be
211 * writable and can only be \l{http://qt-project.org/doc/qt-5.0/qtqml/qtqml-typesystem-basictypes.html}{QML base types}.
212 *
213- * A custom singl eline input which saves the text, polaceholderText, font and color would look as follows:
214+ * A custom single line input which saves the text, paceholderText, font and color would look as follows:
215 * \qml
216 * TextField {
217 * id: input
218
219=== modified file 'modules/Ubuntu/Components/plugin/ucurihandler.cpp'
220--- modules/Ubuntu/Components/plugin/ucurihandler.cpp 2014-10-08 20:16:03 +0000
221+++ modules/Ubuntu/Components/plugin/ucurihandler.cpp 2015-04-17 07:52:46 +0000
222@@ -1,5 +1,5 @@
223 /*
224- * Copyright 2013 Canonical Ltd.
225+ * Copyright 2015 Canonical Ltd.
226 *
227 * This program is free software; you can redistribute it and/or modify
228 * it under the terms of the GNU Lesser General Public License as published by
229@@ -24,13 +24,27 @@
230
231 UriHandlerObject::UriHandlerObject(UCUriHandler* uriHandler)
232 : m_uriHandler(uriHandler)
233+ , m_cacheUris(false)
234 {
235 }
236
237 void UriHandlerObject::Open(const QStringList& uris, const QHash<QString, QVariant>& platformData)
238 {
239 Q_UNUSED(platformData);
240- Q_EMIT m_uriHandler->opened(uris);
241+ m_uris << uris;
242+ if (!m_cacheUris) {
243+ Q_EMIT m_uriHandler->opened(uris);
244+ }
245+}
246+
247+// slot called when statesaver ends its work
248+void UriHandlerObject::handOverCachedUris()
249+{
250+ m_cacheUris = false;
251+ disconnect(&StateSaverBackend::instance(), &StateSaverBackend::completed,
252+ this, &UriHandlerObject::handOverCachedUris);
253+ // emit all cached URIs
254+ Q_EMIT m_uriHandler->opened(m_uris);
255 }
256
257 /*!
258@@ -53,6 +67,13 @@
259 * onOpened: print(uris)
260 * }
261 * \endqml
262+ *
263+ * \section2 Interaction with StateSaver
264+ * When application uses StateSaver to save property states, UriHandler will deliver
265+ * the URIs only after StateSaver restores the last state of the application. This
266+ * can be overruled by specifying the \c {--uri=%u} argument in Exec line of the
267+ * application's desktop file. If that is specified, states will not be loaded
268+ * at all, and will be lost, URIs will be delivered as they come.
269 */
270 UCUriHandler::UCUriHandler()
271 : m_uriHandlerObject(this)
272@@ -84,6 +105,21 @@
273
274 QDBusConnection::sessionBus().registerObject(
275 objectPath, &m_uriHandlerObject, QDBusConnection::ExportAllSlots);
276+
277+ // if the app was launched with --uri= argument, we do not have to queue
278+ // URLs, otherwise yes
279+ if (StateSaverBackend::waitForStateRestored()) {
280+ // connect to completed signal
281+ m_uriHandlerObject.m_cacheUris = true;
282+ connect(&StateSaverBackend::instance(), &StateSaverBackend::completed,
283+ &m_uriHandlerObject, &UriHandlerObject::handOverCachedUris);
284+ // feed URIs
285+ Q_FOREACH(QString arg, QCoreApplication::arguments()) {
286+ if (arg.startsWith(QStringLiteral("--uri="))) {
287+ m_uriHandlerObject.m_uris << arg.remove(QStringLiteral("--uri="));
288+ }
289+ }
290+ }
291 }
292
293 /*!
294
295=== modified file 'modules/Ubuntu/Components/plugin/ucurihandler.h'
296--- modules/Ubuntu/Components/plugin/ucurihandler.h 2013-09-27 20:21:01 +0000
297+++ modules/Ubuntu/Components/plugin/ucurihandler.h 2015-04-17 07:52:46 +0000
298@@ -1,5 +1,5 @@
299 /*
300- * Copyright 2013 Canonical Ltd.
301+ * Copyright 2015 Canonical Ltd.
302 *
303 * This program is free software; you can redistribute it and/or modify
304 * it under the terms of the GNU Lesser General Public License as published by
305@@ -17,6 +17,7 @@
306 */
307
308 #include <QtCore/QObject>
309+#include <QtCore/QStringList>
310
311 class UCUriHandler;
312
313@@ -30,9 +31,13 @@
314
315 public Q_SLOTS:
316 void Open(const QStringList& uris, const QHash<QString, QVariant>& platformData);
317+ void handOverCachedUris();
318
319 private:
320 UCUriHandler* m_uriHandler;
321+ QStringList m_uris;
322+ bool m_cacheUris:1;
323+ friend class UCUriHandler;
324 };
325
326 class UCUriHandler : public QObject
327
328=== added file 'tests/unit_x11/tst_statesaver/UriHandlerApp.qml'
329--- tests/unit_x11/tst_statesaver/UriHandlerApp.qml 1970-01-01 00:00:00 +0000
330+++ tests/unit_x11/tst_statesaver/UriHandlerApp.qml 2015-04-17 07:52:46 +0000
331@@ -0,0 +1,41 @@
332+/*
333+ * Copyright 2015 Canonical Ltd.
334+ *
335+ * This program is free software; you can redistribute it and/or modify
336+ * it under the terms of the GNU Lesser General Public License as published by
337+ * the Free Software Foundation; version 3.
338+ *
339+ * This program is distributed in the hope that it will be useful,
340+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
341+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
342+ * GNU Lesser General Public License for more details.
343+ *
344+ * You should have received a copy of the GNU Lesser General Public License
345+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
346+ */
347+
348+import QtQuick 2.4
349+import Ubuntu.Components 1.2
350+
351+Item {
352+ id: testItem
353+ width: units.gu(40)
354+ height: units.gu(40)
355+
356+ property string testProperty: "yoho"
357+ property bool completed: false
358+
359+ Component.onCompleted: {
360+ completed = true;
361+ testProperty = "me hardies!";
362+ }
363+
364+ Connections {
365+ target: UriHandler
366+ onOpened: {
367+ console.error("URI=", uris);
368+ console.error("completed=", testItem.completed);
369+ console.error("testProperty=", testProperty);
370+ }
371+ }
372+}
373
374=== modified file 'tests/unit_x11/tst_statesaver/tst_statesaver.cpp'
375--- tests/unit_x11/tst_statesaver/tst_statesaver.cpp 2015-01-29 14:15:41 +0000
376+++ tests/unit_x11/tst_statesaver/tst_statesaver.cpp 2015-04-17 07:52:46 +0000
377@@ -1,5 +1,5 @@
378 /*
379- * Copyright 2013 Canonical Ltd.
380+ * Copyright 2015 Canonical Ltd.
381 *
382 * This program is free software; you can redistribute it and/or modify
383 * it under the terms of the GNU Lesser General Public License as published by
384@@ -604,6 +604,38 @@
385 // clean the file
386 QFile::remove(fileName);
387 }
388+
389+ void test_uri_handler()
390+ {
391+ qputenv("APP_ID", "UriHandlerApp");
392+ QProcess testApp;
393+ testApp.start("qmlscene",QStringList() << "-I" << UBUNTU_QML_IMPORT_PATH << "UriHandlerApp.qml");
394+ testApp.waitForStarted();
395+ QTest::qWait(1000);
396+
397+ // make sure we are not killing the parent
398+ QVERIFY(testApp.pid() != QCoreApplication::applicationPid());
399+ // skip tests if the application PID is zero => the child app PID seems to be zero as well
400+ if (!testApp.pid()) {
401+ // kill child process
402+ testApp.close();
403+ QSKIP("This test requires valid PID");
404+ }
405+ // send SIGINT
406+ ::kill(testApp.pid(), SIGINT);
407+ testApp.waitForFinished();
408+
409+ // launch the app with --uri argument
410+ testApp.start("qmlscene",QStringList() << "-I" << UBUNTU_QML_IMPORT_PATH << "--uri=whatever.org" << "UriHandlerApp.qml");
411+ testApp.waitForStarted();
412+ QTest::qWait(2000);
413+
414+ QString result = testApp.readAllStandardError();
415+ // terminate the app
416+ testApp.terminate();
417+ testApp.waitForFinished();
418+ QCOMPARE(result, QString("qml: URI= whatever.org\nqml: completed= false\nqml: testProperty= me hardies!\n"));
419+ }
420 };
421
422 QTEST_MAIN(tst_StateSaverTest)
423
424=== modified file 'tests/unit_x11/tst_statesaver/tst_statesaver.pro'
425--- tests/unit_x11/tst_statesaver/tst_statesaver.pro 2014-07-28 14:46:19 +0000
426+++ tests/unit_x11/tst_statesaver/tst_statesaver.pro 2015-04-17 07:52:46 +0000
427@@ -27,4 +27,5 @@
428 ListViewItems.qml \
429 GridViewItems.qml \
430 NormalAppClose.qml \
431- SaveEnum.qml
432+ SaveEnum.qml \
433+ UriHandlerApp.qml

Subscribers

People subscribed via source and target branches