Files correlati : cg0.exe cg0700a.msk cg0700b.msk cg3.exe cg4.exe Bug : Commento: Merge 1.0 libraries
371 lines
14 KiB
C++
371 lines
14 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2015 The Qt Company Ltd.
|
|
** Contact: http://www.qt.io/licensing/
|
|
**
|
|
** This file is part of the test suite of the Qt Toolkit.
|
|
**
|
|
** $QT_BEGIN_LICENSE:LGPL$
|
|
** Commercial License Usage
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
** accordance with the commercial license agreement provided with the
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
** and conditions see http://www.qt.io/terms-conditions. For further
|
|
** information use the contact form at http://www.qt.io/contact-us.
|
|
**
|
|
** 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 or version 3 as published by the Free
|
|
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
|
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
|
** following information to ensure the GNU Lesser General Public License
|
|
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
**
|
|
** As a special exception, The Qt Company gives you certain additional
|
|
** rights. These rights are described in The Qt Company LGPL Exception
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
**
|
|
** GNU General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
** General Public License version 3.0 as published by the Free Software
|
|
** Foundation and appearing in the file LICENSE.GPL included in the
|
|
** packaging of this file. Please review the following information to
|
|
** ensure the GNU General Public License version 3.0 requirements will be
|
|
** met: http://www.gnu.org/copyleft/gpl.html.
|
|
**
|
|
** $QT_END_LICENSE$
|
|
**
|
|
****************************************************************************/
|
|
|
|
#include <QFile>
|
|
#include <QStack>
|
|
|
|
#ifdef QTEST_XMLPATTERNS
|
|
#include <QXmlNamePool>
|
|
#include <QXmlStreamReader>
|
|
#include <QtDebug>
|
|
#include <QTest>
|
|
|
|
#include "LoadingModel.h"
|
|
LoadingModel::LoadingModel(const Node::Vector &content,
|
|
const QXmlNamePool &np) : QSimpleXmlNodeModel(np)
|
|
, m_nodes(content)
|
|
{
|
|
/*
|
|
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<const Node *>(ni.internalPointer());
|
|
}
|
|
|
|
QXmlNodeModelIndex LoadingModel::createIndex(const Node *const internal) const
|
|
{
|
|
if (!internal)
|
|
qFatal("%s: cannot construct a model index from a null pointer", Q_FUNC_INFO);
|
|
return QAbstractXmlNodeModel::createIndex(const_cast<Node *>(internal));
|
|
}
|
|
|
|
QUrl LoadingModel::documentUri(const QXmlNodeModelIndex &) const
|
|
{
|
|
qFatal("%s: This method should not be called during the test", Q_FUNC_INFO);
|
|
return QUrl();
|
|
}
|
|
|
|
QXmlNodeModelIndex::NodeKind LoadingModel::kind(const QXmlNodeModelIndex &ni) const
|
|
{
|
|
if (ni.isNull())
|
|
qFatal("%s: node model index should not be null", Q_FUNC_INFO);
|
|
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);
|
|
if (m_nodes.indexOf(in1) == -1)
|
|
qFatal("%s: node n1 is not in internal node list", Q_FUNC_INFO);
|
|
if (m_nodes.indexOf(in2) == -1)
|
|
qFatal("%s: node n2 is not in internal node list", Q_FUNC_INFO);
|
|
|
|
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
|
|
{
|
|
if (kind(createIndex(m_nodes.first())) != QXmlNodeModelIndex::Document) {
|
|
qWarning("%s: first node must be a Document node", Q_FUNC_INFO);
|
|
return QXmlNodeModelIndex();
|
|
}
|
|
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);
|
|
|
|
if (internal->kind != QXmlNodeModelIndex::Attribute
|
|
&& internal->kind != QXmlNodeModelIndex::Element) {
|
|
qWarning("%s: node must be an attribute or element", Q_FUNC_INFO);
|
|
return QVariant();
|
|
}
|
|
|
|
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();
|
|
default:
|
|
qWarning("%s: unknown axis enum value %d", Q_FUNC_INFO, static_cast<int>(axis));
|
|
return QXmlNodeModelIndex();
|
|
}
|
|
}
|
|
|
|
QVector<QXmlNodeModelIndex> LoadingModel::attributes(const QXmlNodeModelIndex &ni) const
|
|
{
|
|
QVector<QXmlNodeModelIndex> 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<LoadingModel::Node *> 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<LoadingModel::Node *>(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:
|
|
qFatal("%s: QXmlStreamReader::DTD token is not supported", Q_FUNC_INFO);
|
|
break;
|
|
case QXmlStreamReader::EntityReference:
|
|
qFatal("%s: QXmlStreamReader::EntityReference token is not supported", Q_FUNC_INFO);
|
|
break;
|
|
case QXmlStreamReader::NoToken:
|
|
/* Fallthrough. */
|
|
case QXmlStreamReader::Invalid:
|
|
{
|
|
qWarning("%s", qPrintable(reader.errorString()));
|
|
m_result.clear();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(reader.hasError())
|
|
{
|
|
qWarning("%s", qPrintable(reader.errorString()));
|
|
m_result.clear();
|
|
}
|
|
}
|
|
|
|
QAbstractXmlNodeModel::Ptr LoadingModel::create(const QXmlNamePool &np)
|
|
{
|
|
Loader loader(np);
|
|
loader.load();
|
|
if (loader.m_result.isEmpty()) {
|
|
qWarning("%s: attempt to create model with no content", Q_FUNC_INFO);
|
|
return Ptr(0);
|
|
}
|
|
|
|
return Ptr(new LoadingModel(loader.m_result, np));
|
|
}
|
|
#endif //QTEST_XMLPATTERNS
|