Merge lp:~zsombi/ubuntu-ui-toolkit/other-vibrations into lp:ubuntu-ui-toolkit/rtm
- other-vibrations
- Merge into rtm
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Cris Dywan | ||||
Approved revision: | 1143 | ||||
Merged at revision: | 1142 | ||||
Proposed branch: | lp:~zsombi/ubuntu-ui-toolkit/other-vibrations | ||||
Merge into: | lp:ubuntu-ui-toolkit/rtm | ||||
Diff against target: |
1168 lines (+1014/-9) 17 files modified
components.api (+12/-0) debian/control (+3/-0) modules/Ubuntu/Components/AbstractButton.qml (+1/-1) modules/Ubuntu/Components/plugin/adapters/dbuspropertywatcher_p.cpp (+226/-0) modules/Ubuntu/Components/plugin/adapters/dbuspropertywatcher_p.h (+55/-0) modules/Ubuntu/Components/plugin/plugin.cpp (+2/-0) modules/Ubuntu/Components/plugin/plugin.pro (+7/-2) modules/Ubuntu/Components/plugin/ucserviceproperties.cpp (+317/-0) modules/Ubuntu/Components/plugin/ucserviceproperties.h (+83/-0) modules/Ubuntu/Components/plugin/ucserviceproperties_p.h (+53/-0) tests/unit/runtest.sh (+5/-5) tests/unit_x11/tst_serviceproperties/IncomingCallVibrateWatcher.qml (+31/-0) tests/unit_x11/tst_serviceproperties/InvalidPropertyWatcher.qml (+31/-0) tests/unit_x11/tst_serviceproperties/InvalidPropertyWatcher2.qml (+32/-0) tests/unit_x11/tst_serviceproperties/tst_serviceproperties.cpp (+146/-0) tests/unit_x11/tst_serviceproperties/tst_serviceproperties.pro (+8/-0) tests/unit_x11/unit_x11.pro (+2/-1) |
||||
To merge this branch: | bzr merge lp:~zsombi/ubuntu-ui-toolkit/other-vibrations | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Cris Dywan | Approve | ||
Jonas G. Drange (community) | Needs Information | ||
Review via email: mp+242404@code.launchpad.net |
Commit message
isHapticsFeedba
Description of the change
Zsombor Egri (zsombi) wrote : | # |
Jonas G. Drange (jonas-drange) wrote : | # |
Looks good, but I have added a couple of comments concerning names.
Cris Dywan (kalikiana) wrote : | # |
Some comments with ideas to make the API simpler, and some concerns on the sync bits and eror handling. If we use this for more in the near future it's probably worth making it more robust even if it's for now internal.
84 +void DBusPropertyWat
100 +QVariant DBusPropertyWat
117 +bool DBusPropertyWat
Sync isn't nice. By the looks of it, it's handy for testing - thing is, you're not actually testing the production code paths so you're not doing yourself a favor in the end.
What I'd like suggest is: a default value is given. the current property is read async after setup. the value is cached so read can be sync. write is async always. success can be seen in an error property & signal. the new value will be reflected by the propertiesChanged.
If we want multiple properties we can make that a list of names and defaults, and asking for something other than what you specified will be an error, giving you extra safety even if you're making a typo on the consumer side.
I'll be happy to look into the testing approach based on all-async.
This also automatically makes a QML-able API if we want it that looks and feels similar to "Binding".
163 +void DBusPropertyWat
This needs to warn if the object name is invalid.
I presume we also need error handling for connect().
9 + if (isHapticsFeedb
As an idea, by simplifying the API a bit we could use DBusWatcher in QML and avoid the context property. Or we could have a little internal "settings" object if we re-use it in the future.
Zsombor Egri (zsombi) wrote : | # |
> Looks good, but I have added a couple of comments concerning names.
Thanks for the comments, I tried to reply inline, hopefully it'll get in.
Zsombor Egri (zsombi) wrote : | # |
Jonas, looks like replying to an inline-comitter comment does not land with the reply to the inline comments...
Zsombor Egri (zsombi) wrote : | # |
> Some comments with ideas to make the API simpler, and some concerns on the
> sync bits and eror handling. If we use this for more in the near future it's
> probably worth making it more robust even if it's for now internal.
>
> 84 +void DBusPropertyWat
> &serviceInterface)
> 100 +QVariant DBusPropertyWat
> const QString &property)
> 117 +bool DBusPropertyWat
> const QString &property, const QVariant &value)
>
> Sync isn't nice. By the looks of it, it's handy for testing - thing is, you're
> not actually testing the production code paths so you're not doing yourself a
> favor in the end.
The first one (syncProperties) initiates reading of the watched properties. Yet synchronously. Calls the readProperty() for each watched property, so if we have async read, we will get this async as well. Anyway, the property values read are reported by propertyChanged() signal.
Even if we'd have read/write async, we may want also to keep the sync version of them. And yes, error codes/messages we receive from DBus should be exported, so that part we must also add.
>
> What I'd like suggest is: a default value is given. the current property is
> read async after setup. the value is cached so read can be sync. write is
> async always. success can be seen in an error property & signal. the new value
> will be reflected by the propertiesChanged.
Yep, I agree on this. So far the default is like that, just the current values are read synchronously. Yet we only use write in testing, and tbh the only reason I added the writeProperty() was to be able to test the watching functionality, as I wanted to have a module test which is not DBus-agnostic, and uses the same connection/
> If we want multiple properties we can make that a list of names and defaults,
> and asking for something other than what you specified will be an error,
> giving you extra safety even if you're making a typo on the consumer side.
I'm not sure the intention of DBusWatcher was that. The SystemSettings otoh keeps the defaults and initiates the watcher(s) to get the correct settings - yet we have only one watcher, for the accounts, but we could have more. Each service watcher can watch for several properties on the same service interface, but all defaults are handled in the SystemSettings.
>
> I'll be happy to look into the testing approach based on all-async.
Thanks, but I'd not have any CPO yet for this, as it's more like an internal component.
>
> This also automatically makes a QML-able API if we want it that looks and
> feels similar to "Binding".
Aaah, now I get why you want to see a default in the watcher. In that case, yes, it would be beneficial to have a default on that level.
>
> 163 +void DBusPropertyWat
>
> This needs to warn if the object name is invalid.
> I presume we also need error handling for connect...
- 1142. By Zsombor Egri
-
API changed
Cris Dywan (kalikiana) wrote : | # |
64 +#define DYNAMIC_PROPERTY "__q_proeprty"
81 + // crear all previous connections
914 + property bool thisIsAndInvali
Typos.
Also, can we test with valid *and* invalid? To make sure the error won't be overridden by the valid one. From the code it doesn't seem to stop the loop in that case at least.
Zsombor Egri (zsombi) wrote : | # |
> 64 +#define DYNAMIC_PROPERTY "__q_proeprty"
> 81 + // crear all previous connections
> 914 + property bool thisIsAndInvali
>
> Typos.
Ups... I should have an ibus filter which fixes proeprty, teh and si (is) typos :D
>
> Also, can we test with valid *and* invalid? To make sure the error won't be
> overridden by the valid one. From the code it doesn't seem to stop the loop in
> that case at least.
Yes, I will add one. The error will not be cleared ever if there was an error set. So a valid property won't clear the previous invalid property reported.
- 1143. By Zsombor Egri
-
review comments applied
Cris Dywan (kalikiana) wrote : | # |
Thanks for taking my comments into account. Looking nice now!
- 1144. By Zsombor Egri
-
test and launch updates
- 1145. By Zsombor Egri
-
adding build dependencies
- 1146. By Zsombor Egri
-
rtm merge
- 1147. By Zsombor Egri
-
typo fixed
- 1148. By Zsombor Egri
-
one more typo
Preview Diff
1 | === modified file 'components.api' |
2 | --- components.api 2014-11-07 13:39:31 +0000 |
3 | +++ components.api 2015-02-04 14:00:19 +0000 |
4 | @@ -915,6 +915,18 @@ |
5 | Signal { |
6 | name: "sourceChanged" |
7 | Parameter { type: "QUrl" } |
8 | + name: "UCServiceProperties" |
9 | + prototype: "QObject" |
10 | + exports: ["ServiceProperties 1.1"] |
11 | + name: "ServiceType" |
12 | + name: "Status" |
13 | + Property { name: "type"; revision: 1; type: "ServiceType" } |
14 | + Property { name: "service"; revision: 1; type: "string" } |
15 | + Property { name: "path"; revision: 1; type: "string" } |
16 | + Property { name: "serviceInterface"; revision: 1; type: "string" } |
17 | + Property { name: "adaptorInterface"; revision: 1; type: "string" } |
18 | + Property { name: "error"; revision: 1; type: "string"; isReadonly: true } |
19 | + Property { name: "status"; revision: 1; type: "Status"; isReadonly: true } |
20 | name: "UCStateSaver" |
21 | prototype: "QObject" |
22 | exports: ["StateSaver 0.1", "StateSaver 1.0"] |
23 | |
24 | === modified file 'debian/control' |
25 | --- debian/control 2014-10-16 11:21:39 +0000 |
26 | +++ debian/control 2015-02-04 14:00:19 +0000 |
27 | @@ -37,6 +37,9 @@ |
28 | language-pack-en-base, |
29 | libdbus-1-dev, |
30 | libnih-dbus-dev, |
31 | + dbus, |
32 | + dbus-test-runner, |
33 | + accountsservice, |
34 | xvfb, |
35 | libgl1-mesa-dri, |
36 | locales, |
37 | |
38 | === modified file 'modules/Ubuntu/Components/AbstractButton.qml' |
39 | --- modules/Ubuntu/Components/AbstractButton.qml 2014-09-02 05:52:32 +0000 |
40 | +++ modules/Ubuntu/Components/AbstractButton.qml 2015-02-04 14:00:19 +0000 |
41 | @@ -104,7 +104,7 @@ |
42 | |
43 | onClicked: { |
44 | if (button.__acceptEvents) { |
45 | - pressEffect.start() |
46 | + pressEffect.start(); |
47 | button.clicked() |
48 | } |
49 | } |
50 | |
51 | === added file 'modules/Ubuntu/Components/plugin/adapters/dbuspropertywatcher_p.cpp' |
52 | --- modules/Ubuntu/Components/plugin/adapters/dbuspropertywatcher_p.cpp 1970-01-01 00:00:00 +0000 |
53 | +++ modules/Ubuntu/Components/plugin/adapters/dbuspropertywatcher_p.cpp 2015-02-04 14:00:19 +0000 |
54 | @@ -0,0 +1,226 @@ |
55 | +/* |
56 | + * Copyright 2014 Canonical Ltd. |
57 | + * |
58 | + * This program is free software; you can redistribute it and/or modify |
59 | + * it under the terms of the GNU Lesser General Public License as published by |
60 | + * the Free Software Foundation; version 3. |
61 | + * |
62 | + * This program is distributed in the hope that it will be useful, |
63 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
64 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
65 | + * GNU Lesser General Public License for more details. |
66 | + * |
67 | + * You should have received a copy of the GNU Lesser General Public License |
68 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
69 | + */ |
70 | + |
71 | +#include "dbuspropertywatcher_p.h" |
72 | +#include <QtDBus/QDBusReply> |
73 | +#include <unistd.h> |
74 | +#include <sys/types.h> |
75 | +#include "i18n.h" |
76 | +#include <QtQml/QQmlInfo> |
77 | + |
78 | +#define DYNAMIC_PROPERTY "__q_property" |
79 | + |
80 | +UCServicePropertiesPrivate *createServicePropertiesAdapter(UCServiceProperties *owner) |
81 | +{ |
82 | + return new DBusServiceProperties(owner); |
83 | +} |
84 | + |
85 | +DBusServiceProperties::DBusServiceProperties(UCServiceProperties *qq) |
86 | + : UCServicePropertiesPrivate(qq) |
87 | + , connection("") |
88 | + , watcher(0) |
89 | + , iface(0) |
90 | +{ |
91 | +} |
92 | + |
93 | +bool DBusServiceProperties::init() |
94 | +{ |
95 | + // crear previous connections |
96 | + setStatus(UCServiceProperties::Inactive); |
97 | + delete iface; |
98 | + iface = 0; |
99 | + delete watcher; |
100 | + watcher = 0; |
101 | + setError(QString()); |
102 | + |
103 | + if (service.isEmpty() || path.isEmpty()) { |
104 | + setStatus(UCServiceProperties::ConnectionError); |
105 | + setError(UbuntuI18n::instance().tr("No service/path specified")); |
106 | + return false; |
107 | + } |
108 | + |
109 | + switch (type) { |
110 | + case UCServiceProperties::System: |
111 | + { |
112 | + connection = QDBusConnection::systemBus(); |
113 | + break; |
114 | + } |
115 | + case UCServiceProperties::Session: |
116 | + { |
117 | + connection = QDBusConnection::sessionBus(); |
118 | + break; |
119 | + } |
120 | + default: |
121 | + { |
122 | + setStatus(UCServiceProperties::ConnectionError); |
123 | + setError(UbuntuI18n::instance().tr("Invalid bus type: %1.").arg(type)); |
124 | + return false; |
125 | + } |
126 | + } |
127 | + |
128 | + Q_Q(UCServiceProperties); |
129 | + // connect dbus watcher to catch OwnerChanged |
130 | + watcher = new QDBusServiceWatcher(service, connection, QDBusServiceWatcher::WatchForOwnerChange, q); |
131 | + // connect interface |
132 | + iface = new QDBusInterface(service, path, interface, connection, q); |
133 | + if (!iface->isValid()) { |
134 | + setStatus(UCServiceProperties::ConnectionError); |
135 | + setError(iface->lastError().message()); |
136 | + return false; |
137 | + } |
138 | + // connect watcher to get owner changes |
139 | + QObject::connect(watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)), |
140 | + this, SLOT(changeServiceOwner(QString,QString,QString))); |
141 | + return setupInterface(); |
142 | +} |
143 | + |
144 | +/* |
145 | + * Connect dbus signal identified by (service, path, iface, name) quaduple to a |
146 | + * slot to receive property changes. |
147 | + */ |
148 | +bool DBusServiceProperties::setupInterface() |
149 | +{ |
150 | + QDBusReply<QDBusObjectPath> dbusObjectPath = iface->call("FindUserById", qlonglong(getuid())); |
151 | + if (dbusObjectPath.isValid()) { |
152 | + objectPath = dbusObjectPath.value().path(); |
153 | + iface->connection().connect( |
154 | + service, |
155 | + objectPath, |
156 | + "org.freedesktop.DBus.Properties", |
157 | + "PropertiesChanged", |
158 | + this, |
159 | + SLOT(updateProperties(QString,QVariantMap,QStringList))); |
160 | + return true; |
161 | + } |
162 | + |
163 | + setStatus(UCServiceProperties::ConnectionError); |
164 | + setError(dbusObjectPath.error().message()); |
165 | + return false; |
166 | +} |
167 | + |
168 | +bool DBusServiceProperties::fetchPropertyValues() |
169 | +{ |
170 | + scannedProperties = properties; |
171 | + Q_FOREACH(QString property, properties) { |
172 | + readProperty(property); |
173 | + } |
174 | + return true; |
175 | +} |
176 | + |
177 | +/* |
178 | + * Reads a property value from the adaptorInterface asynchronously. |
179 | + */ |
180 | +bool DBusServiceProperties::readProperty(const QString &property) |
181 | +{ |
182 | + if ((status < UCServiceProperties::Synchronizing) || objectPath.isEmpty()) { |
183 | + return false; |
184 | + } |
185 | + Q_Q(UCServiceProperties); |
186 | + QDBusInterface readIFace(iface->interface(), objectPath, "org.freedesktop.DBus.Properties", connection); |
187 | + if (!readIFace.isValid()) { |
188 | + // report invalid interface only if the property's first letter was with capital one! |
189 | + if (property[0].isUpper()) { |
190 | + qmlInfo(q) << readIFace.lastError().message(); |
191 | + } |
192 | + return false; |
193 | + } |
194 | + QDBusPendingCall pending = readIFace.asyncCall("Get", adaptor, property); |
195 | + if (pending.isError()) { |
196 | + qmlInfo(q) << pending.error().message(); |
197 | + return false; |
198 | + } |
199 | + QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(pending, q); |
200 | + QObject::connect(callWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), |
201 | + this, SLOT(readFinished(QDBusPendingCallWatcher*))); |
202 | + |
203 | + // set a dynamic property so we know which property are we reading |
204 | + callWatcher->setProperty(DYNAMIC_PROPERTY, property); |
205 | + return true; |
206 | +} |
207 | + |
208 | +/* |
209 | + * Writes a property value to theadaptorInterface synchronously. It is for pure testing purposes. |
210 | + */ |
211 | +bool DBusServiceProperties::testProperty(const QString &property, const QVariant &value) |
212 | +{ |
213 | + if (objectPath.isEmpty()) { |
214 | + return false; |
215 | + } |
216 | + QDBusInterface writeIFace(iface->interface(), objectPath, "org.freedesktop.DBus.Properties", connection); |
217 | + if (!writeIFace.isValid()) { |
218 | + // invalid interface |
219 | + return false; |
220 | + } |
221 | + QDBusMessage msg = writeIFace.call("Set", adaptor, property, QVariant::fromValue(QDBusVariant(value))); |
222 | + return msg.type() == QDBusMessage::ReplyMessage; |
223 | +} |
224 | + |
225 | +/* |
226 | + * Slot called when the async read operation finishes. |
227 | + */ |
228 | +void DBusServiceProperties::readFinished(QDBusPendingCallWatcher *call) |
229 | +{ |
230 | + Q_Q(UCServiceProperties); |
231 | + QDBusPendingReply<QVariant> reply = *call; |
232 | + QString property = call->property(DYNAMIC_PROPERTY).toString(); |
233 | + scannedProperties.removeAll(property); |
234 | + if (reply.isError()) { |
235 | + // remove the property from being watched, as it has no property like that |
236 | + properties.removeAll(property); |
237 | + if (property[0].isUpper()) { |
238 | + // report error! |
239 | + qmlInfo(q) << reply.error().message(); |
240 | + } |
241 | + } else { |
242 | + // update watched property value |
243 | + // make sure we have lower case when the property value is updated |
244 | + property[0] = property[0].toLower(); |
245 | + q->setProperty(property.toLocal8Bit().constData(), reply.value()); |
246 | + } |
247 | + |
248 | + if ((status == UCServiceProperties::Synchronizing) && scannedProperties.isEmpty()) { |
249 | + // set status to active |
250 | + setStatus(UCServiceProperties::Active); |
251 | + } |
252 | + |
253 | + // delete watcher |
254 | + call->deleteLater(); |
255 | +} |
256 | + |
257 | +/* |
258 | + * Slot called when service owner is changed. |
259 | + */ |
260 | +void DBusServiceProperties::changeServiceOwner(const QString &serviceName, const QString &oldOwner, const QString &newOwner) |
261 | +{ |
262 | + Q_UNUSED(oldOwner); |
263 | + Q_UNUSED(newOwner); |
264 | + if (serviceName != service) { |
265 | + return; |
266 | + } |
267 | + setupInterface(); |
268 | +} |
269 | + |
270 | +/* |
271 | + * Slot called when the properties are changed in the service. |
272 | + */ |
273 | +void DBusServiceProperties::updateProperties(const QString &onInterface, const QVariantMap &map, const QStringList &invalidated) |
274 | +{ |
275 | + Q_UNUSED(onInterface); |
276 | + Q_UNUSED(map); |
277 | + Q_FOREACH(const QString &property, invalidated) { |
278 | + readProperty(property); |
279 | + } |
280 | +} |
281 | |
282 | === added file 'modules/Ubuntu/Components/plugin/adapters/dbuspropertywatcher_p.h' |
283 | --- modules/Ubuntu/Components/plugin/adapters/dbuspropertywatcher_p.h 1970-01-01 00:00:00 +0000 |
284 | +++ modules/Ubuntu/Components/plugin/adapters/dbuspropertywatcher_p.h 2015-02-04 14:00:19 +0000 |
285 | @@ -0,0 +1,55 @@ |
286 | +/* |
287 | + * Copyright 2014 Canonical Ltd. |
288 | + * |
289 | + * This program is free software; you can redistribute it and/or modify |
290 | + * it under the terms of the GNU Lesser General Public License as published by |
291 | + * the Free Software Foundation; version 3. |
292 | + * |
293 | + * This program is distributed in the hope that it will be useful, |
294 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
295 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
296 | + * GNU Lesser General Public License for more details. |
297 | + * |
298 | + * You should have received a copy of the GNU Lesser General Public License |
299 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
300 | + */ |
301 | + |
302 | +#ifndef DBUSPROPERTYWATCHER_P_H |
303 | +#define DBUSPROPERTYWATCHER_P_H |
304 | + |
305 | +#include <QtCore/QObject> |
306 | +#include <QtDBus/QDBusConnection> |
307 | +#include <QtDBus/QDBusServiceWatcher> |
308 | +#include <QtDBus/QDBusInterface> |
309 | + |
310 | +#include "ucserviceproperties_p.h" |
311 | + |
312 | +class QDBusPendingCallWatcher; |
313 | +class DBusServiceProperties : public QObject, public UCServicePropertiesPrivate |
314 | +{ |
315 | + Q_OBJECT |
316 | + Q_DECLARE_PUBLIC(UCServiceProperties) |
317 | +public: |
318 | + DBusServiceProperties(UCServiceProperties *qq); |
319 | + |
320 | + bool init(); |
321 | + bool fetchPropertyValues(); |
322 | + bool readProperty(const QString &property); |
323 | + // for testing purposes only!!! |
324 | + bool testProperty(const QString &property, const QVariant &value); |
325 | + |
326 | + QStringList scannedProperties; |
327 | + QDBusConnection connection; |
328 | + QDBusServiceWatcher *watcher; |
329 | + QDBusInterface *iface; |
330 | + QString objectPath; |
331 | + |
332 | + bool setupInterface(); |
333 | + |
334 | +public Q_SLOTS: |
335 | + void readFinished(QDBusPendingCallWatcher *watcher); |
336 | + void changeServiceOwner(const QString &serviceName, const QString &oldOwner, const QString &newOwner); |
337 | + void updateProperties(const QString &iface, const QVariantMap &map, const QStringList &invalidated); |
338 | +}; |
339 | + |
340 | +#endif // DBUSPROPERTYWATCHER_P_H |
341 | |
342 | === modified file 'modules/Ubuntu/Components/plugin/plugin.cpp' |
343 | --- modules/Ubuntu/Components/plugin/plugin.cpp 2014-10-07 14:37:16 +0000 |
344 | +++ modules/Ubuntu/Components/plugin/plugin.cpp 2015-02-04 14:00:19 +0000 |
345 | @@ -52,6 +52,7 @@ |
346 | #include "ucaction.h" |
347 | #include "ucactioncontext.h" |
348 | #include "ucactionmanager.h" |
349 | +#include "ucserviceproperties.h" |
350 | |
351 | #include <sys/types.h> |
352 | #include <unistd.h> |
353 | @@ -162,6 +163,7 @@ |
354 | qmlRegisterType<QSortFilterProxyModelQML>(uri, 1, 1, "SortFilterModel"); |
355 | qmlRegisterUncreatableType<FilterBehavior>(uri, 1, 1, "FilterBehavior", "Not instantiable"); |
356 | qmlRegisterUncreatableType<SortBehavior>(uri, 1, 1, "SortBehavior", "Not instantiable"); |
357 | + qmlRegisterType<UCServiceProperties, 1>(uri, 1, 1, "ServiceProperties"); |
358 | } |
359 | |
360 | void UbuntuComponentsPlugin::initializeEngine(QQmlEngine *engine, const char *uri) |
361 | |
362 | === modified file 'modules/Ubuntu/Components/plugin/plugin.pro' |
363 | --- modules/Ubuntu/Components/plugin/plugin.pro 2014-10-07 14:37:16 +0000 |
364 | +++ modules/Ubuntu/Components/plugin/plugin.pro 2015-02-04 14:00:19 +0000 |
365 | @@ -68,7 +68,10 @@ |
366 | ucaction.h \ |
367 | ucactioncontext.h \ |
368 | ucactionmanager.h \ |
369 | - adapters/actionsproxy_p.h |
370 | + adapters/actionsproxy_p.h \ |
371 | + adapters/dbuspropertywatcher_p.h \ |
372 | + ucserviceproperties.h \ |
373 | + ucserviceproperties_p.h |
374 | |
375 | SOURCES += plugin.cpp \ |
376 | uctheme.cpp \ |
377 | @@ -105,7 +108,9 @@ |
378 | ucaction.cpp \ |
379 | ucactioncontext.cpp \ |
380 | ucactionmanager.cpp \ |
381 | - adapters/actionsproxy_p.cpp |
382 | + adapters/actionsproxy_p.cpp \ |
383 | + adapters/dbuspropertywatcher_p.cpp \ |
384 | + ucserviceproperties.cpp |
385 | |
386 | # adapters |
387 | SOURCES += adapters/alarmsadapter_organizer.cpp |
388 | |
389 | === added file 'modules/Ubuntu/Components/plugin/ucserviceproperties.cpp' |
390 | --- modules/Ubuntu/Components/plugin/ucserviceproperties.cpp 1970-01-01 00:00:00 +0000 |
391 | +++ modules/Ubuntu/Components/plugin/ucserviceproperties.cpp 2015-02-04 14:00:19 +0000 |
392 | @@ -0,0 +1,317 @@ |
393 | +/* |
394 | + * Copyright 2014 Canonical Ltd. |
395 | + * |
396 | + * This program is free software; you can redistribute it and/or modify |
397 | + * it under the terms of the GNU Lesser General Public License as published by |
398 | + * the Free Software Foundation; version 3. |
399 | + * |
400 | + * This program is distributed in the hope that it will be useful, |
401 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
402 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
403 | + * GNU Lesser General Public License for more details. |
404 | + * |
405 | + * You should have received a copy of the GNU Lesser General Public License |
406 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
407 | + */ |
408 | + |
409 | +#include "ucserviceproperties.h" |
410 | +#include "ucserviceproperties_p.h" |
411 | +#include "i18n.h" |
412 | +#include <QtQml/QQmlInfo> |
413 | +#include <QtCore/QMetaProperty> |
414 | +#include <QtQml/QQmlProperty> |
415 | +#include <QtQml/private/qqmlproperty_p.h> |
416 | + |
417 | +UCServicePropertiesPrivate::UCServicePropertiesPrivate(UCServiceProperties *qq) |
418 | + : q_ptr(qq) |
419 | + , ready(false) |
420 | + , status(UCServiceProperties::Inactive) |
421 | + , type(UCServiceProperties::System) |
422 | +{ |
423 | +} |
424 | + |
425 | +UCServicePropertiesPrivate::~UCServicePropertiesPrivate() |
426 | +{ |
427 | +} |
428 | + |
429 | +UCServicePropertiesPrivate *UCServicePropertiesPrivate::get(UCServiceProperties *service) |
430 | +{ |
431 | + return service->d_func(); |
432 | +} |
433 | + |
434 | +void UCServicePropertiesPrivate::setError(const QString &msg) |
435 | +{ |
436 | + if (error == msg) { |
437 | + return; |
438 | + } |
439 | + error = msg; |
440 | + Q_EMIT q_ptr->errorChanged(); |
441 | +} |
442 | + |
443 | +void UCServicePropertiesPrivate::setStatus(UCServiceProperties::Status status) |
444 | +{ |
445 | + if (this->status == status) { |
446 | + return; |
447 | + } |
448 | + this->status = status; |
449 | + Q_EMIT q_ptr->statusChanged(); |
450 | +} |
451 | + |
452 | +void printLocked(UCServiceProperties *owner) |
453 | +{ |
454 | + qmlInfo(owner) << UbuntuI18n::instance().tr("Changing connection parameters forbidden."); |
455 | +} |
456 | + |
457 | +/*! |
458 | + * \qmltype ServiceProperties |
459 | + * \instantiates UCServiceProperties |
460 | + * \inqmlmodule Ubuntu.Components 1.1 |
461 | + * \since Ubuntu.Components 1.1 |
462 | + * \ingroup ubuntu-services |
463 | + * \brief The component enables accessing service properties from QML. |
464 | + * |
465 | + * The services accessed by the component are ones providing their interfaces |
466 | + * through DBus. The component is specialized to read properties exposed by these |
467 | + * services, andf to keep these property values up to date. It is not meant to |
468 | + * access signals or slots exposed, nor to change the values of the properties |
469 | + * watched. |
470 | + * |
471 | + * Properties watched should be declared within the body of the component like |
472 | + * any other QML property, preferably defining a default value for them. The component |
473 | + * will enumerate these properties and will ask the service to provide values for |
474 | + * those. When enumerating properties, each property will be checked twice, with |
475 | + * the case specified as well as with the first letter capitalized. |
476 | + * \qml |
477 | + * import QtQuick 2.3 |
478 | + * import Ubuntu.Components 1.1 |
479 | + * |
480 | + * ServiceProperties { |
481 | + * service: "org.freenode.AccountsService" |
482 | + * path: "/org/freenode/AccountsService" |
483 | + * serviceInterface: "org.freenode.AccountsService" |
484 | + * adaptorInterface: "com.ubuntu.touch.Accounts.Sound" |
485 | + * // listing properties to watch |
486 | + * // each property name existence will be checked against the current case |
487 | + * // as well as with first character capitalized |
488 | + * property bool incomingCallVibrate: true |
489 | + * } |
490 | + * \endqml |
491 | + * |
492 | + * Note that there are few properties which must be set in order the component |
493 | + * to work. These are \l service, \l path and \l adaptorInterface. Also, once |
494 | + * specified, \l service, \l serviceInterface and \l adaptorInterface values |
495 | + * should not be changed as it cannot be guaranteed that properties watched will |
496 | + * be available on those service. Therefore any change on these properties after |
497 | + * the component completion will be ignored. Property bindings on properties |
498 | + * watched will be ignored as well, as service will report changes in these property |
499 | + * values. |
500 | + * |
501 | + * The service is connected once the component gets completed (Component.onCompleted). |
502 | + * The \l error property specifies any error occured during connection, and the |
503 | + * \l status property notifies whether the connection to the service is active or not. |
504 | + * |
505 | + * \note Pay attention when chosing the service watched, and set your application's |
506 | + * AppArmor rights to ensure a successful service connection. |
507 | + */ |
508 | +UCServiceProperties::UCServiceProperties(QObject *parent) |
509 | + : QObject(parent) |
510 | + , d_ptr(createServicePropertiesAdapter(this)) |
511 | +{ |
512 | +} |
513 | +UCServiceProperties::~UCServiceProperties() |
514 | +{ |
515 | + delete d_ptr; |
516 | + d_ptr = 0; |
517 | +} |
518 | + |
519 | +void UCServiceProperties::classBegin() |
520 | +{ |
521 | +} |
522 | + |
523 | +void UCServiceProperties::componentComplete() |
524 | +{ |
525 | + Q_D(UCServiceProperties); |
526 | + d->ready = true; |
527 | + // enumerate properties |
528 | + const QMetaObject *mo = metaObject(); |
529 | + for (int i = mo->propertyOffset(); i < mo->propertyCount(); i++) { |
530 | + const QMetaProperty prop = mo->property(i); |
531 | + QString property(prop.name()); |
532 | + |
533 | + // check the binding on the property and warn if there is one. |
534 | + QQmlProperty qmlProperty(this, property); |
535 | + if (QQmlPropertyPrivate::binding(qmlProperty)) { |
536 | + qmlInfo(this) << UbuntuI18n::instance(). |
537 | + tr("Binding detected on property '%1' will be removed by the service updates."). |
538 | + arg(property); |
539 | + } |
540 | + // insert both the declared and capitalized first character properties |
541 | + d->properties << property; |
542 | + property[0] = property[0].toUpper(); |
543 | + d->properties << property; |
544 | + } |
545 | + // initialize DBus |
546 | + if (d->init()) { |
547 | + d->setStatus(UCServiceProperties::Synchronizing); |
548 | + d->fetchPropertyValues(); |
549 | + } |
550 | +} |
551 | + |
552 | +/*! |
553 | + * \qmlproperty enum ServiceProperties::type |
554 | + * Specifies the DBus connection session type. It can get the following values: |
555 | + * \list |
556 | + * \li - \e ServiceProperties.System when system bus is used (default) |
557 | + * \li - \e ServiceProperties.Session when session bus is used |
558 | + * \endlist |
559 | + */ |
560 | +UCServiceProperties::ServiceType UCServiceProperties::type() const |
561 | +{ |
562 | + Q_D(const UCServiceProperties); |
563 | + return d->type; |
564 | +} |
565 | +void UCServiceProperties::setType(ServiceType type) |
566 | +{ |
567 | + Q_D(UCServiceProperties); |
568 | + if (d->type == type) { |
569 | + return; |
570 | + } |
571 | + if (d->ready) { |
572 | + printLocked(this); |
573 | + return; |
574 | + } |
575 | + d->type = type; |
576 | + Q_EMIT typeChanged(); |
577 | +} |
578 | + |
579 | +/*! |
580 | + * \qmlproperty string ServiceProperties::service |
581 | + * The proeprty specifies the DBus service URI. It is mandatory to be specified. |
582 | + */ |
583 | +QString UCServiceProperties::service() const |
584 | +{ |
585 | + Q_D(const UCServiceProperties); |
586 | + return d->service; |
587 | +} |
588 | +void UCServiceProperties::setService(const QString &value) |
589 | +{ |
590 | + Q_D(UCServiceProperties); |
591 | + if (d->service == value) { |
592 | + return; |
593 | + } |
594 | + if (d->ready) { |
595 | + printLocked(this); |
596 | + return; |
597 | + } |
598 | + d->service = value; |
599 | + Q_EMIT serviceChanged(); |
600 | +} |
601 | + |
602 | +/*! |
603 | + * \qmlproperty string ServiceProperties::path |
604 | + * The property specifies the DBus service connection path. It is mandatory to be |
605 | + * specified. |
606 | + */ |
607 | +QString UCServiceProperties::path() const |
608 | +{ |
609 | + Q_D(const UCServiceProperties); |
610 | + return d->path; |
611 | +} |
612 | +void UCServiceProperties::setPath(const QString &value) |
613 | +{ |
614 | + Q_D(UCServiceProperties); |
615 | + if (d->path == value) { |
616 | + return; |
617 | + } |
618 | + d->path = value; |
619 | + Q_EMIT pathChanged(); |
620 | + if (d->ready) { |
621 | + // need to re-initialize connections |
622 | + d->init(); |
623 | + } |
624 | +} |
625 | + |
626 | +/*! |
627 | + * \qmlproperty string ServiceProperties::serviceInterface |
628 | + * The property specifies the service intertface. If it is an empty string, the |
629 | + * component will refer to the merging of all interfaces found in the service. |
630 | + */ |
631 | +QString UCServiceProperties::interface() const |
632 | +{ |
633 | + Q_D(const UCServiceProperties); |
634 | + return d->interface; |
635 | +} |
636 | +void UCServiceProperties::setInterface(const QString &value) |
637 | +{ |
638 | + Q_D(UCServiceProperties); |
639 | + if (d->interface == value) { |
640 | + return; |
641 | + } |
642 | + if (d->ready) { |
643 | + printLocked(this); |
644 | + return; |
645 | + } |
646 | + d->interface = value; |
647 | + Q_EMIT serviceInterfaceChanged(); |
648 | +} |
649 | +/*! |
650 | + * \qmlproperty string ServiceProperties::adaptorInterface |
651 | + * The proeprty specifies the dbus adaptor interface which provides the properties |
652 | + * watched. This can be a different interface that the one specified in \l serviceInterface, |
653 | + * and in the same way, it can be empty, in which case all the properties from all |
654 | + * interfaces of the service will be watched. |
655 | + */ |
656 | +QString UCServiceProperties::adaptor() const |
657 | +{ |
658 | + Q_D(const UCServiceProperties); |
659 | + return d->adaptor; |
660 | +} |
661 | +void UCServiceProperties::setAdaptor(const QString &value) |
662 | +{ |
663 | + Q_D(UCServiceProperties); |
664 | + if (d->adaptor == value) { |
665 | + return; |
666 | + } |
667 | + if (d->ready) { |
668 | + printLocked(this); |
669 | + return; |
670 | + } |
671 | + d->adaptor = value; |
672 | + Q_EMIT adaptorInterfaceChanged(); |
673 | +} |
674 | + |
675 | +/*! |
676 | + * \qmlproperty string ServiceProperties::error |
677 | + * The property is set with a human readablestring each time an error occurrs |
678 | + * during the service connection. Empty string means no error. |
679 | + */ |
680 | +QString UCServiceProperties::error() |
681 | +{ |
682 | + Q_D(UCServiceProperties); |
683 | + return d->error; |
684 | +} |
685 | + |
686 | +/*! |
687 | + * \qmlproperty enum ServiceProperties::status |
688 | + * The property presents the status of the component. |
689 | + * \list |
690 | + * \li - \e ServiceProperties.Inactive - the component is inactive, initial state |
691 | + * \li - \e ServiceProperties.ConnectionError - there was a connection error, the |
692 | + * \l error contains the error string. |
693 | + * \li - \e ServiceProperties.Synchronizing - the connection to the service succeeded, |
694 | + * and the properties are being synchronized; |
695 | + * \li - \e ServiceProperties.Active - the service watcher is active and initial |
696 | + * property synchronization completed. |
697 | + * \endlist |
698 | + * \note While the status is set to \e Synchronizing, the properties are checked |
699 | + * against their existence in the service. Each proeprty will be checked as declared |
700 | + * as well with capital first letter. If neither of these exists in the service, |
701 | + * it will be reported in the \l error property separately. |
702 | + */ |
703 | +UCServiceProperties::Status UCServiceProperties::status() const |
704 | +{ |
705 | + Q_D(const UCServiceProperties); |
706 | + return d->status; |
707 | +} |
708 | + |
709 | +#include "moc_ucserviceproperties.cpp" |
710 | |
711 | === added file 'modules/Ubuntu/Components/plugin/ucserviceproperties.h' |
712 | --- modules/Ubuntu/Components/plugin/ucserviceproperties.h 1970-01-01 00:00:00 +0000 |
713 | +++ modules/Ubuntu/Components/plugin/ucserviceproperties.h 2015-02-04 14:00:19 +0000 |
714 | @@ -0,0 +1,83 @@ |
715 | +/* |
716 | + * Copyright 2014 Canonical Ltd. |
717 | + * |
718 | + * This program is free software; you can redistribute it and/or modify |
719 | + * it under the terms of the GNU Lesser General Public License as published by |
720 | + * the Free Software Foundation; version 3. |
721 | + * |
722 | + * This program is distributed in the hope that it will be useful, |
723 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
724 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
725 | + * GNU Lesser General Public License for more details. |
726 | + * |
727 | + * You should have received a copy of the GNU Lesser General Public License |
728 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
729 | + */ |
730 | + |
731 | +#ifndef UCSERVICEPROPERTIES_H |
732 | +#define UCSERVICEPROPERTIES_H |
733 | + |
734 | +#include <QtCore/QObject> |
735 | +#include <QtQml/QQmlParserStatus> |
736 | + |
737 | +class UCServicePropertiesPrivate; |
738 | +class UCServiceProperties : public QObject, public QQmlParserStatus |
739 | +{ |
740 | + Q_OBJECT |
741 | + Q_INTERFACES(QQmlParserStatus) |
742 | + |
743 | + Q_PROPERTY(ServiceType type READ type WRITE setType NOTIFY typeChanged REVISION 1) |
744 | + Q_PROPERTY(QString service READ service WRITE setService NOTIFY serviceChanged REVISION 1) |
745 | + Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged REVISION 1) |
746 | + Q_PROPERTY(QString serviceInterface READ interface WRITE setInterface NOTIFY serviceInterfaceChanged REVISION 1) |
747 | + Q_PROPERTY(QString adaptorInterface READ adaptor WRITE setAdaptor NOTIFY adaptorInterfaceChanged REVISION 1) |
748 | + Q_PROPERTY(QString error READ error NOTIFY errorChanged REVISION 1) |
749 | + Q_PROPERTY(Status status READ status NOTIFY statusChanged REVISION 1) |
750 | + |
751 | + Q_ENUMS(ServiceType Status) |
752 | +public: |
753 | + enum ServiceType { |
754 | + Undefined, |
755 | + System, |
756 | + Session |
757 | + }; |
758 | + enum Status { |
759 | + Inactive, |
760 | + ConnectionError, |
761 | + Synchronizing, |
762 | + Active |
763 | + }; |
764 | + |
765 | + explicit UCServiceProperties(QObject *parent = 0); |
766 | + ~UCServiceProperties(); |
767 | + void classBegin(); |
768 | + void componentComplete(); |
769 | + |
770 | + ServiceType type() const; |
771 | + void setType(ServiceType type); |
772 | + QString service() const; |
773 | + void setService(const QString &value); |
774 | + QString path() const; |
775 | + void setPath(const QString &value); |
776 | + QString interface() const; |
777 | + void setInterface(const QString &value); |
778 | + QString adaptor() const; |
779 | + void setAdaptor(const QString &value); |
780 | + QString error(); |
781 | + Status status() const; |
782 | + |
783 | +Q_SIGNALS: |
784 | + void typeChanged(); |
785 | + void serviceChanged(); |
786 | + void pathChanged(); |
787 | + void serviceInterfaceChanged(); |
788 | + void adaptorInterfaceChanged(); |
789 | + void errorChanged(); |
790 | + void statusChanged(); |
791 | + |
792 | +private: |
793 | + UCServicePropertiesPrivate *d_ptr; |
794 | + Q_DECLARE_PRIVATE_D(d_ptr, UCServiceProperties) |
795 | +}; |
796 | + |
797 | +#endif // UCSERVICEPROPERTIES_H |
798 | |
799 | === added file 'modules/Ubuntu/Components/plugin/ucserviceproperties_p.h' |
800 | --- modules/Ubuntu/Components/plugin/ucserviceproperties_p.h 1970-01-01 00:00:00 +0000 |
801 | +++ modules/Ubuntu/Components/plugin/ucserviceproperties_p.h 2015-02-04 14:00:19 +0000 |
802 | @@ -0,0 +1,53 @@ |
803 | +/* |
804 | + * Copyright 2014 Canonical Ltd. |
805 | + * |
806 | + * This program is free software; you can redistribute it and/or modify |
807 | + * it under the terms of the GNU Lesser General Public License as published by |
808 | + * the Free Software Foundation; version 3. |
809 | + * |
810 | + * This program is distributed in the hope that it will be useful, |
811 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
812 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
813 | + * GNU Lesser General Public License for more details. |
814 | + * |
815 | + * You should have received a copy of the GNU Lesser General Public License |
816 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
817 | + */ |
818 | + |
819 | +#ifndef UCSERVICEPROPERTIES_P_H |
820 | +#define UCSERVICEPROPERTIES_P_H |
821 | + |
822 | +#include "ucserviceproperties.h" |
823 | +#include <QtCore/QStringList> |
824 | + |
825 | +class UCServicePropertiesPrivate |
826 | +{ |
827 | +public: |
828 | + UCServicePropertiesPrivate(UCServiceProperties *qq); |
829 | + virtual ~UCServicePropertiesPrivate(); |
830 | + |
831 | + static UCServicePropertiesPrivate *get(UCServiceProperties *service); |
832 | + void setError(const QString &msg); |
833 | + void setStatus(UCServiceProperties::Status status); |
834 | + |
835 | + virtual bool init() = 0; |
836 | + virtual bool fetchPropertyValues() = 0; |
837 | + virtual bool readProperty(const QString &property) = 0; |
838 | + virtual bool testProperty(const QString &property, const QVariant &value) = 0; |
839 | + |
840 | + // data |
841 | + UCServiceProperties *q_ptr; |
842 | + bool ready:1; |
843 | + UCServiceProperties::Status status; |
844 | + UCServiceProperties::ServiceType type; |
845 | + QString service; |
846 | + QString path; |
847 | + QString interface; |
848 | + QString adaptor; |
849 | + QString error; |
850 | + QStringList properties; |
851 | +}; |
852 | + |
853 | +UCServicePropertiesPrivate *createServicePropertiesAdapter(UCServiceProperties *owner); |
854 | + |
855 | +#endif // UCSERVICEPROPERTIES_P_H |
856 | |
857 | === modified file 'tests/unit/runtest.sh' |
858 | --- tests/unit/runtest.sh 2014-09-16 08:19:14 +0000 |
859 | +++ tests/unit/runtest.sh 2015-02-04 14:00:19 +0000 |
860 | @@ -22,18 +22,18 @@ |
861 | _TESTFILE=$2 |
862 | _MINIMAL=$3 |
863 | _XML="../../test_$_TARGET_$_TESTFILE.xml" |
864 | -_ARGS="-o $_XML,xunitxml -o -,txt" |
865 | +_ARGS="-p -o -p $_XML,xunitxml -p -o -p -,txt" |
866 | set +e |
867 | |
868 | function create_test_cmd { |
869 | - _CMD="./$_TARGET" |
870 | + _CMD="dbus-test-runner --task ./$_TARGET -n $_TESTFILE -m 300" |
871 | if [ "$_MINIMAL" = "minimal" ]; then |
872 | - _CMD="$_CMD -platform minimal" |
873 | + _CMD="$_CMD -p -platform -p minimal" |
874 | fi |
875 | if [ $_TARGET != $_TESTFILE ]; then |
876 | - _CMD="$_CMD -input $_TESTFILE" |
877 | + _CMD="$_CMD -p -input -p $_TESTFILE" |
878 | fi |
879 | - _CMD="$_CMD -maxwarnings 40" |
880 | + _CMD="$_CMD -p -maxwarnings -p 40" |
881 | } |
882 | |
883 | function execute_test_cmd { |
884 | |
885 | === added directory 'tests/unit_x11/tst_serviceproperties' |
886 | === added file 'tests/unit_x11/tst_serviceproperties/IncomingCallVibrateWatcher.qml' |
887 | --- tests/unit_x11/tst_serviceproperties/IncomingCallVibrateWatcher.qml 1970-01-01 00:00:00 +0000 |
888 | +++ tests/unit_x11/tst_serviceproperties/IncomingCallVibrateWatcher.qml 2015-02-04 14:00:19 +0000 |
889 | @@ -0,0 +1,31 @@ |
890 | +/* |
891 | + * Copyright 2014 Canonical Ltd. |
892 | + * |
893 | + * This program is free software; you can redistribute it and/or modify |
894 | + * it under the terms of the GNU Lesser General Public License as published by |
895 | + * the Free Software Foundation; version 3. |
896 | + * |
897 | + * This program is distributed in the hope that it will be useful, |
898 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
899 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
900 | + * GNU Lesser General Public License for more details. |
901 | + * |
902 | + * You should have received a copy of the GNU Lesser General Public License |
903 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
904 | + */ |
905 | + |
906 | +import QtQuick 2.3 |
907 | +import Ubuntu.Components 1.1 |
908 | + |
909 | +Item { |
910 | + property alias service: service |
911 | + ServiceProperties { |
912 | + id: service |
913 | + service: "org.freedesktop.Accounts" |
914 | + serviceInterface: "org.freedesktop.Accounts" |
915 | + path: "/org/freedesktop/Accounts" |
916 | + adaptorInterface: "com.ubuntu.touch.AccountsService.Sound" |
917 | + |
918 | + property bool incomingCallVibrate: true |
919 | + } |
920 | +} |
921 | |
922 | === added file 'tests/unit_x11/tst_serviceproperties/InvalidPropertyWatcher.qml' |
923 | --- tests/unit_x11/tst_serviceproperties/InvalidPropertyWatcher.qml 1970-01-01 00:00:00 +0000 |
924 | +++ tests/unit_x11/tst_serviceproperties/InvalidPropertyWatcher.qml 2015-02-04 14:00:19 +0000 |
925 | @@ -0,0 +1,31 @@ |
926 | +/* |
927 | + * Copyright 2014 Canonical Ltd. |
928 | + * |
929 | + * This program is free software; you can redistribute it and/or modify |
930 | + * it under the terms of the GNU Lesser General Public License as published by |
931 | + * the Free Software Foundation; version 3. |
932 | + * |
933 | + * This program is distributed in the hope that it will be useful, |
934 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
935 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
936 | + * GNU Lesser General Public License for more details. |
937 | + * |
938 | + * You should have received a copy of the GNU Lesser General Public License |
939 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
940 | + */ |
941 | + |
942 | +import QtQuick 2.3 |
943 | +import Ubuntu.Components 1.1 |
944 | + |
945 | +Item { |
946 | + property alias service: service |
947 | + ServiceProperties { |
948 | + id: service |
949 | + service: "org.freedesktop.Accounts" |
950 | + serviceInterface: "org.freedesktop.Accounts" |
951 | + path: "/org/freedesktop/Accounts" |
952 | + adaptorInterface: "com.ubuntu.touch.AccountsService.Sound" |
953 | + |
954 | + property bool thisIsAnInvalidPropertyToWatch: true |
955 | + } |
956 | +} |
957 | |
958 | === added file 'tests/unit_x11/tst_serviceproperties/InvalidPropertyWatcher2.qml' |
959 | --- tests/unit_x11/tst_serviceproperties/InvalidPropertyWatcher2.qml 1970-01-01 00:00:00 +0000 |
960 | +++ tests/unit_x11/tst_serviceproperties/InvalidPropertyWatcher2.qml 2015-02-04 14:00:19 +0000 |
961 | @@ -0,0 +1,32 @@ |
962 | +/* |
963 | + * Copyright 2014 Canonical Ltd. |
964 | + * |
965 | + * This program is free software; you can redistribute it and/or modify |
966 | + * it under the terms of the GNU Lesser General Public License as published by |
967 | + * the Free Software Foundation; version 3. |
968 | + * |
969 | + * This program is distributed in the hope that it will be useful, |
970 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
971 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
972 | + * GNU Lesser General Public License for more details. |
973 | + * |
974 | + * You should have received a copy of the GNU Lesser General Public License |
975 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
976 | + */ |
977 | + |
978 | +import QtQuick 2.3 |
979 | +import Ubuntu.Components 1.1 |
980 | + |
981 | +Item { |
982 | + property alias service: service |
983 | + ServiceProperties { |
984 | + id: service |
985 | + service: "org.freedesktop.Accounts" |
986 | + serviceInterface: "org.freedesktop.Accounts" |
987 | + path: "/org/freedesktop/Accounts" |
988 | + adaptorInterface: "com.ubuntu.touch.AccountsService.Sound" |
989 | + |
990 | + property bool thisIsAnInvalidPropertyToWatch: true |
991 | + property bool incomingCallVibrate: true |
992 | + } |
993 | +} |
994 | |
995 | === added file 'tests/unit_x11/tst_serviceproperties/tst_serviceproperties.cpp' |
996 | --- tests/unit_x11/tst_serviceproperties/tst_serviceproperties.cpp 1970-01-01 00:00:00 +0000 |
997 | +++ tests/unit_x11/tst_serviceproperties/tst_serviceproperties.cpp 2015-02-04 14:00:19 +0000 |
998 | @@ -0,0 +1,146 @@ |
999 | +/* |
1000 | + * Copyright 2014 Canonical Ltd. |
1001 | + * |
1002 | + * This program is free software; you can redistribute it and/or modify |
1003 | + * it under the terms of the GNU Lesser General Public License as published by |
1004 | + * the Free Software Foundation; version 3. |
1005 | + * |
1006 | + * This program is distributed in the hope that it will be useful, |
1007 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1008 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1009 | + * GNU Lesser General Public License for more details. |
1010 | + * |
1011 | + * You should have received a copy of the GNU Lesser General Public License |
1012 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1013 | + */ |
1014 | + |
1015 | +#include "uctestcase.h" |
1016 | +#include "ucserviceproperties.h" |
1017 | +#include "ucserviceproperties_p.h" |
1018 | +#include <QtCore/QString> |
1019 | +#include <QtCore/QDebug> |
1020 | +#include <QtTest/QTest> |
1021 | +#include <QtTest/QSignalSpy> |
1022 | + |
1023 | +class tst_ServiceProperties : public QObject |
1024 | +{ |
1025 | + Q_OBJECT |
1026 | + |
1027 | +public: |
1028 | + tst_ServiceProperties() {} |
1029 | + |
1030 | +private: |
1031 | + |
1032 | + QString error; |
1033 | + |
1034 | + // FIXME use UbuntuTestCase::ignoreWaring in Vivid |
1035 | + void ignoreWarning(const QString& fileName, uint line, uint column, const QString& message, uint occurences=1) |
1036 | + { |
1037 | + for (uint i = 0; i < occurences; i++) { |
1038 | + QString url(QUrl::fromLocalFile(QFileInfo(fileName).absoluteFilePath()).toEncoded()); |
1039 | + QString warning(QString("%1:%2:%3: %4").arg(url).arg(line).arg(column).arg(message)); |
1040 | + QTest::ignoreMessage(QtWarningMsg, warning.toUtf8()); |
1041 | + } |
1042 | + } |
1043 | + |
1044 | + |
1045 | +private Q_SLOTS: |
1046 | + |
1047 | + void initTestCase() |
1048 | + { |
1049 | + // check if the connection is possible, otherwise we must skip all tests |
1050 | + QScopedPointer<UbuntuTestCase> test(new UbuntuTestCase("IncomingCallVibrateWatcher.qml")); |
1051 | + UCServiceProperties *watcher = static_cast<UCServiceProperties*>(test->rootObject()->property("service").value<QObject*>()); |
1052 | + QVERIFY(watcher); |
1053 | + if (watcher->status() == UCServiceProperties::Synchronizing || |
1054 | + watcher->status() == UCServiceProperties::Inactive) { |
1055 | + QSignalSpy wait(watcher, SIGNAL(statusChanged())); |
1056 | + wait.wait(); |
1057 | + } |
1058 | + if (watcher->status() == UCServiceProperties::ConnectionError) { |
1059 | + error = "Skip test: " + watcher->error(); |
1060 | + } |
1061 | + } |
1062 | + |
1063 | + void test_change_property() |
1064 | + { |
1065 | + if (!error.isEmpty()) { |
1066 | + QSKIP(qPrintable(error)); |
1067 | + } |
1068 | + QScopedPointer<UbuntuTestCase> test(new UbuntuTestCase("IncomingCallVibrateWatcher.qml")); |
1069 | + UCServiceProperties *watcher = static_cast<UCServiceProperties*>(test->rootObject()->property("service").value<QObject*>()); |
1070 | + QVERIFY(watcher); |
1071 | + |
1072 | + bool backup = watcher->property("incomingCallVibrate").toBool(); |
1073 | + UCServicePropertiesPrivate *pWatcher = UCServicePropertiesPrivate::get(watcher); |
1074 | + QSignalSpy spy(watcher, SIGNAL(incomingCallVibrateChanged())); |
1075 | + pWatcher->testProperty("IncomingCallVibrate", !backup); |
1076 | + spy.wait(400); |
1077 | + QCOMPARE(spy.count(), 1); |
1078 | + QCOMPARE(watcher->property("incomingCallVibrate").toBool(), !backup); |
1079 | + |
1080 | + // restore value |
1081 | + spy.clear(); |
1082 | + pWatcher->testProperty("IncomingCallVibrate", backup); |
1083 | + spy.wait(400); |
1084 | + } |
1085 | + |
1086 | + void test_invalid_property() |
1087 | + { |
1088 | + if (!error.isEmpty()) { |
1089 | + QSKIP(qPrintable(error)); |
1090 | + } |
1091 | + ignoreWarning("InvalidPropertyWatcher.qml", 22, 5, "QML ServiceProperties: No such property 'ThisIsAnInvalidPropertyToWatch'"); |
1092 | + QScopedPointer<UbuntuTestCase> test(new UbuntuTestCase("InvalidPropertyWatcher.qml")); |
1093 | + UCServiceProperties *watcher = static_cast<UCServiceProperties*>(test->rootObject()->property("service").value<QObject*>()); |
1094 | + QVERIFY(watcher); |
1095 | + // error should not be set |
1096 | + QCOMPARE(watcher->property("error").toString(), QString()); |
1097 | + } |
1098 | + |
1099 | + void test_one_valid_one_invalid_property() |
1100 | + { |
1101 | + if (!error.isEmpty()) { |
1102 | + QSKIP(qPrintable(error)); |
1103 | + } |
1104 | + ignoreWarning("InvalidPropertyWatcher2.qml", 22, 5, "QML ServiceProperties: No such property 'ThisIsAnInvalidPropertyToWatch'"); |
1105 | + QScopedPointer<UbuntuTestCase> test(new UbuntuTestCase("InvalidPropertyWatcher2.qml")); |
1106 | + UCServiceProperties *watcher = static_cast<UCServiceProperties*>(test->rootObject()->property("service").value<QObject*>()); |
1107 | + QVERIFY(watcher); |
1108 | + // error should not be set |
1109 | + QCOMPARE(watcher->property("error").toString(), QString()); |
1110 | + } |
1111 | + |
1112 | + void test_change_connection_props_data() |
1113 | + { |
1114 | + QTest::addColumn<QString>("property"); |
1115 | + QTest::addColumn<QString>("value"); |
1116 | + |
1117 | + QTest::newRow("Changing servcie") << "service" << "anything.else"; |
1118 | + QTest::newRow("Changing interface") << "serviceInterface" << "anything.else"; |
1119 | + QTest::newRow("Changing adaptor") << "adaptorInterface" << "anything.else"; |
1120 | + } |
1121 | + void test_change_connection_props() |
1122 | + { |
1123 | + QFETCH(QString, property); |
1124 | + QFETCH(QString, value); |
1125 | + |
1126 | + if (!error.isEmpty()) { |
1127 | + QSKIP(qPrintable(error)); |
1128 | + } |
1129 | + ignoreWarning("IncomingCallVibrateWatcher.qml", 22, 5, "QML ServiceProperties: Changing connection parameters forbidden."); |
1130 | + QScopedPointer<UbuntuTestCase> test(new UbuntuTestCase("IncomingCallVibrateWatcher.qml")); |
1131 | + UCServiceProperties *watcher = static_cast<UCServiceProperties*>(test->rootObject()->property("service").value<QObject*>()); |
1132 | + QVERIFY(watcher); |
1133 | + |
1134 | + // try to change the property |
1135 | + watcher->setProperty(property.toLocal8Bit().constData(), value); |
1136 | + // no error should be reported |
1137 | + QCOMPARE(watcher->property("error").toString(), QString()); |
1138 | + } |
1139 | + |
1140 | +}; |
1141 | + |
1142 | +QTEST_MAIN(tst_ServiceProperties) |
1143 | + |
1144 | +#include "tst_serviceproperties.moc" |
1145 | |
1146 | === added file 'tests/unit_x11/tst_serviceproperties/tst_serviceproperties.pro' |
1147 | --- tests/unit_x11/tst_serviceproperties/tst_serviceproperties.pro 1970-01-01 00:00:00 +0000 |
1148 | +++ tests/unit_x11/tst_serviceproperties/tst_serviceproperties.pro 2015-02-04 14:00:19 +0000 |
1149 | @@ -0,0 +1,8 @@ |
1150 | +include(../test-include.pri) |
1151 | +SOURCES += \ |
1152 | + tst_serviceproperties.cpp |
1153 | + |
1154 | +OTHER_FILES += \ |
1155 | + IncomingCallVibrateWatcher.qml \ |
1156 | + InvalidPropertyWatcher.qml \ |
1157 | + InvalidPropertyWatcher2.qml |
1158 | |
1159 | === modified file 'tests/unit_x11/unit_x11.pro' |
1160 | --- tests/unit_x11/unit_x11.pro 2014-08-13 11:21:04 +0000 |
1161 | +++ tests/unit_x11/unit_x11.pro 2015-02-04 14:00:19 +0000 |
1162 | @@ -11,4 +11,5 @@ |
1163 | tst_orientation \ |
1164 | tst_layouts \ |
1165 | tst_mousefilters \ |
1166 | - tst_animator |
1167 | + tst_animator \ |
1168 | + tst_serviceproperties |
DBusPropertyWatcher adaptation layer API added to support multiple DBus service watching. It has been added as adaptation layer API as prerequisite for the multi platform support (SDK must enable development on other platforms).
The property is a temporary workaround to support the feature requested. Future singleton API should be productised during the near future to replace this property.