1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the test suite of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
45 #include <QXmlNamePool>
46 #include <QXmlStreamReader>
50 #include "LoadingModel.h"
51 LoadingModel::LoadingModel(const Node::Vector &content,
52 const QXmlNamePool &np) : QSimpleXmlNodeModel(np)
56 foreach(const Node *n, content)
57 qDebug() << "this:" << n
59 << "parent: " << n->parent
60 << "preceding: " << n->precedingSibling
61 << "following: " << n->followingSibling
62 << "firstChild: " << n->firstChild
63 << "value: " << n->value;
67 LoadingModel::~LoadingModel()
72 const LoadingModel::Node *LoadingModel::toInternal(const QXmlNodeModelIndex &ni) const
74 return static_cast<const Node *>(ni.internalPointer());
77 QXmlNodeModelIndex LoadingModel::createIndex(const Node *const internal) const
80 qFatal("%s: cannot construct a model index from a null pointer", Q_FUNC_INFO);
81 return QAbstractXmlNodeModel::createIndex(const_cast<Node *>(internal));
84 QUrl LoadingModel::documentUri(const QXmlNodeModelIndex &) const
86 qFatal("%s: This method should not be called during the test", Q_FUNC_INFO);
90 QXmlNodeModelIndex::NodeKind LoadingModel::kind(const QXmlNodeModelIndex &ni) const
93 qFatal("%s: node model index should not be null", Q_FUNC_INFO);
94 return toInternal(ni)->kind;
97 QXmlNodeModelIndex::DocumentOrder LoadingModel::compareOrder(const QXmlNodeModelIndex &n1, const QXmlNodeModelIndex &n2) const
99 const Node *const in1 = toInternal(n1);
100 const Node *const in2 = toInternal(n2);
101 if (m_nodes.indexOf(in1) == -1)
102 qFatal("%s: node n1 is not in internal node list", Q_FUNC_INFO);
103 if (m_nodes.indexOf(in2) == -1)
104 qFatal("%s: node n2 is not in internal node list", Q_FUNC_INFO);
107 return QXmlNodeModelIndex::Is;
108 else if(m_nodes.indexOf(in1) < m_nodes.indexOf(in2))
109 return QXmlNodeModelIndex::Precedes;
111 return QXmlNodeModelIndex::Follows;
114 QXmlNodeModelIndex LoadingModel::root(const QXmlNodeModelIndex &) const
116 if (kind(createIndex(m_nodes.first())) != QXmlNodeModelIndex::Document) {
117 qWarning("%s: first node must be a Document node", Q_FUNC_INFO);
118 return QXmlNodeModelIndex();
120 return createIndex(m_nodes.first());
123 QXmlName LoadingModel::name(const QXmlNodeModelIndex &ni) const
125 return toInternal(ni)->name;
128 QVariant LoadingModel::typedValue(const QXmlNodeModelIndex &ni) const
130 const Node *const internal = toInternal(ni);
132 if (internal->kind != QXmlNodeModelIndex::Attribute
133 && internal->kind != QXmlNodeModelIndex::Element) {
134 qWarning("%s: node must be an attribute or element", Q_FUNC_INFO);
138 return internal->value;
141 QString LoadingModel::stringValue(const QXmlNodeModelIndex &ni) const
143 const Node *const internal = toInternal(ni);
145 switch(internal->kind)
147 case QXmlNodeModelIndex::Text:
149 case QXmlNodeModelIndex::ProcessingInstruction:
151 case QXmlNodeModelIndex::Comment:
153 case QXmlNodeModelIndex::Attribute:
154 return internal->value;
160 QXmlNodeModelIndex LoadingModel::nextFromSimpleAxis(QAbstractXmlNodeModel::SimpleAxis axis,
161 const QXmlNodeModelIndex &ni) const
163 const Node *const internal = toInternal(ni);
165 /* Note that a QXmlNodeModelIndex containing a null pointer is not a null node. */
169 return internal->parent ? createIndex(internal->parent) : QXmlNodeModelIndex();
171 return internal->firstChild ? createIndex(internal->firstChild) : QXmlNodeModelIndex();
172 case PreviousSibling:
173 return internal->precedingSibling ? createIndex(internal->precedingSibling) : QXmlNodeModelIndex();
175 return internal->followingSibling ? createIndex(internal->followingSibling) : QXmlNodeModelIndex();
177 qWarning("%s: unknown axis enum value %d", Q_FUNC_INFO, static_cast<int>(axis));
178 return QXmlNodeModelIndex();
182 QVector<QXmlNodeModelIndex> LoadingModel::attributes(const QXmlNodeModelIndex &ni) const
184 QVector<QXmlNodeModelIndex> retval;
185 foreach(const Node *n, toInternal(ni)->attributes)
186 retval.append(createIndex(n));
194 inline Loader(const QXmlNamePool &namePool) : m_namePool(namePool)
197 m_parentStack.push(0);
201 inline void adjustSiblings(LoadingModel::Node *const justBorn);
202 friend class LoadingModel;
203 Q_DISABLE_COPY(Loader);
207 QXmlNamePool m_namePool;
208 QXmlStreamReader m_reader;
209 LoadingModel::Node::Vector m_result;
210 LoadingModel::Node * m_currentNode;
211 QStack<LoadingModel::Node *> m_parentStack;
214 inline void Loader::adjustSiblings(LoadingModel::Node *const justBorn)
218 if(m_currentNode->parent == justBorn->parent)
219 justBorn->precedingSibling = m_currentNode;
221 m_currentNode->followingSibling = justBorn;
224 m_currentNode = justBorn;
226 /* Otherwise we're the first child, and our precedingSibling should remain null. */
228 if(m_parentStack.top() && !m_parentStack.top()->firstChild)
229 m_parentStack.top()->firstChild = justBorn;
234 QFile in(QLatin1String("tree.xml"));
236 /* LoadingModel::m_result will be null, signalling failure. */
237 if(!in.open(QIODevice::ReadOnly))
240 QXmlStreamReader reader(&in);
241 while(!reader.atEnd())
245 switch(reader.tokenType())
247 case QXmlStreamReader::StartDocument:
249 case QXmlStreamReader::StartElement:
252 if(reader.tokenType() == QXmlStreamReader::StartElement)
254 name = QXmlName(m_namePool,
255 reader.name().toString(),
256 reader.namespaceUri().toString(),
257 reader.prefix().toString());
259 /* Else, the name is null. */
261 LoadingModel::Node *const tmp = new LoadingModel::Node(reader.tokenType() == QXmlStreamReader::StartElement
262 ? QXmlNodeModelIndex::Element
263 : QXmlNodeModelIndex::Document,
267 m_result.append(tmp);
271 if(m_currentNode->parent == m_parentStack.top())
272 m_currentNode->followingSibling = tmp;
275 const QXmlStreamAttributes attributes(reader.attributes());
276 const int len = attributes.count();
278 for(int i = 0; i < len; ++i)
280 const QXmlStreamAttribute &attr = attributes.at(i);
281 const LoadingModel::Node *const a = new LoadingModel::Node(QXmlNodeModelIndex::Attribute,
283 attr.value().toString(),
285 attr.name().toString(),
286 attr.namespaceUri().toString(),
287 attr.prefix().toString()));
288 /* We add it also to m_result such that compareOrder() is correct
289 * for attributes. m_result owns a. */
290 tmp->attributes.append(a);
295 m_parentStack.push(m_currentNode);
298 case QXmlStreamReader::EndDocument:
300 case QXmlStreamReader::EndElement:
302 m_currentNode->followingSibling = 0;
303 m_currentNode = m_parentStack.pop();
305 if(reader.tokenType() == QXmlStreamReader::EndDocument)
306 const_cast<LoadingModel::Node *>(m_result.first())->followingSibling = 0;
310 case QXmlStreamReader::Characters:
312 LoadingModel::Node *const tmp = new LoadingModel::Node(QXmlNodeModelIndex::Text, m_parentStack.top(), reader.text().toString());
313 m_result.append(tmp);
317 case QXmlStreamReader::ProcessingInstruction:
319 LoadingModel::Node *const tmp = new LoadingModel::Node(QXmlNodeModelIndex::ProcessingInstruction,
321 reader.processingInstructionData().toString(),
322 QXmlName(m_namePool, reader.processingInstructionTarget().toString()));
323 m_result.append(tmp);
327 case QXmlStreamReader::Comment:
329 LoadingModel::Node *const tmp = new LoadingModel::Node(QXmlNodeModelIndex::Comment, m_parentStack.top(), reader.text().toString());
330 m_result.append(tmp);
334 case QXmlStreamReader::DTD:
335 qFatal("%s: QXmlStreamReader::DTD token is not supported", Q_FUNC_INFO);
337 case QXmlStreamReader::EntityReference:
338 qFatal("%s: QXmlStreamReader::EntityReference token is not supported", Q_FUNC_INFO);
340 case QXmlStreamReader::NoToken:
342 case QXmlStreamReader::Invalid:
344 qWarning("%s", qPrintable(reader.errorString()));
351 if(reader.hasError())
353 qWarning("%s", qPrintable(reader.errorString()));
358 QAbstractXmlNodeModel::Ptr LoadingModel::create(const QXmlNamePool &np)
362 if (loader.m_result.isEmpty()) {
363 qWarning("%s: attempt to create model with no content", Q_FUNC_INFO);
367 return Ptr(new LoadingModel(loader.m_result, np));