source: trunk/examples/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 13.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 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:BSD$
10** You may use this file under the terms of the BSD license as follows:
11**
12** "Redistribution and use in source and binary forms, with or without
13** modification, are permitted provided that the following conditions are
14** met:
15** * Redistributions of source code must retain the above copyright
16** notice, this list of conditions and the following disclaimer.
17** * Redistributions in binary form must reproduce the above copyright
18** notice, this list of conditions and the following disclaimer in
19** the documentation and/or other materials provided with the
20** distribution.
21** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
22** the names of its contributors may be used to endorse or promote
23** products derived from this software without specific prior written
24** permission.
25**
26** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
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
51QT_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
66QObjectXmlModel::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]
76QXmlNodeModelIndex 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]
97QObjectXmlModel::QObjectNodeType QObjectXmlModel::toNodeType(const QXmlNodeModelIndex &n)
98{
99 return QObjectNodeType(n.additionalData() & (15 << 26));
100}
101//! [1]
102
103//! [9]
104QObjectXmlModel::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
132QXmlNodeModelIndex 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]
146QXmlNodeModelIndex 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]
243QVector<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
279QObject *QObjectXmlModel::asQObject(const QXmlNodeModelIndex &n)
280{
281 return static_cast<QObject *>(n.internalPointer());
282}
283
284bool QObjectXmlModel::isProperty(const QXmlNodeModelIndex n)
285{
286 return n.additionalData() & QObjectProperty;
287}
288
289QUrl QObjectXmlModel::documentUri(const QXmlNodeModelIndex& ) const
290{
291 return m_baseURI;
292}
293
294QXmlNodeModelIndex::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
314QXmlNodeModelIndex::DocumentOrder QObjectXmlModel::compareOrder(const QXmlNodeModelIndex& , const QXmlNodeModelIndex& ) const
315{
316 return QXmlNodeModelIndex::Follows; // TODO
317}
318
319//! [0]
320QXmlNodeModelIndex QObjectXmlModel::root() const
321{
322 return createIndex(m_root);
323}
324//! [0]
325
326QXmlNodeModelIndex 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 */
347QXmlNodeModelIndex::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
367QMetaProperty 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
374QXmlName 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
397QVariant 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 */
434bool 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
458QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.