diff -r 000000000000 -r 1918ee327afb tests/auto/qabstractxmlnodemodel/LoadingModel.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/auto/qabstractxmlnodemodel/LoadingModel.cpp Mon Jan 11 14:00:40 2010 +0000 @@ -0,0 +1,360 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include + +#ifdef QTEST_XMLPATTERNS +#include +#include +#include +#include + +#include "LoadingModel.h" +LoadingModel::LoadingModel(const Node::Vector &content, + const QXmlNamePool &np) : QSimpleXmlNodeModel(np) + , m_nodes(content) +{ + Q_ASSERT(!content.isEmpty()); + /* + foreach(const Node *n, content) + qDebug() << "this:" << n + << "kind:" << n->kind + << "parent: " << n->parent + << "preceding: " << n->precedingSibling + << "following: " << n->followingSibling + << "firstChild: " << n->firstChild + << "value: " << n->value; + */ +} + +LoadingModel::~LoadingModel() +{ + qDeleteAll(m_nodes); +} + +const LoadingModel::Node *LoadingModel::toInternal(const QXmlNodeModelIndex &ni) const +{ + return static_cast(ni.internalPointer()); +} + +QXmlNodeModelIndex LoadingModel::createIndex(const Node *const internal) const +{ + Q_ASSERT_X(internal, Q_FUNC_INFO, + "We shouldn't construct from null pointers."); + return QAbstractXmlNodeModel::createIndex(const_cast(internal)); +} + +QUrl LoadingModel::documentUri(const QXmlNodeModelIndex &) const +{ + Q_ASSERT(false); + return QUrl(); +} + +QXmlNodeModelIndex::NodeKind LoadingModel::kind(const QXmlNodeModelIndex &ni) const +{ + Q_ASSERT(!ni.isNull()); + return toInternal(ni)->kind; +} + +QXmlNodeModelIndex::DocumentOrder LoadingModel::compareOrder(const QXmlNodeModelIndex &n1, const QXmlNodeModelIndex &n2) const +{ + const Node *const in1 = toInternal(n1); + const Node *const in2 = toInternal(n2); + Q_ASSERT(m_nodes.indexOf(in1) != -1); + Q_ASSERT(m_nodes.indexOf(in2) != -1); + + if(in1 == in2) + return QXmlNodeModelIndex::Is; + else if(m_nodes.indexOf(in1) < m_nodes.indexOf(in2)) + return QXmlNodeModelIndex::Precedes; + else + return QXmlNodeModelIndex::Follows; +} + +QXmlNodeModelIndex LoadingModel::root(const QXmlNodeModelIndex &) const +{ + Q_ASSERT(kind(createIndex(m_nodes.first())) == QXmlNodeModelIndex::Document); + return createIndex(m_nodes.first()); +} + +QXmlName LoadingModel::name(const QXmlNodeModelIndex &ni) const +{ + return toInternal(ni)->name; +} + +QVariant LoadingModel::typedValue(const QXmlNodeModelIndex &ni) const +{ + const Node *const internal = toInternal(ni); + + Q_ASSERT(internal->kind == QXmlNodeModelIndex::Attribute + || internal->kind == QXmlNodeModelIndex::Element); + + return internal->value; +} + +QString LoadingModel::stringValue(const QXmlNodeModelIndex &ni) const +{ + const Node *const internal = toInternal(ni); + + switch(internal->kind) + { + case QXmlNodeModelIndex::Text: + /* Fallthrough. */ + case QXmlNodeModelIndex::ProcessingInstruction: + /* Fallthrough. */ + case QXmlNodeModelIndex::Comment: + /* Fallthrough. */ + case QXmlNodeModelIndex::Attribute: + return internal->value; + default: + return QString(); + } +} + +QXmlNodeModelIndex LoadingModel::nextFromSimpleAxis(QAbstractXmlNodeModel::SimpleAxis axis, + const QXmlNodeModelIndex &ni) const +{ + const Node *const internal = toInternal(ni); + + /* Note that a QXmlNodeModelIndex containing a null pointer is not a null node. */ + switch(axis) + { + case Parent: + return internal->parent ? createIndex(internal->parent) : QXmlNodeModelIndex(); + case FirstChild: + return internal->firstChild ? createIndex(internal->firstChild) : QXmlNodeModelIndex(); + case PreviousSibling: + return internal->precedingSibling ? createIndex(internal->precedingSibling) : QXmlNodeModelIndex(); + case NextSibling: + return internal->followingSibling ? createIndex(internal->followingSibling) : QXmlNodeModelIndex(); + } + + Q_ASSERT(false); + return QXmlNodeModelIndex(); +} + +QVector LoadingModel::attributes(const QXmlNodeModelIndex &ni) const +{ + QVector retval; + foreach(const Node *n, toInternal(ni)->attributes) + retval.append(createIndex(n)); + + return retval; +} + +class Loader +{ +public: + inline Loader(const QXmlNamePool &namePool) : m_namePool(namePool) + , m_currentNode(0) + { + m_parentStack.push(0); + } + +private: + inline void adjustSiblings(LoadingModel::Node *const justBorn); + friend class LoadingModel; + Q_DISABLE_COPY(Loader); + + void load(); + + QXmlNamePool m_namePool; + QXmlStreamReader m_reader; + LoadingModel::Node::Vector m_result; + LoadingModel::Node * m_currentNode; + QStack m_parentStack; +}; + +inline void Loader::adjustSiblings(LoadingModel::Node *const justBorn) +{ + if(m_currentNode) + { + if(m_currentNode->parent == justBorn->parent) + justBorn->precedingSibling = m_currentNode; + + m_currentNode->followingSibling = justBorn; + } + + m_currentNode = justBorn; + + /* Otherwise we're the first child, and our precedingSibling should remain null. */ + + if(m_parentStack.top() && !m_parentStack.top()->firstChild) + m_parentStack.top()->firstChild = justBorn; +} + +void Loader::load() +{ + QFile in(QLatin1String("tree.xml")); + + /* LoadingModel::m_result will be null, signalling failure. */ + if(!in.open(QIODevice::ReadOnly)) + return; + + QXmlStreamReader reader(&in); + while(!reader.atEnd()) + { + reader.readNext(); + + switch(reader.tokenType()) + { + case QXmlStreamReader::StartDocument: + /* Fallthrough. */ + case QXmlStreamReader::StartElement: + { + QXmlName name; + if(reader.tokenType() == QXmlStreamReader::StartElement) + { + name = QXmlName(m_namePool, + reader.name().toString(), + reader.namespaceUri().toString(), + reader.prefix().toString()); + } + /* Else, the name is null. */ + + LoadingModel::Node *const tmp = new LoadingModel::Node(reader.tokenType() == QXmlStreamReader::StartElement + ? QXmlNodeModelIndex::Element + : QXmlNodeModelIndex::Document, + m_parentStack.top(), + QString(), + name); + m_result.append(tmp); + + if(m_currentNode) + { + if(m_currentNode->parent == m_parentStack.top()) + m_currentNode->followingSibling = tmp; + } + + const QXmlStreamAttributes attributes(reader.attributes()); + const int len = attributes.count(); + + for(int i = 0; i < len; ++i) + { + const QXmlStreamAttribute &attr = attributes.at(i); + const LoadingModel::Node *const a = new LoadingModel::Node(QXmlNodeModelIndex::Attribute, + m_parentStack.top(), + attr.value().toString(), + QXmlName(m_namePool, + attr.name().toString(), + attr.namespaceUri().toString(), + attr.prefix().toString())); + /* We add it also to m_result such that compareOrder() is correct + * for attributes. m_result owns a. */ + tmp->attributes.append(a); + m_result.append(a); + } + + adjustSiblings(tmp); + m_parentStack.push(m_currentNode); + break; + } + case QXmlStreamReader::EndDocument: + /* Fallthrough. */ + case QXmlStreamReader::EndElement: + { + m_currentNode->followingSibling = 0; + m_currentNode = m_parentStack.pop(); + + if(reader.tokenType() == QXmlStreamReader::EndDocument) + const_cast(m_result.first())->followingSibling = 0; + + break; + } + case QXmlStreamReader::Characters: + { + LoadingModel::Node *const tmp = new LoadingModel::Node(QXmlNodeModelIndex::Text, m_parentStack.top(), reader.text().toString()); + m_result.append(tmp); + adjustSiblings(tmp); + break; + } + case QXmlStreamReader::ProcessingInstruction: + { + LoadingModel::Node *const tmp = new LoadingModel::Node(QXmlNodeModelIndex::ProcessingInstruction, + m_parentStack.top(), + reader.processingInstructionData().toString(), + QXmlName(m_namePool, reader.processingInstructionTarget().toString())); + m_result.append(tmp); + adjustSiblings(tmp); + break; + } + case QXmlStreamReader::Comment: + { + LoadingModel::Node *const tmp = new LoadingModel::Node(QXmlNodeModelIndex::Comment, m_parentStack.top(), reader.text().toString()); + m_result.append(tmp); + adjustSiblings(tmp); + break; + } + case QXmlStreamReader::DTD: + /* Fallthrough. */ + case QXmlStreamReader::EntityReference: + { + Q_ASSERT_X(false, Q_FUNC_INFO, + "We don't support this."); + /* Fallthrough. */ + } + case QXmlStreamReader::NoToken: + /* Fallthrough. */ + case QXmlStreamReader::Invalid: + { + qWarning(qPrintable(reader.errorString())); + m_result.clear(); + return; + } + } + } + + if(reader.hasError()) + { + qWarning(qPrintable(reader.errorString())); + m_result.clear(); + } +} + +QAbstractXmlNodeModel::Ptr LoadingModel::create(const QXmlNamePool &np) +{ + Loader loader(np); + loader.load(); + return Ptr(new LoadingModel(loader.m_result, np)); +} +#endif //QTEST_XMLPATTERNS