1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the examples of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** You may use this file under the terms of the BSD license as follows:
10 **
11 ** "Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions are
13 ** met:
14 ** * Redistributions of source code must retain the above copyright
15 ** notice, this list of conditions and the following disclaimer.
16 ** * Redistributions in binary form must reproduce the above copyright
17 ** notice, this list of conditions and the following disclaimer in
18 ** the documentation and/or other materials provided with the
19 ** distribution.
20 ** * Neither the name of The Qt Company Ltd nor the names of its
21 ** contributors may be used to endorse or promote products derived
22 ** from this software without specific prior written permission.
23 **
24 **
25 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40
41 #include <QVector>
42 #include <QtDebug>
43
44 #include <QCoreApplication>
45 #include <QMetaProperty>
46 #include <QXmlQuery>
47 #include <QXmlResultItems>
48
49 #include "qobjectxmlmodel.h"
50
51 QT_BEGIN_NAMESPACE
52
53 /*
54 <metaObjects>
55 <metaObject className="QObject"/>
56 <metaObject className="QWidget" superClass="QObject">
57 </metaObject>
58 ...
59 </metaObjects>
60 <QObject objectName="MyWidget" property1="..." property2="..."> <!-- This is root() -->
61 <QObject objectName="MyFOO" property1="..."/>
62 ....
63 </QObject>
64 */
65
QObjectXmlModel(QObject * const object,const QXmlNamePool & np)66 QObjectXmlModel::QObjectXmlModel(QObject *const object, const QXmlNamePool &np)
67 : QSimpleXmlNodeModel(np),
68 m_baseURI(QUrl::fromLocalFile(QCoreApplication::applicationFilePath())),
69 m_root(object),
70 m_allMetaObjects(allMetaObjects())
71 {
72 Q_ASSERT(m_baseURI.isValid());
73 }
74
75 //! [5]
qObjectSibling(const int pos,const QXmlNodeModelIndex & n) const76 QXmlNodeModelIndex QObjectXmlModel::qObjectSibling(const int pos, const QXmlNodeModelIndex &n) const
77 {
78 Q_ASSERT(pos == 1 || pos == -1);
79 Q_ASSERT(asQObject(n));
80
81 const QObject *parent = asQObject(n)->parent();
82 if (parent) {
83 const QList<QObject *> &children = parent->children();
84 const int siblingPos = children.indexOf(asQObject(n)) + pos;
85
86 if (siblingPos >= 0 && siblingPos < children.count())
87 return createIndex(children.at(siblingPos));
88 else
89 return QXmlNodeModelIndex();
90 }
91 else
92 return QXmlNodeModelIndex();
93 }
94 //! [5]
95
96 //! [1]
toNodeType(const QXmlNodeModelIndex & n)97 QObjectXmlModel::QObjectNodeType QObjectXmlModel::toNodeType(const QXmlNodeModelIndex &n)
98 {
99 return QObjectNodeType(n.additionalData() & (15 << 26));
100 }
101 //! [1]
102
103 //! [9]
allMetaObjects() const104 QObjectXmlModel::AllMetaObjects QObjectXmlModel::allMetaObjects() const
105 {
106 QXmlQuery query(namePool());
107 query.bindVariable("root", root());
108 query.setQuery("declare variable $root external;"
109 "$root/descendant-or-self::QObject");
110 Q_ASSERT(query.isValid());
111
112 QXmlResultItems result;
113 query.evaluateTo(&result);
114 QXmlItem i(result.next());
115
116 AllMetaObjects objects;
117 while (!i.isNull()) {
118 const QMetaObject *moo = asQObject(i.toNodeModelIndex())->metaObject();
119 while (moo) {
120 if (!objects.contains(moo))
121 objects.append(moo);
122 moo = moo->superClass();
123 }
124 i = result.next();
125 }
126
127 Q_ASSERT(!objects.contains(0));
128 return objects;
129 }
130 //! [9]
131
metaObjectSibling(const int pos,const QXmlNodeModelIndex & n) const132 QXmlNodeModelIndex QObjectXmlModel::metaObjectSibling(const int pos, const QXmlNodeModelIndex &n) const
133 {
134 Q_ASSERT(pos == 1 || pos == -1);
135 Q_ASSERT(!n.isNull());
136
137 const int indexOf = m_allMetaObjects.indexOf(static_cast<const QMetaObject *>(n.internalPointer())) + pos;
138
139 if (indexOf >= 0 && indexOf < m_allMetaObjects.count())
140 return createIndex(const_cast<QMetaObject *>(m_allMetaObjects.at(indexOf)), MetaObject);
141 else
142 return QXmlNodeModelIndex();
143 }
144
145 //! [2]
nextFromSimpleAxis(SimpleAxis axis,const QXmlNodeModelIndex & n) const146 QXmlNodeModelIndex QObjectXmlModel::nextFromSimpleAxis(SimpleAxis axis, const QXmlNodeModelIndex &n) const
147 {
148 switch (toNodeType(n))
149 {
150 case IsQObject:
151 {
152 switch (axis)
153 {
154 case Parent:
155 return createIndex(asQObject(n)->parent());
156
157 case FirstChild:
158 {
159 if (!asQObject(n) || asQObject(n)->children().isEmpty())
160 return QXmlNodeModelIndex();
161 else
162 return createIndex(asQObject(n)->children().first());
163 }
164
165 case NextSibling:
166 return qObjectSibling(1, n);
167
168 //! [10]
169 case PreviousSibling:
170 {
171 if (asQObject(n) == m_root)
172 return createIndex(qint64(0), MetaObjects);
173 else
174 return qObjectSibling(-1, n);
175 }
176 //! [10]
177 }
178 Q_ASSERT(false);
179 }
180
181 //! [7]
182 case QObjectClassName:
183 case QObjectProperty:
184 {
185 Q_ASSERT(axis == Parent);
186 return createIndex(asQObject(n));
187 }
188 //! [7]
189 //! [2]
190 //! [3]
191
192 //! [11]
193 case MetaObjects:
194 {
195 switch (axis)
196 {
197 case Parent:
198 return QXmlNodeModelIndex();
199 case PreviousSibling:
200 return QXmlNodeModelIndex();
201 case NextSibling:
202 return root();
203 case FirstChild:
204 {
205 return createIndex(const_cast<QMetaObject*>(m_allMetaObjects.first()),MetaObject);
206 }
207 }
208 Q_ASSERT(false);
209 }
210 //! [11]
211
212 case MetaObject:
213 {
214 switch (axis)
215 {
216 case FirstChild:
217 return QXmlNodeModelIndex();
218 case Parent:
219 return createIndex(qint64(0), MetaObjects);
220 case PreviousSibling:
221 return metaObjectSibling(-1, n);
222 case NextSibling:
223 return metaObjectSibling(1, n);
224 }
225 }
226
227 case MetaObjectClassName:
228 case MetaObjectSuperClass:
229 {
230 Q_ASSERT(axis == Parent);
231 return createIndex(asQObject(n), MetaObject);
232 }
233 //! [3]
234 //! [4]
235 }
236
237 Q_ASSERT(false);
238 return QXmlNodeModelIndex();
239 }
240 //! [4]
241
242 //! [6]
attributes(const QXmlNodeModelIndex & n) const243 QVector<QXmlNodeModelIndex> QObjectXmlModel::attributes(const QXmlNodeModelIndex& n) const
244 {
245 QVector<QXmlNodeModelIndex> result;
246 QObject *const object = asQObject(n);
247
248 switch(toNodeType(n))
249 {
250 case IsQObject:
251 {
252 const QMetaObject *const metaObject = object->metaObject();
253 const int count = metaObject->propertyCount();
254 result.append(createIndex(object, QObjectClassName));
255
256 for (int i = 0; i < count; ++i) {
257 const QMetaProperty qmp(metaObject->property(i));
258 const int ii = metaObject->indexOfProperty(qmp.name());
259 if (i == ii)
260 result.append(createIndex(object, QObjectProperty | i));
261 }
262 return result;
263 }
264 //! [6]
265
266 case MetaObject:
267 {
268 result.append(createIndex(object, MetaObjectClassName));
269 result.append(createIndex(object, MetaObjectSuperClass));
270 return result;
271 }
272 //! [8]
273 default:
274 return QVector<QXmlNodeModelIndex>();
275 }
276 }
277 //! [8]
278
asQObject(const QXmlNodeModelIndex & n)279 QObject *QObjectXmlModel::asQObject(const QXmlNodeModelIndex &n)
280 {
281 return static_cast<QObject *>(n.internalPointer());
282 }
283
isProperty(const QXmlNodeModelIndex n)284 bool QObjectXmlModel::isProperty(const QXmlNodeModelIndex n)
285 {
286 return n.additionalData() & QObjectProperty;
287 }
288
documentUri(const QXmlNodeModelIndex &) const289 QUrl QObjectXmlModel::documentUri(const QXmlNodeModelIndex& ) const
290 {
291 return m_baseURI;
292 }
293
kind(const QXmlNodeModelIndex & n) const294 QXmlNodeModelIndex::NodeKind QObjectXmlModel::kind(const QXmlNodeModelIndex& n) const
295 {
296 switch (toNodeType(n))
297 {
298 case IsQObject:
299 case MetaObject:
300 case MetaObjects:
301 return QXmlNodeModelIndex::Element;
302
303 case QObjectProperty:
304 case MetaObjectClassName:
305 case MetaObjectSuperClass:
306 case QObjectClassName:
307 return QXmlNodeModelIndex::Attribute;
308 }
309
310 Q_ASSERT(false);
311 return QXmlNodeModelIndex::Element;
312 }
313
compareOrder(const QXmlNodeModelIndex &,const QXmlNodeModelIndex &) const314 QXmlNodeModelIndex::DocumentOrder QObjectXmlModel::compareOrder(const QXmlNodeModelIndex& , const QXmlNodeModelIndex& ) const
315 {
316 return QXmlNodeModelIndex::Follows; // TODO
317 }
318
319 //! [0]
root() const320 QXmlNodeModelIndex QObjectXmlModel::root() const
321 {
322 return createIndex(m_root);
323 }
324 //! [0]
325
root(const QXmlNodeModelIndex & n) const326 QXmlNodeModelIndex QObjectXmlModel::root(const QXmlNodeModelIndex& n) const
327 {
328 QObject *p = asQObject(n);
329 Q_ASSERT(p);
330
331 do {
332 QObject *const candidate = p->parent();
333 if (candidate)
334 p = candidate;
335 else
336 break;
337 }
338 while (true);
339
340 return createIndex(p);
341 }
342
343 /*!
344 We simply throw all of them into a QList and
345 return an iterator over it.
346 */
ancestors(const QXmlNodeModelIndex n) const347 QXmlNodeModelIndex::List QObjectXmlModel::ancestors(const QXmlNodeModelIndex n) const
348 {
349 const QObject *p = asQObject(n);
350 Q_ASSERT(p);
351
352 QXmlNodeModelIndex::List result;
353 do {
354 QObject *const candidate = p->parent();
355 if (candidate) {
356 result.append(createIndex(candidate, 0));
357 p = candidate;
358 }
359 else
360 break;
361 }
362 while (true);
363
364 return result;
365 }
366
toMetaProperty(const QXmlNodeModelIndex & n)367 QMetaProperty QObjectXmlModel::toMetaProperty(const QXmlNodeModelIndex &n)
368 {
369 const int propertyOffset = n.additionalData() & (~QObjectProperty);
370 const QObject *const qo = asQObject(n);
371 return qo->metaObject()->property(propertyOffset);
372 }
373
name(const QXmlNodeModelIndex & n) const374 QXmlName QObjectXmlModel::name(const QXmlNodeModelIndex &n) const
375 {
376 switch (toNodeType(n))
377 {
378 case IsQObject:
379 return QXmlName(namePool(), QLatin1String("QObject"));
380 case MetaObject:
381 return QXmlName(namePool(), QLatin1String("metaObject"));
382 case QObjectClassName:
383 case MetaObjectClassName:
384 return QXmlName(namePool(), QLatin1String("className"));
385 case QObjectProperty:
386 return QXmlName(namePool(), toMetaProperty(n).name());
387 case MetaObjects:
388 return QXmlName(namePool(), QLatin1String("metaObjects"));
389 case MetaObjectSuperClass:
390 return QXmlName(namePool(), QLatin1String("superClass"));
391 }
392
393 Q_ASSERT(false);
394 return QXmlName();
395 }
396
typedValue(const QXmlNodeModelIndex & n) const397 QVariant QObjectXmlModel::typedValue(const QXmlNodeModelIndex &n) const
398 {
399 switch (toNodeType(n))
400 {
401 case QObjectProperty:
402 {
403 const QVariant &candidate = toMetaProperty(n).read(asQObject(n));
404 if (isTypeSupported(candidate.type()))
405 return candidate;
406 else
407 return QVariant();
408 }
409
410 case MetaObjectClassName:
411 return QVariant(static_cast<QMetaObject*>(n.internalPointer())->className());
412
413 case MetaObjectSuperClass:
414 {
415 const QMetaObject *const superClass = static_cast<QMetaObject*>(n.internalPointer())->superClass();
416 if (superClass)
417 return QVariant(superClass->className());
418 else
419 return QVariant();
420 }
421
422 case QObjectClassName:
423 return QVariant(asQObject(n)->metaObject()->className());
424
425 default:
426 return QVariant();
427 }
428 }
429
430 /*!
431 Returns \c true if QVariants of type \a type can be used
432 in QtXmlPatterns, otherwise \c false.
433 */
isTypeSupported(QVariant::Type type)434 bool QObjectXmlModel::isTypeSupported(QVariant::Type type)
435 {
436 /* See data/qatomicvalue.cpp too. */
437 switch (type)
438 {
439 /* Fallthrough all these. */
440 case QVariant::Char:
441 case QVariant::String:
442 case QVariant::Url:
443 case QVariant::Bool:
444 case QVariant::ByteArray:
445 case QVariant::Int:
446 case QVariant::LongLong:
447 case QVariant::ULongLong:
448 case QVariant::Date:
449 case QVariant::DateTime:
450 case QVariant::Time:
451 case QVariant::Double:
452 return true;
453 default:
454 return false;
455 }
456 }
457
458 QT_END_NAMESPACE
459