348 lines
9.8 KiB
C++
348 lines
9.8 KiB
C++
// Copyright (c) 2011 Stanislaw Adaszewski, portions (c) 2019 Tomas Pavlicek
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are met:
|
|
// * Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above copyright
|
|
// notice, this list of conditions and the following disclaimer in the
|
|
// documentation and/or other materials provided with the distribution.
|
|
// * Neither the name of Stanislaw Adaszewski nor the
|
|
// names of other contributors may be used to endorse or promote products
|
|
// derived from this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
// DISCLAIMED. IN NO EVENT SHALL STANISLAW ADASZEWSKI BE LIABLE FOR ANY
|
|
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
// * Used under BSD license 2.0 *
|
|
|
|
#include "PreCompiled.h"
|
|
|
|
#include "QDomNodeModel.h"
|
|
|
|
#include <QDomNode>
|
|
#include <QDomDocument>
|
|
#include <QUrl>
|
|
#include <QVector>
|
|
#include <QSourceLocation>
|
|
#include <QVariant>
|
|
|
|
class PrivateDomNodeWrapper: public QDomNode
|
|
{
|
|
public:
|
|
PrivateDomNodeWrapper(const QDomNode& other):
|
|
QDomNode(other)
|
|
{
|
|
}
|
|
|
|
PrivateDomNodeWrapper(QDomNodePrivate *otherImpl):
|
|
QDomNode(otherImpl)
|
|
{
|
|
}
|
|
|
|
QDomNodePrivate* getImpl()
|
|
{
|
|
return impl;
|
|
}
|
|
};
|
|
|
|
QDomNodeModel::QDomNodeModel(QXmlNamePool pool, QDomDocument doc, bool parsedReadOnly):
|
|
m_Pool(pool), m_Doc(doc), m_ReadOnly(parsedReadOnly)
|
|
{
|
|
|
|
}
|
|
|
|
QUrl QDomNodeModel::baseUri (const QXmlNodeModelIndex &) const
|
|
{
|
|
// TODO: Not implemented.
|
|
return QUrl();
|
|
}
|
|
|
|
#include <QDebug>
|
|
|
|
QXmlNodeModelIndex::DocumentOrder QDomNodeModel::compareOrder (
|
|
const QXmlNodeModelIndex & ni1,
|
|
const QXmlNodeModelIndex & ni2 ) const
|
|
{
|
|
QDomNode n1 = toDomNode(ni1);
|
|
QDomNode n2 = toDomNode(ni2);
|
|
|
|
if (n1 == n2)
|
|
return QXmlNodeModelIndex::Is;
|
|
|
|
if (m_ReadOnly)
|
|
{
|
|
int i1 = n1.lineNumber();
|
|
int i2 = n2.lineNumber();
|
|
|
|
if (i1 < i2)
|
|
return QXmlNodeModelIndex::Precedes;
|
|
|
|
if (i1 > i2)
|
|
return QXmlNodeModelIndex::Follows;
|
|
|
|
i1 = n1.columnNumber();
|
|
i2 = n2.columnNumber();
|
|
|
|
if (i1 < i2)
|
|
return QXmlNodeModelIndex::Precedes;
|
|
|
|
if (i1 > i2)
|
|
return QXmlNodeModelIndex::Follows;
|
|
|
|
return QXmlNodeModelIndex::Is;
|
|
}
|
|
|
|
QVector<QDomNode> p1(path(n1));
|
|
QVector<QDomNode> p2(path(n2));
|
|
|
|
if (p1.at(0) != p2.at(0))
|
|
return QXmlNodeModelIndex::Is; // When root is not common, return obvious nonsense
|
|
|
|
int s = p1.size() < p2.size() ? p1.size() : p2.size();
|
|
for (int i = 1; i < s; ++i)
|
|
{
|
|
if (p1.at(i) != p2.at(i))
|
|
{
|
|
QDomNode c = p1.at(i - 1).firstChild();
|
|
while (!c.isNull())
|
|
{
|
|
if (c == p1.at(i))
|
|
return QXmlNodeModelIndex::Precedes;
|
|
if (c == p2.at(i))
|
|
return QXmlNodeModelIndex::Follows;
|
|
|
|
c = c.nextSibling();
|
|
}
|
|
|
|
return QXmlNodeModelIndex::Is; // Should be impossible!
|
|
}
|
|
}
|
|
|
|
return QXmlNodeModelIndex::Is; // Should be impossible!
|
|
}
|
|
|
|
QUrl QDomNodeModel::documentUri (const QXmlNodeModelIndex&) const
|
|
{
|
|
// TODO: Not implemented.
|
|
return QUrl();
|
|
}
|
|
|
|
QXmlNodeModelIndex QDomNodeModel::elementById ( const QXmlName & id ) const
|
|
{
|
|
return fromDomNode(m_Doc.elementById(id.toClarkName(m_Pool)));
|
|
}
|
|
|
|
QXmlNodeModelIndex::NodeKind QDomNodeModel::kind ( const QXmlNodeModelIndex & ni ) const
|
|
{
|
|
QDomNode n = toDomNode(ni);
|
|
if (n.isAttr())
|
|
return QXmlNodeModelIndex::Attribute;
|
|
else if (n.isText())
|
|
return QXmlNodeModelIndex::Text;
|
|
else if (n.isComment())
|
|
return QXmlNodeModelIndex::Comment;
|
|
else if (n.isDocument())
|
|
return QXmlNodeModelIndex::Document;
|
|
else if (n.isElement())
|
|
return QXmlNodeModelIndex::Element;
|
|
else if (n.isProcessingInstruction())
|
|
return QXmlNodeModelIndex::ProcessingInstruction;
|
|
|
|
return (QXmlNodeModelIndex::NodeKind) 0;
|
|
}
|
|
|
|
QXmlName QDomNodeModel::name ( const QXmlNodeModelIndex & ni ) const
|
|
{
|
|
QDomNode n = toDomNode(ni);
|
|
|
|
if (n.isAttr() || n.isElement()) {
|
|
if (!n.namespaceURI().isEmpty())
|
|
return QXmlName(m_Pool, n.localName(), n.namespaceURI(), n.prefix());
|
|
|
|
QString p = n.prefix();
|
|
QString t = n.nodeName();
|
|
|
|
if (p.isEmpty())
|
|
{
|
|
int c = t.indexOf(QLatin1Char(':'));
|
|
if (c < 0)
|
|
p = QString::fromUtf8("");
|
|
else
|
|
{
|
|
p = t.left(c);
|
|
t = t.mid(c + 1);
|
|
}
|
|
}
|
|
|
|
QVector<QXmlName> ns(namespaceBindings(ni));
|
|
int x;
|
|
for (x = 0; x < ns.size(); ++x)
|
|
if (ns.at(x).prefix(m_Pool) == p) break;
|
|
|
|
if (x < ns.size())
|
|
return QXmlName(m_Pool, t, ns.at(x).namespaceUri(m_Pool), p);
|
|
}
|
|
|
|
return QXmlName(m_Pool, n.nodeName(), QString(), QString());
|
|
}
|
|
|
|
QVector<QXmlName> QDomNodeModel::namespaceBindings(const QXmlNodeModelIndex & ni ) const
|
|
{
|
|
QDomNode n = toDomNode(ni);
|
|
|
|
QVector<QXmlName> res;
|
|
while (!n.isNull())
|
|
{
|
|
QDomNamedNodeMap attrs = n.attributes();
|
|
for (int i = 0; i < attrs.size(); ++i)
|
|
{
|
|
QString a = attrs.item(i).nodeName();
|
|
|
|
QString p;
|
|
if (a == QString::fromUtf8("xmlns"))
|
|
p = QString::fromUtf8("");
|
|
else if (a.startsWith(QString::fromUtf8("xmlns:")))
|
|
p = a.mid(6);
|
|
|
|
if (!p.isNull())
|
|
{
|
|
int x;
|
|
for (x = 0; x < res.size(); ++x)
|
|
if (res.at(x).prefix(m_Pool) == p) break;
|
|
|
|
if (x >= res.size())
|
|
res.append(QXmlName(m_Pool, QString::fromUtf8("xmlns"), attrs.item(i).nodeValue(), p));
|
|
}
|
|
}
|
|
|
|
n = n.parentNode();
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
QVector<QXmlNodeModelIndex> QDomNodeModel::nodesByIdref(const QXmlName&) const
|
|
{
|
|
// TODO: Not implemented.
|
|
return QVector<QXmlNodeModelIndex>();
|
|
}
|
|
|
|
QXmlNodeModelIndex QDomNodeModel::root ( const QXmlNodeModelIndex & ni ) const
|
|
{
|
|
QDomNode n = toDomNode(ni);
|
|
while (!n.parentNode().isNull())
|
|
n = n.parentNode();
|
|
|
|
return fromDomNode(n);
|
|
}
|
|
|
|
QSourceLocation QDomNodeModel::sourceLocation(const QXmlNodeModelIndex&) const
|
|
{
|
|
// TODO: Not implemented.
|
|
return QSourceLocation();
|
|
}
|
|
|
|
QString QDomNodeModel::stringValue ( const QXmlNodeModelIndex & ni ) const
|
|
{
|
|
QDomNode n = toDomNode(ni);
|
|
|
|
if (n.isProcessingInstruction())
|
|
return n.toProcessingInstruction().data();
|
|
else if (n.isText())
|
|
return n.toText().data();
|
|
else if (n.isComment())
|
|
return n.toComment().data();
|
|
else if (n.isElement())
|
|
return n.toElement().text();
|
|
else if (n.isDocument())
|
|
return n.toDocument().documentElement().text();
|
|
else if (n.isAttr())
|
|
return n.toAttr().value();
|
|
|
|
return QString();
|
|
}
|
|
|
|
QVariant QDomNodeModel::typedValue ( const QXmlNodeModelIndex & ni ) const
|
|
{
|
|
return qVariantFromValue(stringValue(ni));
|
|
}
|
|
|
|
QXmlNodeModelIndex QDomNodeModel::fromDomNode(const QDomNode &n) const
|
|
{
|
|
if (n.isNull())
|
|
return QXmlNodeModelIndex();
|
|
|
|
return createIndex(PrivateDomNodeWrapper(n).getImpl(), 0);
|
|
}
|
|
|
|
QDomNode QDomNodeModel::toDomNode(const QXmlNodeModelIndex &ni) const
|
|
{
|
|
return PrivateDomNodeWrapper((QDomNodePrivate*) ni.data());
|
|
}
|
|
|
|
QVector<QDomNode> QDomNodeModel::path(const QDomNode &n) const
|
|
{
|
|
QVector<QDomNode> res;
|
|
QDomNode cur = n;
|
|
while (!cur.isNull())
|
|
{
|
|
res.push_back(cur);
|
|
cur = cur.parentNode();
|
|
}
|
|
|
|
std::reverse(res.begin(), res.end());
|
|
return res;
|
|
}
|
|
|
|
int QDomNodeModel::childIndex(const QDomNode &n) const
|
|
{
|
|
QDomNodeList children = n.parentNode().childNodes();
|
|
for (int i = 0; i < children.size(); i++)
|
|
if (children.at(i) == n)
|
|
return i;
|
|
|
|
return -1;
|
|
}
|
|
|
|
QVector<QXmlNodeModelIndex> QDomNodeModel::attributes ( const QXmlNodeModelIndex & ni ) const
|
|
{
|
|
QDomElement n = toDomNode(ni).toElement();
|
|
QDomNamedNodeMap attrs = n.attributes();
|
|
QVector<QXmlNodeModelIndex> res;
|
|
for (int i = 0; i < attrs.size(); i++)
|
|
{
|
|
res.push_back(fromDomNode(attrs.item(i)));
|
|
}
|
|
return res;
|
|
}
|
|
|
|
QXmlNodeModelIndex QDomNodeModel::nextFromSimpleAxis ( SimpleAxis axis, const QXmlNodeModelIndex & ni) const
|
|
{
|
|
QDomNode n = toDomNode(ni);
|
|
switch(axis)
|
|
{
|
|
case Parent:
|
|
return fromDomNode(n.parentNode());
|
|
|
|
case FirstChild:
|
|
return fromDomNode(n.firstChild());
|
|
|
|
case PreviousSibling:
|
|
return fromDomNode(n.previousSibling());
|
|
|
|
case NextSibling:
|
|
return fromDomNode(n.nextSibling());
|
|
}
|
|
|
|
return QXmlNodeModelIndex();
|
|
}
|