|
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 examples of the Qt Toolkit. |
|
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 <QVector> |
|
43 #include <QtDebug> |
|
44 |
|
45 #include <QCoreApplication> |
|
46 #include <QMetaProperty> |
|
47 #include <QXmlQuery> |
|
48 #include <QXmlResultItems> |
|
49 |
|
50 #include "qobjectxmlmodel.h" |
|
51 |
|
52 QT_BEGIN_NAMESPACE |
|
53 |
|
54 /* |
|
55 <metaObjects> |
|
56 <metaObject className="QObject"/> |
|
57 <metaObject className="QWidget" superClass="QObject"> |
|
58 </metaObject> |
|
59 ... |
|
60 </metaObjects> |
|
61 <QObject objectName="MyWidget" property1="..." property2="..."> <!-- This is root() --> |
|
62 <QObject objectName="MyFOO" property1="..."/> |
|
63 .... |
|
64 </QObject> |
|
65 */ |
|
66 |
|
67 QObjectXmlModel::QObjectXmlModel(QObject *const object, const QXmlNamePool &np) |
|
68 : QSimpleXmlNodeModel(np), |
|
69 m_baseURI(QUrl::fromLocalFile(QCoreApplication::applicationFilePath())), |
|
70 m_root(object), |
|
71 m_allMetaObjects(allMetaObjects()) |
|
72 { |
|
73 Q_ASSERT(m_baseURI.isValid()); |
|
74 } |
|
75 |
|
76 //! [5] |
|
77 QXmlNodeModelIndex QObjectXmlModel::qObjectSibling(const int pos, const QXmlNodeModelIndex &n) const |
|
78 { |
|
79 Q_ASSERT(pos == 1 || pos == -1); |
|
80 Q_ASSERT(asQObject(n)); |
|
81 |
|
82 const QObject *parent = asQObject(n)->parent(); |
|
83 if (parent) { |
|
84 const QList<QObject *> &children = parent->children(); |
|
85 const int siblingPos = children.indexOf(asQObject(n)) + pos; |
|
86 |
|
87 if (siblingPos >= 0 && siblingPos < children.count()) |
|
88 return createIndex(children.at(siblingPos)); |
|
89 else |
|
90 return QXmlNodeModelIndex(); |
|
91 } |
|
92 else |
|
93 return QXmlNodeModelIndex(); |
|
94 } |
|
95 //! [5] |
|
96 |
|
97 //! [1] |
|
98 QObjectXmlModel::QObjectNodeType QObjectXmlModel::toNodeType(const QXmlNodeModelIndex &n) |
|
99 { |
|
100 return QObjectNodeType(n.additionalData() & (15 << 26)); |
|
101 } |
|
102 //! [1] |
|
103 |
|
104 //! [9] |
|
105 QObjectXmlModel::AllMetaObjects QObjectXmlModel::allMetaObjects() const |
|
106 { |
|
107 QXmlQuery query(namePool()); |
|
108 query.bindVariable("root", root()); |
|
109 query.setQuery("declare variable $root external;" |
|
110 "$root/descendant-or-self::QObject"); |
|
111 Q_ASSERT(query.isValid()); |
|
112 |
|
113 QXmlResultItems result; |
|
114 query.evaluateTo(&result); |
|
115 QXmlItem i(result.next()); |
|
116 |
|
117 AllMetaObjects objects; |
|
118 while (!i.isNull()) { |
|
119 const QMetaObject *moo = asQObject(i.toNodeModelIndex())->metaObject(); |
|
120 while (moo) { |
|
121 if (!objects.contains(moo)) |
|
122 objects.append(moo); |
|
123 moo = moo->superClass(); |
|
124 } |
|
125 i = result.next(); |
|
126 } |
|
127 |
|
128 Q_ASSERT(!objects.contains(0)); |
|
129 return objects; |
|
130 } |
|
131 //! [9] |
|
132 |
|
133 QXmlNodeModelIndex QObjectXmlModel::metaObjectSibling(const int pos, const QXmlNodeModelIndex &n) const |
|
134 { |
|
135 Q_ASSERT(pos == 1 || pos == -1); |
|
136 Q_ASSERT(!n.isNull()); |
|
137 |
|
138 const int indexOf = m_allMetaObjects.indexOf(static_cast<const QMetaObject *>(n.internalPointer())) + pos; |
|
139 |
|
140 if (indexOf >= 0 && indexOf < m_allMetaObjects.count()) |
|
141 return createIndex(const_cast<QMetaObject *>(m_allMetaObjects.at(indexOf)), MetaObject); |
|
142 else |
|
143 return QXmlNodeModelIndex(); |
|
144 } |
|
145 |
|
146 //! [2] |
|
147 QXmlNodeModelIndex QObjectXmlModel::nextFromSimpleAxis(SimpleAxis axis, const QXmlNodeModelIndex &n) const |
|
148 { |
|
149 switch (toNodeType(n)) |
|
150 { |
|
151 case IsQObject: |
|
152 { |
|
153 switch (axis) |
|
154 { |
|
155 case Parent: |
|
156 return createIndex(asQObject(n)->parent()); |
|
157 |
|
158 case FirstChild: |
|
159 { |
|
160 if (!asQObject(n) || asQObject(n)->children().isEmpty()) |
|
161 return QXmlNodeModelIndex(); |
|
162 else |
|
163 return createIndex(asQObject(n)->children().first()); |
|
164 } |
|
165 |
|
166 case NextSibling: |
|
167 return qObjectSibling(1, n); |
|
168 |
|
169 //! [10] |
|
170 case PreviousSibling: |
|
171 { |
|
172 if (asQObject(n) == m_root) |
|
173 return createIndex(qint64(0), MetaObjects); |
|
174 else |
|
175 return qObjectSibling(-1, n); |
|
176 } |
|
177 //! [10] |
|
178 } |
|
179 Q_ASSERT(false); |
|
180 } |
|
181 |
|
182 //! [7] |
|
183 case QObjectClassName: |
|
184 case QObjectProperty: |
|
185 { |
|
186 Q_ASSERT(axis == Parent); |
|
187 return createIndex(asQObject(n)); |
|
188 } |
|
189 //! [7] |
|
190 //! [2] |
|
191 //! [3] |
|
192 |
|
193 //! [11] |
|
194 case MetaObjects: |
|
195 { |
|
196 switch (axis) |
|
197 { |
|
198 case Parent: |
|
199 return QXmlNodeModelIndex(); |
|
200 case PreviousSibling: |
|
201 return QXmlNodeModelIndex(); |
|
202 case NextSibling: |
|
203 return root(); |
|
204 case FirstChild: |
|
205 { |
|
206 return createIndex(const_cast<QMetaObject*>(m_allMetaObjects.first()),MetaObject); |
|
207 } |
|
208 } |
|
209 Q_ASSERT(false); |
|
210 } |
|
211 //! [11] |
|
212 |
|
213 case MetaObject: |
|
214 { |
|
215 switch (axis) |
|
216 { |
|
217 case FirstChild: |
|
218 return QXmlNodeModelIndex(); |
|
219 case Parent: |
|
220 return createIndex(qint64(0), MetaObjects); |
|
221 case PreviousSibling: |
|
222 return metaObjectSibling(-1, n); |
|
223 case NextSibling: |
|
224 return metaObjectSibling(1, n); |
|
225 } |
|
226 } |
|
227 |
|
228 case MetaObjectClassName: |
|
229 case MetaObjectSuperClass: |
|
230 { |
|
231 Q_ASSERT(axis == Parent); |
|
232 return createIndex(asQObject(n), MetaObject); |
|
233 } |
|
234 //! [3] |
|
235 //! [4] |
|
236 } |
|
237 |
|
238 Q_ASSERT(false); |
|
239 return QXmlNodeModelIndex(); |
|
240 } |
|
241 //! [4] |
|
242 |
|
243 //! [6] |
|
244 QVector<QXmlNodeModelIndex> QObjectXmlModel::attributes(const QXmlNodeModelIndex& n) const |
|
245 { |
|
246 QVector<QXmlNodeModelIndex> result; |
|
247 QObject *const object = asQObject(n); |
|
248 |
|
249 switch(toNodeType(n)) |
|
250 { |
|
251 case IsQObject: |
|
252 { |
|
253 const QMetaObject *const metaObject = object->metaObject(); |
|
254 const int count = metaObject->propertyCount(); |
|
255 result.append(createIndex(object, QObjectClassName)); |
|
256 |
|
257 for (int i = 0; i < count; ++i) { |
|
258 const QMetaProperty qmp(metaObject->property(i)); |
|
259 const int ii = metaObject->indexOfProperty(qmp.name()); |
|
260 if (i == ii) |
|
261 result.append(createIndex(object, QObjectProperty | i)); |
|
262 } |
|
263 return result; |
|
264 } |
|
265 //! [6] |
|
266 |
|
267 case MetaObject: |
|
268 { |
|
269 result.append(createIndex(object, MetaObjectClassName)); |
|
270 result.append(createIndex(object, MetaObjectSuperClass)); |
|
271 return result; |
|
272 } |
|
273 //! [8] |
|
274 default: |
|
275 return QVector<QXmlNodeModelIndex>(); |
|
276 } |
|
277 } |
|
278 //! [8] |
|
279 |
|
280 QObject *QObjectXmlModel::asQObject(const QXmlNodeModelIndex &n) |
|
281 { |
|
282 return static_cast<QObject *>(n.internalPointer()); |
|
283 } |
|
284 |
|
285 bool QObjectXmlModel::isProperty(const QXmlNodeModelIndex n) |
|
286 { |
|
287 return n.additionalData() & QObjectProperty; |
|
288 } |
|
289 |
|
290 QUrl QObjectXmlModel::documentUri(const QXmlNodeModelIndex& ) const |
|
291 { |
|
292 return m_baseURI; |
|
293 } |
|
294 |
|
295 QXmlNodeModelIndex::NodeKind QObjectXmlModel::kind(const QXmlNodeModelIndex& n) const |
|
296 { |
|
297 switch (toNodeType(n)) |
|
298 { |
|
299 case IsQObject: |
|
300 case MetaObject: |
|
301 case MetaObjects: |
|
302 return QXmlNodeModelIndex::Element; |
|
303 |
|
304 case QObjectProperty: |
|
305 case MetaObjectClassName: |
|
306 case MetaObjectSuperClass: |
|
307 case QObjectClassName: |
|
308 return QXmlNodeModelIndex::Attribute; |
|
309 } |
|
310 |
|
311 Q_ASSERT(false); |
|
312 return QXmlNodeModelIndex::Element; |
|
313 } |
|
314 |
|
315 QXmlNodeModelIndex::DocumentOrder QObjectXmlModel::compareOrder(const QXmlNodeModelIndex& , const QXmlNodeModelIndex& ) const |
|
316 { |
|
317 return QXmlNodeModelIndex::Follows; // TODO |
|
318 } |
|
319 |
|
320 //! [0] |
|
321 QXmlNodeModelIndex QObjectXmlModel::root() const |
|
322 { |
|
323 return createIndex(m_root); |
|
324 } |
|
325 //! [0] |
|
326 |
|
327 QXmlNodeModelIndex QObjectXmlModel::root(const QXmlNodeModelIndex& n) const |
|
328 { |
|
329 QObject *p = asQObject(n); |
|
330 Q_ASSERT(p); |
|
331 |
|
332 do { |
|
333 QObject *const candidate = p->parent(); |
|
334 if (candidate) |
|
335 p = candidate; |
|
336 else |
|
337 break; |
|
338 } |
|
339 while (true); |
|
340 |
|
341 return createIndex(p); |
|
342 } |
|
343 |
|
344 /*! |
|
345 We simply throw all of them into a QList and |
|
346 return an iterator over it. |
|
347 */ |
|
348 QXmlNodeModelIndex::List QObjectXmlModel::ancestors(const QXmlNodeModelIndex n) const |
|
349 { |
|
350 const QObject *p = asQObject(n); |
|
351 Q_ASSERT(p); |
|
352 |
|
353 QXmlNodeModelIndex::List result; |
|
354 do { |
|
355 QObject *const candidate = p->parent(); |
|
356 if (candidate) { |
|
357 result.append(createIndex(candidate, 0)); |
|
358 p = candidate; |
|
359 } |
|
360 else |
|
361 break; |
|
362 } |
|
363 while (true); |
|
364 |
|
365 return result; |
|
366 } |
|
367 |
|
368 QMetaProperty QObjectXmlModel::toMetaProperty(const QXmlNodeModelIndex &n) |
|
369 { |
|
370 const int propertyOffset = n.additionalData() & (~QObjectProperty); |
|
371 const QObject *const qo = asQObject(n); |
|
372 return qo->metaObject()->property(propertyOffset); |
|
373 } |
|
374 |
|
375 QXmlName QObjectXmlModel::name(const QXmlNodeModelIndex &n) const |
|
376 { |
|
377 switch (toNodeType(n)) |
|
378 { |
|
379 case IsQObject: |
|
380 return QXmlName(namePool(), QLatin1String("QObject")); |
|
381 case MetaObject: |
|
382 return QXmlName(namePool(), QLatin1String("metaObject")); |
|
383 case QObjectClassName: |
|
384 case MetaObjectClassName: |
|
385 return QXmlName(namePool(), QLatin1String("className")); |
|
386 case QObjectProperty: |
|
387 return QXmlName(namePool(), toMetaProperty(n).name()); |
|
388 case MetaObjects: |
|
389 return QXmlName(namePool(), QLatin1String("metaObjects")); |
|
390 case MetaObjectSuperClass: |
|
391 return QXmlName(namePool(), QLatin1String("superClass")); |
|
392 } |
|
393 |
|
394 Q_ASSERT(false); |
|
395 return QXmlName(); |
|
396 } |
|
397 |
|
398 QVariant QObjectXmlModel::typedValue(const QXmlNodeModelIndex &n) const |
|
399 { |
|
400 switch (toNodeType(n)) |
|
401 { |
|
402 case QObjectProperty: |
|
403 { |
|
404 const QVariant &candidate = toMetaProperty(n).read(asQObject(n)); |
|
405 if (isTypeSupported(candidate.type())) |
|
406 return candidate; |
|
407 else |
|
408 return QVariant(); |
|
409 } |
|
410 |
|
411 case MetaObjectClassName: |
|
412 return QVariant(static_cast<QMetaObject*>(n.internalPointer())->className()); |
|
413 |
|
414 case MetaObjectSuperClass: |
|
415 { |
|
416 const QMetaObject *const superClass = static_cast<QMetaObject*>(n.internalPointer())->superClass(); |
|
417 if (superClass) |
|
418 return QVariant(superClass->className()); |
|
419 else |
|
420 return QVariant(); |
|
421 } |
|
422 |
|
423 case QObjectClassName: |
|
424 return QVariant(asQObject(n)->metaObject()->className()); |
|
425 |
|
426 default: |
|
427 return QVariant(); |
|
428 } |
|
429 } |
|
430 |
|
431 /*! |
|
432 Returns \c true if QVariants of type \a type can be used |
|
433 in QtXmlPatterns, otherwise \c false. |
|
434 */ |
|
435 bool QObjectXmlModel::isTypeSupported(QVariant::Type type) |
|
436 { |
|
437 /* See data/qatomicvalue.cpp too. */ |
|
438 switch (type) |
|
439 { |
|
440 /* Fallthrough all these. */ |
|
441 case QVariant::Char: |
|
442 case QVariant::String: |
|
443 case QVariant::Url: |
|
444 case QVariant::Bool: |
|
445 case QVariant::ByteArray: |
|
446 case QVariant::Int: |
|
447 case QVariant::LongLong: |
|
448 case QVariant::ULongLong: |
|
449 case QVariant::Date: |
|
450 case QVariant::DateTime: |
|
451 case QVariant::Time: |
|
452 case QVariant::Double: |
|
453 return true; |
|
454 default: |
|
455 return false; |
|
456 } |
|
457 } |
|
458 |
|
459 QT_END_NAMESPACE |