|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the Qt Mobility Components. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "qvaluespace.h" |
|
43 #include "qvaluespace_p.h" |
|
44 |
|
45 #include <QSet> |
|
46 #include <QDebug> |
|
47 #include <contextproperty.h> |
|
48 #include <contextregistryinfo.h> |
|
49 |
|
50 QTM_BEGIN_NAMESPACE |
|
51 |
|
52 using namespace QValueSpace; |
|
53 |
|
54 /* ContextKit layer |
|
55 |
|
56 This layer makes ContextKit properties visible in the QValueSpace. |
|
57 |
|
58 You can not publish values of ContextKit properties using the |
|
59 QValueSpace. This might be fixed later. |
|
60 |
|
61 ContextKit properties have names with dots in them, which allows |
|
62 these properties to be arranged in a tree. The context commander |
|
63 does this in its UI, for example. |
|
64 |
|
65 However, the ContextKit itself does not pay attention to the dots |
|
66 at all: properties just have names and there are no such things as |
|
67 parent / child / sibling relations between properties. For |
|
68 example, there is a property called "Battery.ChargeLevel", but the |
|
69 ContextKit doesn't know anything about "Battery". Subscribing to |
|
70 "Battery" is exactly the same as subscribing to any other |
|
71 non-declared property. When "Battery.ChargeLevel" changes, |
|
72 "Battery" does _not_ receive a change notification. |
|
73 |
|
74 The QValueSpace, on the other hand, has a explicit tree-structure: |
|
75 the key "/foo" represents all its children, like "/foo/bar". When |
|
76 "/foo/bar" changes, "/foo" _does_ receive a change notification. |
|
77 |
|
78 There are two ways to map ContextKit properties into the |
|
79 QValueSpace: simply as a long list of siblings (a one-level tree), |
|
80 or as the multi-level tree that is implied by their names. |
|
81 |
|
82 We do the latter since that is more natural. For example, the |
|
83 ContextKit property "Battery.ChargeLevel" is mapped to |
|
84 "/Battery/ChargeLevel", and the key "/Battery" gets a change |
|
85 notifications for all its children. |
|
86 */ |
|
87 |
|
88 /* ContextKitHandle - contains a ContextKit property and all its |
|
89 direct and indirect children. |
|
90 |
|
91 ContextKitHandles do not form a hierarchy between each other; think |
|
92 of them as individual little trees that are created in direct |
|
93 response to requests to the ContextKitLayer. The properties in |
|
94 these trees can overlap; a single ContextKit property can be |
|
95 accessed via many ContextKitHandles. |
|
96 */ |
|
97 |
|
98 class ContextKitHandle : public QObject { |
|
99 |
|
100 Q_OBJECT |
|
101 |
|
102 public: |
|
103 ContextKitHandle (ContextKitHandle *parent, const QString &root); |
|
104 ~ContextKitHandle (); |
|
105 |
|
106 bool value (const QString &path, QVariant *data); |
|
107 void subscribe (); |
|
108 void unsubscribe (); |
|
109 QSet<QString> children (); |
|
110 |
|
111 signals: |
|
112 void valueChanged(); |
|
113 |
|
114 private: |
|
115 QString prefix; |
|
116 QHash<QString, ContextProperty *> props; |
|
117 |
|
118 void insert (const QString &path, const QString &key); |
|
119 }; |
|
120 |
|
121 void ContextKitHandle::insert (const QString &path, const QString &key) |
|
122 { |
|
123 ContextProperty *prop = new ContextProperty (key); |
|
124 connect (prop, SIGNAL (valueChanged()), |
|
125 this, SIGNAL (valueChanged())); |
|
126 props.insert (path, prop); |
|
127 } |
|
128 |
|
129 ContextKitHandle::ContextKitHandle (ContextKitHandle *parent, const QString &path) |
|
130 { |
|
131 QString key = path; |
|
132 if (key.startsWith("/")) |
|
133 key = key.mid(1); |
|
134 key = key.replace('/', '.'); |
|
135 if (parent) |
|
136 key = parent->prefix + key; |
|
137 |
|
138 prefix = (key == "")? "" : key + "."; |
|
139 foreach (const QString &k, ContextRegistryInfo::instance()->listKeys()) |
|
140 { |
|
141 if (k == key) |
|
142 insert ("", k); |
|
143 else if (k.startsWith (prefix)) |
|
144 insert (k.mid(prefix.length()).replace ('.', '/'), k); |
|
145 } |
|
146 } |
|
147 |
|
148 ContextKitHandle::~ContextKitHandle () |
|
149 { |
|
150 foreach (ContextProperty *prop, props.values()) |
|
151 delete prop; |
|
152 } |
|
153 |
|
154 bool |
|
155 ContextKitHandle::value (const QString &path, QVariant *data) |
|
156 { |
|
157 // path always starts with a "/". |
|
158 ContextProperty *p = props.value (path.mid(1)); |
|
159 if (p) |
|
160 { |
|
161 *data = p->value(); |
|
162 return true; |
|
163 } |
|
164 else |
|
165 return false; |
|
166 } |
|
167 |
|
168 void |
|
169 ContextKitHandle::subscribe () |
|
170 { |
|
171 foreach (ContextProperty *p, props.values()) |
|
172 p->subscribe (); |
|
173 } |
|
174 |
|
175 void |
|
176 ContextKitHandle::unsubscribe () |
|
177 { |
|
178 foreach (ContextProperty *p, props.values()) |
|
179 p->unsubscribe (); |
|
180 } |
|
181 |
|
182 QSet<QString> |
|
183 ContextKitHandle::children () |
|
184 { |
|
185 QSet<QString> kids; |
|
186 |
|
187 foreach (const QString &path, props.keys()) |
|
188 { |
|
189 int pos = path.indexOf("/"); |
|
190 if (pos >= 0) |
|
191 kids.insert (path.left(pos)); |
|
192 else |
|
193 kids.insert (path); |
|
194 } |
|
195 return kids; |
|
196 } |
|
197 |
|
198 /* ContextKitLayer - implements QAbstractValueSpaceLayer interface to |
|
199 hook ContextKit into QValueSpace. |
|
200 |
|
201 It mainly creates ContextKitHandles and dispatches to them. |
|
202 */ |
|
203 |
|
204 class ContextKitLayer : public QAbstractValueSpaceLayer |
|
205 { |
|
206 Q_OBJECT |
|
207 |
|
208 public: |
|
209 ContextKitLayer(); |
|
210 virtual ~ContextKitLayer(); |
|
211 |
|
212 /* ValueSpaceLayer interface - Common functions */ |
|
213 QString name(); |
|
214 bool startup(Type); |
|
215 QUuid id(); |
|
216 unsigned int order(); |
|
217 LayerOptions layerOptions() const; |
|
218 |
|
219 Handle item(Handle parent, const QString &); |
|
220 void removeHandle(Handle); |
|
221 void setProperty(Handle handle, Properties); |
|
222 |
|
223 bool value(Handle, QVariant *); |
|
224 bool value(Handle, const QString &, QVariant *); |
|
225 QSet<QString> children(Handle); |
|
226 |
|
227 /* ValueSpaceLayer interface - QValueSpaceSubscriber functions */ |
|
228 bool supportsInterestNotification() const { return true; } |
|
229 bool notifyInterest(Handle handle, bool interested); |
|
230 |
|
231 /* ValueSpaceLayer interface - QValueSpacePublisher functions */ |
|
232 bool setValue(QValueSpacePublisher *, Handle, const QString &, const QVariant &) { return false; } |
|
233 bool removeValue(QValueSpacePublisher *, Handle, const QString &) { return false; } |
|
234 bool removeSubTree(QValueSpacePublisher *, Handle) { return false; } |
|
235 void addWatch(QValueSpacePublisher *, Handle) { return; } |
|
236 void removeWatches(QValueSpacePublisher *, Handle) { return; } |
|
237 void sync() { return; } |
|
238 |
|
239 static ContextKitLayer *instance(); |
|
240 |
|
241 private slots: |
|
242 void contextHandleChanged(); |
|
243 }; |
|
244 |
|
245 QVALUESPACE_AUTO_INSTALL_LAYER(ContextKitLayer); |
|
246 |
|
247 ContextKitLayer::ContextKitLayer () |
|
248 { |
|
249 } |
|
250 |
|
251 ContextKitLayer::~ContextKitLayer () |
|
252 { |
|
253 } |
|
254 |
|
255 Q_GLOBAL_STATIC(ContextKitLayer, contextKitLayer); |
|
256 ContextKitLayer *ContextKitLayer::instance () |
|
257 { |
|
258 return contextKitLayer (); |
|
259 } |
|
260 |
|
261 QString ContextKitLayer::name() |
|
262 { |
|
263 return "ContextKit Layer"; |
|
264 } |
|
265 |
|
266 bool ContextKitLayer::startup(Type) |
|
267 { |
|
268 return true; |
|
269 } |
|
270 |
|
271 QUuid ContextKitLayer::id() |
|
272 { |
|
273 return QVALUESPACE_CONTEXTKIT_LAYER; |
|
274 } |
|
275 |
|
276 unsigned int ContextKitLayer::order() |
|
277 { |
|
278 return 0; |
|
279 } |
|
280 |
|
281 LayerOptions ContextKitLayer::layerOptions () const |
|
282 { |
|
283 return TransientLayer | ReadOnlyLayer; |
|
284 } |
|
285 |
|
286 QAbstractValueSpaceLayer::Handle ContextKitLayer::item (Handle parent, const QString &subPath) |
|
287 { |
|
288 return (Handle) new ContextKitHandle ((parent == InvalidHandle) |
|
289 ? NULL |
|
290 : (ContextKitHandle *) parent, |
|
291 subPath); |
|
292 } |
|
293 |
|
294 void ContextKitLayer::removeHandle (Handle handle) |
|
295 { |
|
296 ContextKitHandle *h = (ContextKitHandle *)handle; |
|
297 delete h; |
|
298 } |
|
299 |
|
300 void ContextKitLayer::setProperty (Handle handle, Properties properties) |
|
301 { |
|
302 ContextKitHandle *h = (ContextKitHandle *)handle; |
|
303 |
|
304 if (properties & Publish) |
|
305 connect (h, SIGNAL(valueChanged()), |
|
306 this, SLOT(contextHandleChanged())); |
|
307 else |
|
308 disconnect (h, SIGNAL(valueChanged()), |
|
309 this, SLOT(contextHandleChanged())); |
|
310 } |
|
311 |
|
312 void ContextKitLayer::contextHandleChanged() |
|
313 { |
|
314 ContextKitHandle *h = (ContextKitHandle *)sender(); |
|
315 emit handleChanged ((Handle) h); |
|
316 } |
|
317 |
|
318 bool ContextKitLayer::value (Handle handle, QVariant *data) |
|
319 { |
|
320 ContextKitHandle *h = (ContextKitHandle *)handle; |
|
321 return h->value ("", data); |
|
322 } |
|
323 |
|
324 bool ContextKitLayer::value (Handle handle, const QString &subPath, QVariant *data) |
|
325 { |
|
326 ContextKitHandle *h = (ContextKitHandle *)handle; |
|
327 return h->value (subPath, data); |
|
328 } |
|
329 |
|
330 bool ContextKitLayer::notifyInterest(Handle handle, bool interested) |
|
331 { |
|
332 ContextKitHandle *h = (ContextKitHandle *)handle; |
|
333 |
|
334 if (interested) |
|
335 h->subscribe(); |
|
336 else |
|
337 h->unsubscribe(); |
|
338 return true; |
|
339 } |
|
340 |
|
341 QSet<QString> ContextKitLayer::children (Handle handle) |
|
342 { |
|
343 ContextKitHandle *h = (ContextKitHandle *)handle; |
|
344 return h->children (); |
|
345 } |
|
346 |
|
347 #include "contextkitlayer.moc" |
|
348 QTM_END_NAMESPACE |
|
349 |