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 on 2015-04-16

test added, more to come

1480. By Zsombor Egri on 2015-04-17

staging merge

Unmerged revisions

1480. By Zsombor Egri on 2015-04-17

staging merge

1479. By Zsombor Egri on 2015-04-16

test added, more to come

1478. By Zsombor Egri on 2015-04-16

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