TechDraw: SVG export refactoring - All XML modifications via DOM
This commit is contained in:
committed by
WandererFan
parent
a1ac85bf3f
commit
f4ca09f985
345
src/Mod/TechDraw/App/QDomNodeModel.cpp
Normal file
345
src/Mod/TechDraw/App/QDomNodeModel.cpp
Normal file
@@ -0,0 +1,345 @@
|
||||
// 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.
|
||||
|
||||
|
||||
#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();
|
||||
}
|
||||
Reference in New Issue
Block a user