Files
qt5-legatus-legacy/Lts/Viewer/SituationMap/GeometryModel/geometry_model_q_dom.cpp
T
2026-08-13 18:33:10 +02:00

2712 lines
108 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
**
** @RDE_HEADER@
** GeometryModel implementation to write and read PlanEditor plans from/to XML and manipulate DOM-tree.
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Stephan Kuhagen <kuhagen@rheinmetall-de.com>
** Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** ??.??.200?, SK : First edition for use with Qt4
** 11.11.2015, JT : Splitting interface and implementation
**
** -----------------------------------------------------------------------------------------------
*/
#include "geometry_model_q_dom.h"
#include <Common/id_handler.h>
#include <QtGui/QFont>
#include <QtGui/QFontMetrics>
#include <QtGui/QTransform>
#include <QtXml/QDomNode>
#include <QtXml/QDomElement>
#include <QCoreApplication>
#include <QDebug>
#include <limits.h>
#include <assert.h>
template<class _Ty, class _Other = _Ty> inline _Ty doExchange(_Ty &_Val, _Other && _New_val)
{
// assign _New_val to _Val, return previous _Val
_Ty _Old_val = std::move(_Val);
_Val = std::forward<_Other>(_New_val);
return (_Old_val);
}
namespace SituationMap
{
const int CoordinateDoublePrecision = 20;
bool GeometryModelQDom::_staticInitDone = false;
QMultiMap< GeometryModel::PrimitiveType , GeometryModel::Attribute > GeometryModelQDom::_primitiveSupportedAttributes;
QMap < QString , GeometryModel::PrimitiveType> GeometryModelQDom::_primitiveTagsTypes;
QMap < GeometryModel::PrimitiveType , QString > GeometryModelQDom::_primitiveTagsStrings;
QMap < QPair<GeometryModel::PrimitiveType, GeometryModel::Attribute>, QString > GeometryModelQDom::_attributeDefaults;
QMap < GeometryModel::Attribute , QVariant::Type > GeometryModelQDom::_attributeTypes;
static const QLatin1String mapSettingsName("MapSettings");
static const QLatin1String rootNodeName("GeometryModel");
static const QLatin1String connectionIdName("connectionId");
static const QLatin1String userDataName("userData");
// convert to QString (with non locale-aware conversions)
QString GeometryModelQDom::variant2XmlString(const QVariant &v)
{
switch (v.type())
{
case QVariant::Int : return QString::fromLatin1(QByteArray::number(v.toInt())); break;
case QVariant::UInt : return QString::fromLatin1(QByteArray::number(v.toUInt())); break;
case QVariant::LongLong : return QString::fromLatin1(QByteArray::number(v.toLongLong())); break;
case QVariant::ULongLong : return QString::fromLatin1(QByteArray::number(v.toULongLong())); break;
case QVariant::Double : return QString::fromLatin1(QByteArray::number(v.toDouble(), 'f', -1)); break;
case QVariant::PointF :
{
const QPointF &point = v.toPointF();
return QString::number(point.x(), 'f', CoordinateDoublePrecision) + QLatin1Char(' ') + QString::number(point.y(), 'f', CoordinateDoublePrecision);
} break;
case QVariant::Color :
{
const QColor &color = v.value<QColor>();
return QStringLiteral("#%1%2%3%4")
.arg(color.red() , 2, 16, QLatin1Char('0'))
.arg(color.green(), 2, 16, QLatin1Char('0'))
.arg(color.blue() , 2, 16, QLatin1Char('0'))
.arg(color.alpha(), 2, 16, QLatin1Char('0'));
} break;
default: break;
}
return v.toString();
} // QString GeometryModelQDom::variant2XmlString( const QVariant & v )
QColor GeometryModelQDom::colorFromString(const QString &attColor)
{
QColor result = Qt::black; // in case of wrong attColor the default is black.
if (attColor.startsWith(QLatin1Char('#')) && attColor.length() == 9)
{
result.setNamedColor(attColor.left(7));
// Get Alpha-Channel
bool ok;
int alpha = attColor.rightRef(2).toInt(&ok, 16);
if (ok) result.setAlpha(alpha);
}
else result.setNamedColor(attColor);
return result;
} // QColor GeometryModelQDom::colorFromString( const QString & attColor )
void GeometryModelQDom::valueFromVariant(const QVariant &v, QPointF &result) { result = GeometryModelQDom::pointFromString(v.toString()); }
void GeometryModelQDom::valueFromVariant(const QVariant &v, QColor &result) { result = GeometryModelQDom::colorFromString(v.toString()); }
QPointF GeometryModelQDom::pointFromString(const QString &attPoint)
{
QPointF result;
const auto xyStrList = attPoint.splitRef(QLatin1Char(' '));
if (xyStrList.size() == 2)
{
bool okX = false;
bool okY = false;
const double &x = xyStrList[0].toDouble(&okX);
const double &y = xyStrList[1].toDouble(&okY);
if (okX && okY)
{
result.setX(x);
result.setY(y);
}
}
return result;
} // QPointF GeometryModelQDom::pointFromString( const QString & attPoint )
#ifdef _WINDOWS
#pragma warning ( disable : 4172 )
#endif
class GeometryModel::Node::Implementation
{
mutable QDomNode _domNode;
static SituationMap::IdHandler *_idHandler;
static SituationMap::IdHandler &idHandler()
{
if (!_idHandler)
_idHandler = new SituationMap::IdHandler();
return *_idHandler;
} // idHandler()
public:
Implementation() : _domNode() {;}
Implementation(const QDomNode &domNode) : _domNode(domNode)
{
// The QDomNode is simply a smart pointer to internal QDom objects. For this the
// QDomNode handles the derived classes itself, so we don't habe to distinguish
// the different QDomNode classes, like QDomElement, QDomAttr ... Just use the copy
// ctor of QDomNode.
} // Implementation(const QDomNode & domNode)
Implementation(const QDomElement &domElement) : _domNode(domElement) {;}
Implementation(const Implementation &other) : Implementation(other._domNode) {;}
~Implementation() = default;
Implementation &operator = (const QDomNode &domNode)
{
_domNode = domNode;
return *this;
} // operator =
Implementation &operator = (const Implementation &other)
{
if (this != &other) _domNode = other._domNode;
return *this;
} // operator =
QDomNode *operator ->() const { return &_domNode; }
const QDomNode &node() const { return _domNode; }
QDomNode &node() { return _domNode; }
bool isValid() const { return !_domNode.isNull(); }
bool isRootNode() const { return (_domNode.nodeName() == rootNodeName); }
bool hasChildNodes() const { return _domNode.hasChildNodes(); }
Node parentNode() const { return Node(Implementation(_domNode.parentNode())); }
Node next() const { return Node(Implementation(_domNode.nextSiblingElement())); }
Node firstChildNode() const { return Node(Implementation(_domNode.firstChildElement())); }
Node firstChildNode(const QString &nodeName) const { return Node(Implementation(_domNode.firstChildElement(nodeName))); }
bool operator == (const Implementation &other) const { return (_domNode == other._domNode); }
bool operator != (const Implementation &other) const { return (_domNode != other._domNode); }
Referenced *connected() const
{
uint id = connectedId();
if (id != SituationMap::IdHandler::BadId)
return static_cast<Referenced *>(idHandler().accessId(id));
return nullptr;
} // connected() const
uint connectedId() const
{
if (isValid())
{
QDomElement e = _domNode.toElement();
if (e.hasAttribute(connectionIdName))
{
QString value = e.attribute(connectionIdName);
bool ok = false;
uint id = value.toUInt(&ok, 10);
if ((ok) && (idHandler().isIdInUse(id)))
return id;
e.removeAttribute(connectionIdName);
}
}
return SituationMap::IdHandler::BadId;
} // connectedId() const
uint makeConnection(Referenced *objPtr)
{
if (objPtr != nullptr)
{
uint id = idHandler().createId(static_cast<IdHandler::AccessableId*>(objPtr));
if (id != SituationMap::IdHandler::BadId)
{
QDomElement e = _domNode.toElement();
e.setAttribute(connectionIdName, id);
return id;
}
}
return SituationMap::IdHandler::BadId;
} // makeConnection(SituationMap::IdHandler::AccessableId * objPtr)
bool unlinkConnection() const
{
uint id = connectedId();
if (id != SituationMap::IdHandler::BadId)
{
idHandler().freeId(id);
QDomElement e = _domNode.toElement();
e.removeAttribute(connectionIdName);
return true;
}
return false;
} // unlinkConnection()
}; // GeometryModel::Node::Implementation
SituationMap::IdHandler *GeometryModel::Node::Implementation::_idHandler = nullptr;
#ifdef _WINDOWS
#pragma warning ( default : 4172 )
#endif
GeometryModel::Node::Node() : _d(new Implementation()) {;}
GeometryModel::Node::Node(const Node &other) : _d(new Implementation(*(other._d))) {;}
GeometryModel::Node::Node(const Implementation &other) : _d(new Implementation(other)) {;}
GeometryModel::Node::~Node() { delete _d; }
GeometryModel::Node &GeometryModel::Node::operator= (const Node &other)
{
if (this != &other) // self-assignment check
{
delete _d;
_d = new Implementation(*(other._d));
}
return *this;
}
GeometryModel::Node &GeometryModel::Node::operator = (Node &&other)
{
if (this != &other) // self-assignment check
{
delete _d;
_d = doExchange(other._d, nullptr);
}
return *this;
}
const GeometryModel::Node::Implementation &GeometryModel::Node::get() const { return *_d; }
GeometryModel::Node::Implementation &GeometryModel::Node::get() { return *_d; }
bool GeometryModel::Node::isValid() const { return _d->isValid(); }
bool GeometryModel::Node::isRootNode() const { return _d->isRootNode(); }
GeometryModel::Node GeometryModel::Node::parentNode() const { return _d->parentNode(); }
bool GeometryModel::Node::hasChildNodes() const { return _d->hasChildNodes(); }
GeometryModel::Node GeometryModel::Node::next() const { return _d->next(); }
GeometryModel::Node GeometryModel::Node::firstChildNode() const { return _d->firstChildNode(); }
GeometryModel::Node GeometryModel::Node::firstChildNode(const QString &nodeName) const { return _d->firstChildNode(nodeName); }
bool GeometryModel::Node::operator ==(const Node &other) const { return ((*_d) == (*(other._d))); }
bool GeometryModel::Node::operator !=(const Node &other) const { return ((*_d) != (*(other._d))); }
uint GeometryModel::Node::makeConnection(Referenced *objPtr) const { return _d->makeConnection(objPtr); }
bool GeometryModel::Node::unlinkConnection() const { return _d->unlinkConnection(); }
uint GeometryModel::Node::connectedId() const { return _d->connectedId(); }
Referenced *GeometryModel::Node::connected() const { return _d->connected(); }
GeometryModelQDom::GeometryModelQDom(QObject *parent)
: GeometryModel(parent)
, QDomDocument(QLatin1String(rootNodeName) + QLatin1String("Document"))
, _skipChangedSignal(false)
, _undoEnabled(true)
, _maxUndoSteps(100)
, _undoStack()
, _undoHistory()
, _redoStack()
, _redoHistory()
, _undoBlock()
, _undoHistoryBlock()
, _insideUndoBlock(false)
, _modificationCounter(0)
{
init();
// OpenSuse13.2:
// Don´t really know why, but ModuleTest::checkOverlayHandler2/3 (dealing with GeometryModel)
// lead to SegFault at end of program, if 'cleanupStaticMember' is not added:
qAddPostRoutine(&GeometryModelQDom::cleanupStaticMember);
} // GeometryModelQDom::GeometryModelQDom(QObject *parent)
GeometryModelQDom::GeometryModelQDom(const GeometryModelQDom &other)
: GeometryModel(other)
, QDomDocument(other.cloneNode().toDocument())
, _skipChangedSignal(false)
, _undoEnabled(other._undoEnabled)
, _maxUndoSteps(other._maxUndoSteps)
, _undoStack()
, _undoHistory()
, _redoStack()
, _redoHistory()
, _undoBlock()
, _undoHistoryBlock()
, _insideUndoBlock(false)
, _modificationCounter(0)
{
} // GeometryModelQDom::GeometryModelQDom(const GeometryModelQDom &other)
GeometryModelQDom::~GeometryModelQDom()
{
cleanModel();
}
GeometryModelQDom & GeometryModelQDom::operator = (const GeometryModelQDom &other)
{
fromByteArray(other.toByteArray());
_undoEnabled = other._undoEnabled;
_maxUndoSteps = other._maxUndoSteps;
return *this;
} // GeometryModelQDom & GeometryModelQDom::operator = (const GeometryModelQDom &other)
/* ~~~~~~~~~~~~~~~~ create XML representation of GeometryModel ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
static void xmlContent( const QDomDocument & domDocument, QByteArray & xmlContent )
{
xmlContent = domDocument.toByteArray(3);
}
template<class MemoryClass> MemoryClass xmlContent(GeometryModelQDom localCopy)
{
MemoryClass xmlContentMem;
// 'clean' just localCopy, not the original
// cleanModel removes userData; in other words: unlink; remove uniqueMapIds
localCopy.cleanModel();
QDomElement rootNode = localCopy.firstChildElement(rootNodeName);
qDebug() << " xmlContent rootNode.isNull " << rootNode.isNull()
<< ", rootNode.hasChildNodes " << rootNode.hasChildNodes()
<< ", rootNode.hasAttributes " << rootNode.hasAttributes();
// rootNode may have ChildNodes and/or Attribute (like metaData)
// pay attention also to attributes
if ((rootNode.isNull()) || !(rootNode.hasChildNodes() || rootNode.hasAttributes()) )
{
qDebug() << " empty -> use constant default string";
// Don't return an empty string because file mamagement service will get an error when loading
// the empty file content.
xmlContentMem = MemoryClass::fromStdString(std::string("<!DOCTYPE GeometryModelDocument>\n<GeometryModel>\n</GeometryModel>"));
}
else
xmlContent( localCopy, xmlContentMem );
qDebug() << " xmlContentMem " << xmlContentMem;
return xmlContentMem;
} // template<class MemoryClass> MemoryClass xmlString(GeometryModelQDom localCopy)
QByteArray GeometryModelQDom::toByteArray() const
{
return xmlContent<QByteArray>(*this);
}
//QString GeometryModelQDom::toString() const
//{
// return xmlContent<QString>(*this);
//}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
QByteArray GeometryModelQDom::toByteArrayDebug() const { return QDomDocument::toByteArray(3); } // complete XML content for debug purposes
/* ~~~~~~~~~~~~~~~~ restore GeometryModel from XML representation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
template<class ContentClass> bool parseXmlString(ContentClass content, GeometryModelQDom &geoModel)
{
qDebug() << " parseXmlString 1";
geoModel.clearUndoStack();
geoModel.clearRedoStack();
geoModel.cleanModel();
bool ok = geoModel.QDomDocument::setContent(content);
qDebug() << " parseXmlString geoModel.cleanModel() " << geoModel.toString();
geoModel.blockSignals(true);
{
geoModel.cleanModel();
qDebug() << " parseXmlString geoModel.cleanModel() " << geoModel.toString();;
QDomElement rootNode = geoModel.firstChildElement(rootNodeName);
if (rootNode.isNull())
{
QDomElement root = geoModel.createElement(rootNodeName);
geoModel.appendChild(root);
}
}
geoModel.blockSignals(false);
qDebug() << " parseXmlString ok = " << ok;
return ok;
} // template<class MemoryClass> bool parseXmlString(MemoryClass memory, GeometryModelQDom &geoModel)
bool GeometryModelQDom::fromByteArray(const QByteArray &content)
{
if (content.isEmpty()) // allow empty content
{
blockSignals(true);
clearModel();
blockSignals(false);
clearUndoStack();
clearRedoStack();
return true;
}
return parseXmlString(content,*this);
} // bool GeometryModelQDom::fromByteArray(const QByteArray &content)
bool GeometryModelQDom::fromDevice(QIODevice *device)
{
if (device->size() < 1) // allow empty content
{
blockSignals(true);
clearModel();
blockSignals(false);
clearUndoStack();
clearRedoStack();
return true;
}
return parseXmlString(device,*this);
} // bool GeometryModelQDom::fromDevice (QIODevice *device)
bool GeometryModelQDom::fromByteArrayDebug(const QByteArray &content)
{
clearUndoStack();
clearRedoStack();
cleanModel();
return QDomDocument::setContent(content);
} // bool GeometryModelQDom::fromStringDebug(const QByteArray &content)
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
void GeometryModelQDom::setModelAttribute(Attribute attribute, const QVariant &value)
{
QDomElement root = firstChildElement(rootNodeName);
qDebug() << "GeometryModelQDom isNull = " << root.isNull();
//const bool bEnableUndoRedo = true; //attribute != Attribute::MetaPixelBasedTextBoxes;
pushUndo(QLatin1String("setModelAttribute"));
if (supportedAttributes(PrimitiveType::RootNode).contains(attribute))
root.setAttribute(attributeToString(attribute), variant2XmlString(value));
else
{
emit attributeError(tr("Unknown or unsupported attribute for model root node: %1").arg(attributeToString(attribute)));
popUndo();
return;
}
emitChangedSignal(Node(), attribute, false);
} // void GeometryModelQDom::setModelAttribute(Attribute attribute, const QVariant &value)
QVariant GeometryModelQDom::getModelAttribute(Attribute attribute) const
{
QDomElement root = firstChildElement(rootNodeName);
if (supportedAttributes(PrimitiveType::RootNode).contains(attribute))
return getAttribute(root, attribute);
else
emit const_cast<GeometryModelQDom*>(this)->attributeError(tr("Unknown or unsupported attribute for model root node: %1").arg(attributeToString(attribute)));
return QVariant();
} // QVariant GeometryModelQDom::getModelAttribute(Attribute attribute) const
void GeometryModelQDom::setModelEditorAttribute(Attribute attribute, const QVariant &value)
{
QDomElement root = firstChildElement(mapSettingsName);
switch (attribute)
{
case Attribute::PeMapBrightness:
case Attribute::PeMapCenterX:
case Attribute::PeMapCenterY:
case Attribute::PeMapSaturation:
case Attribute::PeMapZoom:
case Attribute::PeShowUtm:
case Attribute::PeSymbolOpacity:
case Attribute::PeSymbolFillType:
case Attribute::PeSymbolScale:
case Attribute::PeMapRotation:
case Attribute::PeMapType:
root.setAttribute(attributeToString(attribute), variant2XmlString(value));
break;
default:
emit attributeError(tr("Unknown or unsupported attribute for model-editor: %1").arg(attributeToString(attribute)));
return;
}
emitChangedSignal(Node(), attribute, false);
} // void GeometryModelQDom::setModelEditorAttribute(Attribute attribute, const QVariant &value)
void GeometryModelQDom::setPrimitiveAttribute(const Node &node, Attribute attribute, const QVariant &value)
{
pushUndo(QLatin1String("setPrimitiveAttribute"));
// Check, if Attribute is supported by Primitive; if so, set it
if (hasAttribute(node, attribute))
node.get()->toElement().setAttribute(attributeToString(attribute), variant2XmlString(value));
else
{
emit attributeError(tr("Unknown or unsupported attribute for primitive: %1, Attribute: %2").arg(node.get()->nodeName(), attributeToString(attribute)));
popUndo();
return;
}
emitChangedSignal(node, attribute, false);
} // void GeometryModelQDom::setPrimitiveAttribute(QDomNode node...)
GeometryModel::Node GeometryModelQDom::addPrimitive( PrimitiveType type
, const QList<QPointF> &points
, const QList<QPair<Attribute, QVariant> > &attributes
, int userData
, const QString &textData
, HorizontalAlign textAlign)
{
QDomElement root = firstChildElement(rootNodeName);
bool undoEnabledRestore = _undoEnabled;
pushUndo(QLatin1String("addPrimitive"));
_undoEnabled = false;
// Create new node and set required attributes
QDomElement primitiveDom;
if (_primitiveTagsStrings.contains(type))
primitiveDom = createElement(_primitiveTagsStrings[type]);
else
{
emit typeError(tr("Unknown Primitive-Type %1").arg(static_cast<int>(type)));
_undoEnabled = undoEnabledRestore;
popUndo();
return Node();
}
Node primitiveNode(primitiveDom);
// No changed() inside this block
_skipChangedSignal = true;
if (setPrimitivePoints(Node(primitiveDom), points))
{
// Init Primitive with default-Values
using index = QPair<GeometryModelQDom::PrimitiveType, GeometryModelQDom::Attribute>;
QList<Attribute> primAttributes = supportedAttributes(type);
for (int i = 0; i < primAttributes.size(); ++i)
{
Attribute ap = primAttributes.at(i);
setPrimitiveAttribute(primitiveNode, ap, _attributeDefaults[index(type, ap)]);
}
// Set Attributes given as parameter
for (int i = 0; i < attributes.size(); ++i)
setPrimitiveAttribute(primitiveNode, (attributes.at(i)).first, (attributes.at(i)).second);
// Add textData, if any
if (! textData.isNull())
setTextData(primitiveNode, textData, textAlign);
// Insert userData as Attribute
if ((type != PrimitiveType::Node) && (type != PrimitiveType::RootNode))
{
if (SituationMap::IdHandler::isIdValid(userData))
{
QString userDataStr = QString::number(userData, 10);
primitiveDom.setAttribute(userDataName, userDataStr);
}
}
Node result(root.appendChild(primitiveDom));
_skipChangedSignal = false;
emitChangedSignal(result, Attribute::MaxAttributes, true);
_undoEnabled = undoEnabledRestore;
return result;
}
else
{
_undoEnabled = undoEnabledRestore;
popUndo();
return Node();
}
} // QDomNode GeometryModelQDom::addPrimitive(PrimitiveType type, ...)
GeometryModel::Node GeometryModelQDom::addText(const Node &parent
, const QString &textData
, HorizontalAlign textAlign
, const QList<QPair<Attribute, QVariant> > &attributes
, int userData)
{
pushUndo(QLatin1String("addText"));
// Check, if parent is of correct type
QString tag = parent.get()->nodeName();
PrimitiveType type = getType(parent);
// Get Position (center of bounding box)
// TODO: Position of text depends on Parent-Type
// TODO: on moveNode, translateNode,... transform text also
QRectF parentBox = getBoundingBox(parent);
QList<QPointF> pointList;
switch (type)
{
case PrimitiveType::Ellipse:
case PrimitiveType::Line:
case PrimitiveType::Polyline:
case PrimitiveType::Rectangle:
case PrimitiveType::Spline:
pointList.append(parentBox.topLeft());
break;
default:
emit typeError(tr("Can not add text to type %1").arg(tag));
popUndo();
return Node();
}
// Create Text-Node and reparent to parent
Node textNode(addPrimitive(PrimitiveType::Text, pointList, attributes, userData));
parent.get()->appendChild(textNode.get().node());
// Set textData and alignment
QDomElement textDataNode = (textNode.get()->appendChild(createElement(QLatin1String("text_data")))).toElement();
textDataNode.setAttribute(QLatin1String("alignment"), QString::number((int)textAlign, 10));
QDomCDATASection cdata = createCDATASection(textData);
emitChangedSignal(parent, Attribute::MaxAttributes, false);
return Node(Node::Implementation(textDataNode.appendChild(cdata)));
} // QDomNode GeometryModelQDom::addText(QDomNode parent, const QString &textData,...
GeometryModel::Node GeometryModelQDom::getRootNode() const { return Node(Node::Implementation(firstChildElement(rootNodeName))); }
bool GeometryModelQDom::isEmpty() const
{
QDomElement rootNode = firstChildElement(rootNodeName);
return (!rootNode.hasChildNodes());
} // bool GeometryModelQDom::isEmpty() const
GeometryModel::Node GeometryModelQDom::getText(const Node &parent) const
{
// Check, if parent is of correct type
PrimitiveType type = getType(parent);
switch (type)
{
case PrimitiveType::Ellipse:
case PrimitiveType::Line:
case PrimitiveType::Polyline:
case PrimitiveType::Rectangle:
case PrimitiveType::Spline:
return Node(Node::Implementation(parent.get()->firstChildElement(QLatin1String("text"))));
default:
return Node();
}
} // QDomNode GeometryModelQDom::getText(QDomNode parent)
QString GeometryModelQDom::getTextData(const Node &node) const
{
QString result;
// Check, if parent is of correct type
QString tag = node.get()->nodeName();
if (tag != QLatin1String("text"))
emit const_cast<GeometryModelQDom*>(this)->typeError(tr("Can not get text-data from %1").arg(tag));
else
{
QDomNode textData = node.get()->firstChildElement(QLatin1String("text_data"));
QDomNode data = textData.firstChild();
if (! data.isNull())
result = data.nodeValue();
}
return result;
} // QString GeometryModelQDom::getTextData(QDomNode textNode)
QList<QPointF> GeometryModelQDom::getPrimitivePoints(const Node &node) const { return getPrimitivePoints(node.get().node()); }
QList<QPointF> GeometryModelQDom::getPrimitivePoints(const QDomNode &node) const
{
const QString &tag = node.nodeName();
PrimitiveType type = getType(node);
// set the number of required points for this primitive...
QList<QPointF> result;
int minPoints = 0;
int maxPoints = 0;
switch (type)
{
case PrimitiveType::DictionarySymbol:
{
minPoints = 1;
maxPoints = INT_MAX;
} break;
case PrimitiveType::Ellipse:
case PrimitiveType::Rectangle:
{
minPoints = 4;
maxPoints = 4;
} break;
case PrimitiveType::ParticipantSymbol:
case PrimitiveType::Symbol:
case PrimitiveType::Text:
{
minPoints = 1;
maxPoints = 1;
} break;
case PrimitiveType::Line:
{
minPoints = 2;
maxPoints = 2;
} break;
case PrimitiveType::Polyline:
case PrimitiveType::Spline:
{
minPoints = 3;
maxPoints = INT_MAX;
} break;
default:
{
emit const_cast<GeometryModelQDom*>(this)->modelError(tr("No points in primitive of type %1").arg(tag));
return result;
}
} // switch
// ... and get the points
QDomNodeList nodes = node.childNodes();
if (nodes.isEmpty())
emit const_cast<GeometryModelQDom*>(this)->modelError(tr("No points found in primitive of type %1").arg(tag));
else
{
for (int i = 0; i < nodes.size(); ++i)
{
QDomElement p = nodes.at(i).toElement();
if (p.nodeName() != QLatin1String("point")) continue;
if (!p.hasAttribute(QLatin1String("x")) || !p.hasAttribute(QLatin1String("y")))
emit const_cast<GeometryModelQDom*>(this)->modelError(tr("Invalid point in primitive of type %1").arg(tag));
else
{
bool okx, oky;
double x = p.toElement().attribute(QLatin1String("x")).toDouble(&okx);
double y = p.toElement().attribute(QLatin1String("y")).toDouble(&oky);
if (!(okx && oky))
emit const_cast<GeometryModelQDom*>(this)->modelError(tr("Invalid point in primitive of type %1").arg(tag));
else
result.append(QPointF(x, y));
}
}
}
// Check points
if ((result.size() < minPoints) || (result.size() > maxPoints))
emit const_cast<GeometryModelQDom*>(this)->attributeError(tr("Wrong number of points for new primitive %1").arg(_primitiveTagsStrings[type]));
return result;
} // QList<QPointF> GeometryModelQDom::getPrimitivePoints(QDomNode node) const
QRectF GeometryModelQDom::getBoundingBox(const Node &node) const { return getBoundingBox(node.get().node()); }
QRectF GeometryModelQDom::getBoundingBox(const QDomNode &node) const
{
PrimitiveType type = getType(node);
QRectF result;
if ((type == PrimitiveType::Node) || (type == PrimitiveType::RootNode) || (node == *this))
{
// Recursive over all children
QRectF merge;
QDomNodeList children;
if ((type == PrimitiveType::Node) || (type == PrimitiveType::RootNode))
{
// Children of other Node
children = node.childNodes();
}
else
children = node.firstChildElement(rootNodeName).childNodes();
for (int i = 0; i < children.size(); ++i)
{
merge = getBoundingBox(children.at(i));
if (! merge.isNull())
result = result.isNull() ? merge : result.united(merge);
}
}
else
{
// TODO Add calculation for rotated Primitives
bool ok;
QList<QPointF> points = getPrimitivePoints(node);
double width, height;
switch (type)
{
case PrimitiveType::Ellipse:
case PrimitiveType::Rectangle:
width = getAttribute(node, Attribute::Width).toDouble(&ok);
height = getAttribute(node, Attribute::Height).toDouble(&ok);
if (ok && (points.size() == 1))
{
result.setRect(points[0].x(), points[0].y(), width, height);
result.moveCenter(points[0]);
}
break;
case PrimitiveType::Line:
if (points.size() == 2)
result = QRectF(points[0], points[1]).normalized();
break;
case PrimitiveType::DictionarySymbol:
if (points.size() > 2)
{
result = QRectF(points.at(0), points.at(1));
for (int i = 2; i < points.count(); ++i)
result = result.united(QRectF(points.at(0), points.at(i)));
}
else
{
result = QRectF(points[0].x(), points[0].y(), 1.0, 1.0);
result.moveCenter(points[0]);
}
break;
case PrimitiveType::Polyline:
case PrimitiveType::Spline:
if (points.size() > 2)
{
result = QRectF(points.at(0), points.at(1));
for (int i = 2; i < points.count(); ++i)
result = result.united(QRectF(points.at(0), points.at(i)));
}
break;
case PrimitiveType::ParticipantSymbol:
case PrimitiveType::Symbol:
case PrimitiveType::Text:
if (points.size() == 1)
{
// TODO Calculate real dimensions of Textbox and Symbol?
// Only possible with more information from GDW implementation, Map Scale etc.
result = QRectF(0, 0, 0, 0);
result.moveCenter(points[0]);
}
break;
default:
break;
}
} // if ( type == Node ) {...} else...
return result;
} // QRectF GeometryModelQDom::getBoundingBox(QDomNode node)
void GeometryModelQDom::movePrimitiveIntoGroup(const Node &primitive, const Node &target)
{
pushUndo(QLatin1String("movePrimitiveIntoGroup"));
QString tag = primitive.get()->nodeName();
if (target.get()->nodeName() != QLatin1String("node"))
{
emit typeError(tr("Can not move primitive into %1").arg(target.get()->nodeName()));
popUndo();
return;
}
if (_primitiveTagsTypes.contains(tag))
{
target.get()->appendChild(primitive.get().node());
emitChangedSignal(primitive, Attribute::MaxAttributes, false);
}
} // void GeometryModelQDom::movePrimitiveIntoGroup(QDomNode primitive, QDomNode target)
void GeometryModelQDom::releaseGroup(const Node &group)
{
pushUndo(QLatin1String("releaseGroup"));
if (group.get()->nodeName() != QLatin1String("node"))
{
emit typeError(tr("Given node is not a group: %1").arg(group.get()->nodeName()));
popUndo();
return;
}
QDomNode parent = group.get()->parentNode();
while (group.get()->hasChildNodes())
parent.appendChild(group.get()->firstChild());
parent.removeChild(group.get().node());
emitChangedSignal(Node(), Attribute::MaxAttributes, false);
} // void GeometryModelQDom::releaseGroup(QDomNode group)
void GeometryModelQDom::deleteGroup(const Node &group)
{
if (!group.isValid()) return;
pushUndo(QLatin1String("deleteGroup"));
if (group.get()->nodeName() != QLatin1String("node"))
{
emit typeError(tr("Given node is not a group: %1").arg(group.get()->nodeName()));
popUndo();
return;
}
QDomNode parent = group.get()->parentNode();
parent.removeChild(group.get().node());
emitChangedSignal(Node(), Attribute::MaxAttributes, false);
} // void GeometryModelQDom::deleteGroup(QDomNode group)
void GeometryModelQDom::removePrimitive(const Node &primitive)
{
_skipChangedSignal = true;
removePrimitive(primitive.get().node());
_skipChangedSignal = false;
}
void GeometryModelQDom::removePrimitive(const QDomNode &primitive)
{
// could be a group node
while (primitive.hasChildNodes())
{
removePrimitive(primitive.firstChild());
}
// Remove userData
bool ok;
int userData = getUserData(primitive, &ok);
if (ok)
{
primitive.toElement().removeAttribute(userDataName);
emit userDataCleanup(userData);
}
// pushUndo() here, because we must not save the primitive with userData, since
// the GeISiR2-Primitive is removed from the Map
pushUndo(QLatin1String("removePrimitive"));
QDomNode parent = primitive.parentNode();
QDomNode oldChild = parent.removeChild(primitive);
if (! oldChild.isNull())
emitChangedSignal(Node(), Attribute::MaxAttributes, false);
else popUndo();
} // void GeometryModelQDom::removePrimitive(QDomNode primitive)
void GeometryModelQDom::removePrimitivesByUserData(const QList<int> &userDataList)
{
_skipChangedSignal = true;
int removed = 0;
// First delete userData, then make the undo-backup
QList<QDomNode> nodeList;
nodeList.reserve(userDataList.size());
for (int i = 0; i < userDataList.size(); ++i)
{
Node node = findPrimitive(userDataList.at(i));
node.get()->toElement().removeAttribute(userDataName);
nodeList.append(node.get().node());
}
startUndoBlock();
for (int i = 0; i < nodeList.size(); ++i)
{
removePrimitive(nodeList.at(i));
++removed;
}
endUndoBlock(QLatin1String("removePrimitivesByUserData"));
_skipChangedSignal = false;
if (removed > 0)
emitChangedSignal(Node(), Attribute::MaxAttributes, false);
} // void GeometryModelQDom::removePrimitivesByUserData(QList<int> userDataList)
void GeometryModelQDom::removeText(Node &parent)
{
pushUndo(QLatin1String("removeText"));
// Check, if parent is of correct type
PrimitiveType type = getType(parent);
switch (type)
{
case PrimitiveType::Ellipse:
case PrimitiveType::Line:
case PrimitiveType::Polyline:
case PrimitiveType::Rectangle:
case PrimitiveType::Spline:
parent.get()->removeChild(parent.get()->firstChildElement(QLatin1String("text")));
emitChangedSignal(parent, Attribute::MaxAttributes, false);
break;
default:
popUndo();
return;
}
} // void GeometryModelQDom::removeText(QDomNode parent)
void GeometryModelQDom::setTextData(const Node &textNode, const QString &data, HorizontalAlign textAlign)
{
pushUndo(QLatin1String("setTextData"));
// Check, if parent is of correct type
const QString &tag = textNode.get()->nodeName();
if (tag != QLatin1String("text"))
{
emit typeError(tr("Can not set text-data for %1").arg(tag));
popUndo();
}
else
{
QDomNode textData = textNode.get()->firstChildElement(QLatin1String("text_data"));
if (textData.isNull())
textData = (textNode.get()->appendChild(createElement(QLatin1String("text_data")))).toElement();
textData.toElement().setAttribute(QLatin1String("alignment"), QString::number((int)textAlign, 10));
textData.removeChild(textData.firstChild());
textData.appendChild(createCDATASection(data));
emitChangedSignal(textNode, Attribute::MaxAttributes, false);
}
} // void GeometryModelQDom::setTextData(QDomNode textNode, const QString &data, HorizontalAlign textAlign)
void GeometryModelQDom::clearModel()
{
qDebug() << " GeometryModelQDom::clearModel()";
QDomElement root = firstChildElement(rootNodeName);
pushUndo(QLatin1String("clearPlan"));
bool oldSCS = _skipChangedSignal;
bool oldUE = _undoEnabled;
_skipChangedSignal = true;
_undoEnabled = false;
while (root.hasChildNodes())
removePrimitive(root.firstChild());
_skipChangedSignal = oldSCS;
_undoEnabled = oldUE;
const auto supportedAttribs = supportedAttributes(GeometryModel::PrimitiveType::RootNode);
for (const GeometryModel::Attribute &attr : supportedAttribs)
{
const QString & attrName = attributeToString(attr);
if (root.hasAttribute(attrName))
{
root.removeAttribute(attrName);
}
}
emitChangedSignal(Node(), Attribute::MaxAttributes, false);
} // void GeometryModelQDom::clearModel()
bool GeometryModelQDom::setPrimitivePoints(const Node &node, const QList<QPointF> &points)
{
PrimitiveType type = getType(node);
// Check number of points and insert them
int minPoints = 0;
int maxPoints = 0;
switch (type)
{
case PrimitiveType::DictionarySymbol:
{
minPoints = 1;
maxPoints = INT_MAX;
} break;
case PrimitiveType::Ellipse:
case PrimitiveType::Rectangle:
{
minPoints = 4;
maxPoints = 4;
} break;
case PrimitiveType::ParticipantSymbol:
case PrimitiveType::Symbol:
case PrimitiveType::Text:
{
minPoints = 1;
maxPoints = 1;
} break;
case PrimitiveType::Line:
{
minPoints = 2;
maxPoints = 2;
} break;
case PrimitiveType::Polyline:
case PrimitiveType::Spline:
{
minPoints = 3;
maxPoints = INT_MAX;
} break;
case PrimitiveType::RootNode:
case PrimitiveType::Node:
{
if (points.isEmpty()) return true;
} break;
default: break;
}
if ((points.size() < minPoints) || (points.size() > maxPoints))
{
emit attributeError(tr("Wrong number of points for primitive %1").arg(_primitiveTagsStrings[type]));
return false;
}
else
{
pushUndo(QLatin1String("setPrimitivePoints"));
// Remove old Points before Adding
QDomElement p = node.get()->firstChildElement(QLatin1String("point"));
while (! p.isNull())
{
node.get()->removeChild(p);
p = node.get()->firstChildElement(QLatin1String("point"));
}
for (int i = 0; i < points.size(); ++i)
{
QDomElement point = (node.get()->appendChild(createElement(QLatin1String("point")))).toElement();
// QString::number() does NOT honor locale settings:
point.setAttribute(QLatin1String("x"), QString::number(points.at(i).x(), 'f', CoordinateDoublePrecision)); // to enforce "1.23" instead of "1,23"
point.setAttribute(QLatin1String("y"), QString::number(points.at(i).y(), 'f', CoordinateDoublePrecision));
}
emitChangedSignal(node, Attribute::None, true);
}
return true;
} // bool GeometryModelQDom::setPrimitivePoints(QDomNode node, QList<QPointF> points)
void GeometryModelQDom::translateNode(const Node &node, double x, double y) { translateNode(node.get().node(), x, y); }
void GeometryModelQDom::translateNode(const QDomNode &node, double x, double y)
{
pushUndo(QLatin1String("translateNode"));
QTransform t;
t = t.translate(x, y);
if (node == *this)
{
// translate complete plan
QDomElement root = node.firstChildElement(rootNodeName);
QDomNodeList children = root.childNodes();
// No changed() inside this block
_skipChangedSignal = true;
for (int i = 0; i < children.size(); ++i)
translateNode(children.at(i), x, y);
_skipChangedSignal = false;
}
else
{
QString tag = node.nodeName();
if (tag == QLatin1String("node"))
{
QDomNodeList children = node.childNodes();
for (int i = 0; i < children.size(); ++i)
translateNode(children.at(i), x, y);
}
else
transformNode(node, t);
}
emitChangedSignal(Node(Node::Implementation(node)), Attribute::None, true);
} // void GeometryModelQDom::translateNode(QDomNode node, double x, double y)
void GeometryModelQDom::moveNode(const Node &node, double x, double y) { moveNode(node.get().node(), x, y); }
void GeometryModelQDom::moveNode(const QDomNode &node, double x, double y)
{
pushUndo(QLatin1String("moveNode"));
// Move to (x,y)
QRectF bb = getBoundingBox(node);
QPointF center = bb.center();
translateNode(node, -center.x() + x, -center.y() + y);
emitChangedSignal(Node(Node::Implementation(node)), Attribute::None, true);
} // void GeometryModelQDom::moveNode(QDomNode node, double x, double y)
void GeometryModelQDom::scaleNode(const Node &node, double scaleX, double scaleY) { scaleNode(node.get().node(), scaleX, scaleY); }
void GeometryModelQDom::scaleNode(const QDomNode &node, double scaleX, double scaleY)
{
pushUndo(QLatin1String("scaleNode"));
// Translate to (0.0, 0.0)
QRectF bb = getBoundingBox(node);
QPointF center = bb.center();
translateNode(node, -center.x(), -center.y());
// Scale
QTransform t;
t = t.scale(scaleX, scaleY);
QString tag = node.nodeName();
if (tag == QLatin1String("node"))
{
QDomNodeList children = node.childNodes();
for (int i = 0; i < children.size(); ++i)
transformNode(children.at(i), t);
}
else transformNode(node, t);
// Translate back
translateNode(node, center.x(), center.y());
emitChangedSignal(Node(Node::Implementation(node)), Attribute::None, true);
} // void GeometryModelQDom::scaleNode(QDomNode node, double scaleX, double scaleY)
void GeometryModelQDom::rotateNode(const Node &node, double angle) { rotateNode(node.get().node(), angle); }
void GeometryModelQDom::rotateNode(const QDomNode &node, double angle)
{
pushUndo(QLatin1String("rotateNode"));
// Translate to (0.0, 0.0)
QRectF bb = getBoundingBox(node);
QPointF center = bb.center();
translateNode(node, -center.x(), -center.y());
// Rotate
QTransform t;
t = t.rotate(angle);
QString tag = node.nodeName();
if (tag == QLatin1String("node"))
{
QDomNodeList children = node.childNodes();
for (int i = 0; i < children.size(); ++i)
transformNode(children.at(i), t);
}
else transformNode(node, t);
// Translate back
translateNode(node, center.x(), center.y());
emitChangedSignal(Node(Node::Implementation(node)), Attribute::Rotate, true);
} // void GeometryModelQDom::rotateNode(QDomNode node, double angle)
void GeometryModelQDom::reorderPrimitives(const NodeList &nodes, PrimitivOrder order)
{
QDomElement root = firstChildElement(rootNodeName);
if (nodes.length() > 0)
{
pushUndo(QLatin1String("reorderPrimitives"));
if (order == GeometryModelQDom::PrimitivOrder::Lower)
{
QDomNode before;
for (int i = nodes.length() - 1; i >= 0; --i)
before = root.insertBefore(nodes.at(i).get().node(), before);
}
else if (order == GeometryModelQDom::PrimitivOrder::Raise)
{
for (int i = 0; i < nodes.length(); ++i)
root.insertAfter(nodes.at(i).get().node(), QDomNode());
}
emitChangedSignal(Node(), Attribute::MaxAttributes, false);
}
} // void GeometryModelQDom::reorderPrimitives(const QList<QDomNode> &nodes, t_PrimOrder order)
void GeometryModelQDom::merge(const Node &other, bool skipUndo, bool intoNewGroup) { merge(other.get().node(), skipUndo, intoNewGroup); }
void GeometryModelQDom::merge(GeometryModel *other, bool skipUndo, bool intoNewGroup)
{
const GeometryModelQDom *otherQDom = dynamic_cast<GeometryModelQDom *>(other);
merge(*otherQDom, skipUndo, intoNewGroup);
} // void GeometryModelQDom::merge( GeometryModel * other, bool skipUndo, bool intoNewGroup )
void GeometryModelQDom::merge(const QDomNode &other, bool skipUndo, bool intoNewGroup)
{
if ((other == *this) || (other.ownerDocument() == *this))
{
// Do not merge with itself or own child
return;
}
if (! skipUndo)
pushUndo(QLatin1String("merge"));
QString tag = other.nodeName();
if (other.nodeType() == QDomNode::DocumentNode)
{
// Its a complete plan, add recursive
QDomElement root = other.firstChildElement(rootNodeName);
// No changed() inside this block
_skipChangedSignal = true;
if (intoNewGroup)
{
QList<QDomNode> nodeList;
QDomNodeList domNodeList = root.childNodes();
nodeList.reserve(domNodeList.size());
for (int i = 0; i < domNodeList.size(); ++i)
nodeList.append(domNodeList.at(i));
const QDomNode &group = createGroup(nodeList);
setNodeDisplayName(Node(group), tr("Imported Group"));
}
else
{
while (root.hasChildNodes())
merge(root.firstChild(), true);
}
_skipChangedSignal = false;
}
else if ((getType(other) == PrimitiveType::Unknown) || (getType(other) == PrimitiveType::MapDefaults))
{
// Unknown type error
emit typeError(tr("Can not merge with %1").arg(tag));
if (! skipUndo)
popUndo();
return;
}
else
{
// Insert
QDomElement docRoot = firstChildElement(rootNodeName);
docRoot.appendChild(other);
}
emitChangedSignal(Node(), Attribute::MaxAttributes, false);
} // void PlanModel::merge(QDomNode other, bool skipUndo, bool intoNewGroup)
unsigned int GeometryModelQDom::modificationCounter() const { return _modificationCounter; }
void GeometryModelQDom::resetModificationCounter()
{
_modificationCounter = 0;
emit modificationCount(_modificationCounter);
} // void GeometryModelQDom::resetModificationCounter()
void GeometryModelQDom::undo(unsigned int steps)
{
if (undoSteps() < 1) return;
if (steps < 1) return;
if (_insideUndoBlock)
endUndoBlock();
emit nodeCleanup(Node(firstChildElement(rootNodeName)));
while ((steps > 0) && (undoSteps() > 0))
{
QDomNode root = firstChildElement(rootNodeName);
QDomNode undoNode = _undoStack.pop();
_redoStack.push(root.cloneNode());
_redoHistory.push(_undoHistory.pop());
root = replaceChild(undoNode, root);
if (root.isNull()) // was replaceChild successful?
{
emit criticalError(tr("Undo function failed."));
break;
}
else
{
--steps;
}
--_modificationCounter;
emit modificationCount(_modificationCounter);
}
emitChangedSignal(Node(), Attribute::MaxAttributes, true);
} // void GeometryModelQDom::undo(unsigned int steps)
void GeometryModelQDom::redo(unsigned int steps)
{
if (redoSteps() < 1) return;
if (steps < 1) return;
emit nodeCleanup(Node(firstChildElement(rootNodeName)));
while ((steps > 0) && (redoSteps() > 0))
{
QDomNode root = firstChildElement(rootNodeName);
QDomNode redoNode = _redoStack.pop();
_undoStack.push(root.cloneNode());
_undoHistory.push(_redoHistory.pop());
root = replaceChild(redoNode, root);
if (root.isNull()) // was replaceChild successful?
{
emit criticalError(tr("Redo function failed."));
break;
}
--steps;
++_modificationCounter;
emit modificationCount(_modificationCounter);
}
emitChangedSignal(Node(), Attribute::MaxAttributes, true);
} // void GeometryModelQDom::redo(unsigned int steps)
void GeometryModelQDom::enableUndo(bool enable)
{
_undoEnabled = enable;
} // void GeometryModelQDom::enableUndo(bool enable)
void GeometryModelQDom::startUndoBlock()
{
if (! _insideUndoBlock)
{
QDomElement root = firstChildElement(rootNodeName);
_undoBlock = root.cloneNode();
}
_insideUndoBlock = true;
} // void GeometryModelQDom::startUndoBlock()
void GeometryModelQDom::abortUndoBlock()
{
if (_insideUndoBlock)
_undoBlock.clear();
} // void GeometryModelQDom::abortUndoBlock()
void GeometryModelQDom::endUndoBlock(const QString &eventDescription)
{
if (_insideUndoBlock)
{
if (_undoEnabled && (! _undoBlock.isNull()))
{
while (undoSteps() >= _maxUndoSteps)
{
// Size-limit reached, remove first element
_undoStack.erase(_undoStack.begin());
_undoHistory.erase(_undoHistory.begin());
}
_undoStack.push(_undoBlock);
_undoHistory.push((eventDescription.isEmpty() ? _undoHistoryBlock : eventDescription));
clearRedoStack();
++_modificationCounter;
emit modificationCount(_modificationCounter);
}
}
_insideUndoBlock = false;
} // void GeometryModelQDom::endUndoBlock(const QString &eventDescription)
void GeometryModelQDom::setMaxUndoSteps(unsigned int max)
{
_maxUndoSteps = (max < 1) ? 1 : max;
while (undoSteps() > _maxUndoSteps)
{
// shrink to max size, if needed.
_undoStack.erase(_undoStack.begin());
_undoHistory.erase(_undoHistory.begin());
}
} // void GeometryModelQDom::setMaxUndoSteps(int max)
unsigned int GeometryModelQDom::maxUndoSteps() const
{
return _maxUndoSteps;
}
void GeometryModelQDom::cleanModel()
{
qDebug() << " GeometryModelQDom::cleanModel()";
QMap<QString, GeometryModelQDom::PrimitiveType>::iterator it = _primitiveTagsTypes.begin();
while (it != _primitiveTagsTypes.end())
{
QDomNodeList nodes = elementsByTagName(it.key());
for (int i = 0; i < nodes.size(); ++i)
{
if ((_primitiveTagsTypes[it.key()] == PrimitiveType::Node) || (_primitiveTagsTypes[it.key()] == PrimitiveType::RootNode))
{
// Remove empty groups
QDomNode group = nodes.at(i);
if ( ! (group.hasChildNodes() || group.hasAttributes()) )
{
group.parentNode().removeChild(group);
}
}
else
{
// Remove userData
const QDomNode &node = nodes.at(i);
if (hasUserData(node))
{
bool ok;
int userData = getUserData(node, &ok);
if (ok)
{
nodes.at(i).toElement().removeAttribute(userDataName);
emit userDataCleanup(userData);
}
}
}
GeometryModel::Node::Implementation nodeImpl(nodes.at(i));
emit connectionCleanup(nodeImpl.connected());
nodeImpl.unlinkConnection();
}
++it;
}
resetModificationCounter();
} // void GeometryModelQDom::cleanModel()
void GeometryModelQDom::setNodeDisplayName(const Node &node, const QString &name)
{
const QString attName = QLatin1String("GuiDisplayName");
QDomElement e = node.get().node().toElement();
if (e.isNull())
{
qCritical() << " node not found";
return;
}
e.setAttribute(attName, name);
emitChangedSignal(node, Attribute::MaxAttributes, false);
} // void GeometryModelQDom::setNodeDisplayName(const Node & node, const QString & name)
QString GeometryModelQDom::getNodeDisplayName(const Node &node) const
{
const QString attName = QLatin1String("GuiDisplayName");
QDomElement e = node.get().node().toElement();
return (e.hasAttribute(attName)) ? e.attribute(attName) : QString();
} // QString GeometryModelQDom::getNodeDisplayName(const Node & node) const
QVariant GeometryModelQDom::getAttribute(const Node &node, Attribute attribute) const { return getAttribute(node.get().node(), attribute); }
QVariant GeometryModelQDom::getAttribute(const QDomNode &node, Attribute attribute) const
{
QString att = attributeToString(attribute);
QDomElement e = node.toElement();
if (e.hasAttribute(att))
{
QString value = e.attribute(att);
if (_attributeTypes[attribute] == QVariant::Color)
{
// Return Colors as QString and let the user convert it with static method
// PlanModel::colorFromString() - QVariant ignores alpha in Colors
return QVariant(colorFromString(value));
}
else if (_attributeTypes[attribute] == QVariant::PointF)
return QVariant(pointFromString(value));
else
{
if (_attributeTypes[attribute] == QVariant::UserType)
{
// Return PlanModel-Enums as String-Value
// TODO: Implement UserTypes?
return QVariant(value);
}
else
{
// Convert other values to their native type
QVariant result(_attributeTypes[attribute]);
result.setValue(value);
return result;
}
}
}
else
{
// Check for default
if (hasAttribute(node, attribute))
{
using index = QPair<GeometryModelQDom::PrimitiveType, GeometryModelQDom::Attribute>;
QVariant result(_attributeTypes[attribute]);
result.setValue(_attributeDefaults[index(PrimitiveType::Unknown, attribute)]);
return result;
}
else
{
emit const_cast<GeometryModelQDom*>(this)->attributeError(att + tr(": Attribute unknown in primitive %1").arg(node.nodeName()));
return QVariant(QVariant::Invalid);
}
}
return QVariant(QVariant::Invalid);
} // QVariant GeometryModelQDom::getAttribute(QDomNode node, Attribute attribute)
bool GeometryModelQDom::hasAttribute(const Node &node, Attribute attribute) const { return hasAttribute(node.get().node(), attribute); }
bool GeometryModelQDom::hasAttribute(const QDomNode &node, Attribute attribute) const
{
QString tag = node.nodeName();
if (_primitiveTagsTypes.contains(tag))
{
PrimitiveType t = _primitiveTagsTypes[tag];
if (_primitiveSupportedAttributes.contains(t))
return supportedAttributes(t).contains(attribute);
}
return false;
} // bool GeometryModelQDom::hasAttribute(QDomNode node, Attribute attribute) const
QVariant::Type GeometryModelQDom::attributeType(const Attribute &attribute) const
{
if (_attributeTypes.contains(attribute)) return _attributeTypes[attribute];
else return QVariant::Invalid;
} // QVariant::Type GeometryModelQDom::attributeType(Attribute attribute) const
QList<GeometryModelQDom::Attribute> GeometryModelQDom::supportedAttributes(PrimitiveType type) const
{
if (_primitiveSupportedAttributes.contains(type)) return _primitiveSupportedAttributes.values(type);
else return QList<GeometryModelQDom::Attribute>();
} // QList<GeometryModelQDom::Attribute> GeometryModelQDom::supportedAttributes(PrimitiveType type) const
GeometryModel::Node GeometryModelQDom::createGroup(const NodeList &primitives)
{
pushUndo(QLatin1String("createGroup"));
QDomElement root = firstChildElement(rootNodeName);
QDomElement node = createElement(_primitiveTagsStrings[PrimitiveType::Node]);
QDomNode group = root.appendChild(node);
if (! group.isNull())
{
for (int i = 0; i < primitives.size(); ++i)
{
// For performance-reasons we use direct appendChild(), but
// normally you should use movePrimitiveIntoGroup(primitives.at(i), group);
group.appendChild(primitives.at(i).get().node());
}
}
emitChangedSignal(Node(), Attribute::MaxAttributes, false);
return Node(Node::Implementation(group));
} // QDomNode PlanModel::createGroup(QList<QDomNode> primitives)
QDomNode GeometryModelQDom::createGroup(const QList<QDomNode> &primitives)
{
pushUndo(QLatin1String("createGroup"));
QDomElement root = firstChildElement(rootNodeName);
QDomElement node = createElement(_primitiveTagsStrings[PrimitiveType::Node]);
QDomNode group = root.appendChild(node);
if (! group.isNull())
{
for (int i = 0; i < primitives.size(); ++i)
{
// For performance-reasons we use direct appendChild(), but
// normally you should use movePrimitiveIntoGroup(primitives.at(i), group);
group.appendChild(primitives.at(i));
}
}
emitChangedSignal(Node(), Attribute::MaxAttributes, false);
return group;
} // QDomNode PlanModel::createGroup(QList<QDomNode> primitives)
GeometryModel::Node GeometryModelQDom::isInGroup(const Node &node) const
{
QDomNode parent = node.get()->parentNode();
return Node(Node::Implementation((getType(parent) == PrimitiveType::Node) ? parent : QDomNode()));
} // QDomNode GeometryModelQDom::isInGroup(QDomNode primitive) const
GeometryModel::NodeList GeometryModelQDom::getGroupPrimitives(const Node &node)
{
PrimitiveType myNodeType = getType(node);
if ((myNodeType != PrimitiveType::Node) && (myNodeType != PrimitiveType::RootNode))
{
emit typeError(tr("Given node is not a group: %1").arg(node.get()->nodeName()));
return NodeList();
}
const QDomNodeList &domPrimitiveList = node.get()->childNodes();
GeometryModel::NodeList primitiveList;
primitiveList.reserve(domPrimitiveList.size());
for (int i = 0; i < domPrimitiveList.size(); ++i)
primitiveList += Node(Node::Implementation(domPrimitiveList.at(i)));
return primitiveList;
} // QDomNodeList GeometryModelQDom::getGroupPrimitives(QDomNode node) const
GeometryModel::Node GeometryModelQDom::findPrimitive(int userData) const
{
// TODO: This is inefficient!!! Search only for Att userData!
QString userDataString = QString::number(userData, 10);
QMap<QString, GeometryModelQDom::PrimitiveType>::iterator it = _primitiveTagsTypes.begin();
while (it != _primitiveTagsTypes.end())
{
QDomNodeList nodes = elementsByTagName(it.key());
for (int i = 0; i < nodes.size(); ++i)
{
QDomElement e = nodes.at(i).toElement();
if (e.hasAttribute(userDataName) && (e.attribute(userDataName) == userDataString))
return Node(Node::Implementation(nodes.at(i)));
}
++it;
}
return Node();
} // QDomNode GeometryModelQDom::findPrimitive(int userData) const
bool GeometryModelQDom::hasUserData(const Node &node) const { return hasUserData(node.get().node()); }
int GeometryModelQDom::getUserData(const Node &node, bool *ok) const { return getUserData(node.get().node(), ok); }
bool GeometryModelQDom::hasUserData(const QDomNode &node) const { return node.toElement().hasAttribute(userDataName); }
int GeometryModelQDom::getUserData(const QDomNode &node, bool *okPtr) const
{
if (okPtr) *okPtr = false; // if provided, initialize
int result = 0;
bool ok = false;
QDomElement e = node.toElement();
if (e.hasAttribute(userDataName))
{
QString value = e.attribute(userDataName);
result = value.toInt(&ok, 10);
if (!(ok))
emit const_cast<GeometryModelQDom*>(this)->modelError(tr("Can not convert value to int: %1").arg(value));
}
else
{
PrimitiveType type = getType(node);
if ((type != PrimitiveType::Node) && (type != PrimitiveType::RootNode) && (type != PrimitiveType::Unknown))
{
qWarning() << "Missing user data at node " << node.nodeName() << " connectedId=" << Node::Implementation(node).connectedId()
<< " [maybe m_internal->m_modelClipboard->clearModel()]";
// #ifdef LTS_DEBUG
// // *** To locate a bug stop program here and start debugger, should be removed for final release
// assert(false);
// // ***
// #endif
emit const_cast<GeometryModelQDom*>(this)->typeError(tr("No UserData in %1").arg(node.nodeName()));
}
return SituationMap::IdHandler::BadId;
}
if (okPtr) *okPtr = ok;
return result;
} // void* GeometryModelQDom::getUserData(QDomNode node, bool *ok)
void GeometryModelQDom::setUserData(const Node &node, int userData)
{
PrimitiveType type = getType(node);
if ((type == PrimitiveType::Node) || (type == PrimitiveType::RootNode) || (type == PrimitiveType::Unknown))
emit typeError(tr("Can not set UserData in %1").arg(node.get()->nodeName()));
else
{
if (!SituationMap::IdHandler::isIdValid(userData))
{
QDomElement e = node.get()->toElement();
e.removeAttribute(userDataName);
}
else
{
QString userDataString = QString::number(userData, 10);
QDomElement e = node.get()->toElement();
e.setAttribute(userDataName, userDataString);
}
emitChangedSignal(node, Attribute::MaxAttributes, false);
}
} // void GeometryModelQDom::setUserData(QDomNode node, int userData)
QMultiMap<int, GeometryModel::Node> GeometryModelQDom::userDataMap(const Node &node)
{
QMultiMap<int, QDomNode> domResult = userDataMap(node.get().node());
QMultiMap<int, GeometryModel::Node> result;
QMultiMap<int, QDomNode>::const_iterator iter = domResult.constBegin();
for (; iter != domResult.constEnd(); ++iter)
result.insert(iter.key(), Node(Node::Implementation(iter.value())));
return result;
} // QMultiMap<int, GeometryModel::Node> GeometryModelQDom::userDataMap(const Node & node)
QMultiMap<int, QDomNode> GeometryModelQDom::userDataMap(const QDomNode &node) const
{
QMultiMap<int, QDomNode> result;
if ((node.ownerDocument() != *this) && (! node.isNull()))
{
// Not a Node of this Document, ignore
return result;
}
QDomNodeList children;
if ((node == *this) || node.isNull())
children = firstChildElement(rootNodeName).childNodes();
else if ((getType(node) == PrimitiveType::Node) || (getType(node) == PrimitiveType::RootNode))
children = node.childNodes();
for (int i = 0; i < children.size(); ++i)
{
QDomNode curNode = children.at(i);
if (getType(curNode) == PrimitiveType::Node)
{
// If its a node, search deep and merge results...
QMultiMap<int, QDomNode> deepResult = userDataMap(curNode);
QMap<int, QDomNode>::const_iterator it = deepResult.constBegin();
while (it != deepResult.constEnd())
{
int key = it.key();
QList<QDomNode> values = deepResult.values(key);
for (int k = 0; k < values.size(); ++k)
result.insert(key, values.at(k));
++it;
}
}
else
{
// ...get UserData and append to result
bool ok;
int userData = getUserData(curNode, &ok);
if (ok)
result.insert(userData, curNode);
}
}
return result;
} // QMultiMap<int, QDomNode> GeometryModelQDom::userDataMap(QDomNode node)
static void resetUserData(const QDomNode &node)
{
const QDomNodeList &childNodes = node.childNodes();
for (int i = 0; i < childNodes.size(); ++i)
resetUserData(childNodes.at(i));
node.toElement().removeAttribute(userDataName);
node.toElement().removeAttribute(connectionIdName);
} // resetUserData (QDomNode & node)
GeometryModel::Node GeometryModelQDom::copy(const Node &node, int)
{
QDomElement root = firstChildElement(rootNodeName);
pushUndo(QLatin1String("copy"));
QDomNode clone = node.get()->cloneNode(true);
resetUserData(clone);
QDomNode result = root.appendChild(clone);
emitChangedSignal(Node(), Attribute::MaxAttributes, false);
return Node(Node::Implementation(result));
} // GeometryModel::Node GeometryModelQDom::copy(Node node, int userData)
GeometryModelQDom::PrimitiveType GeometryModelQDom::getType(const Node &node) const { return getType(node.get().node()); }
GeometryModelQDom::PrimitiveType GeometryModelQDom::getType(const QDomNode &node) const
{
QString tag = node.nodeName();
if (_primitiveTagsTypes.contains(tag)) return _primitiveTagsTypes[tag];
else return PrimitiveType::Unknown;
} // PrimitiveType GeometryModelQDom::getType(QDomNode node) const
unsigned int GeometryModelQDom::redoSteps() const { return _redoStack.size(); }
unsigned int GeometryModelQDom::undoSteps() const { return _undoStack.size(); }
QString GeometryModelQDom::attributeToString(const Attribute &attribute) const
{
switch (attribute)
{
case Attribute::AbcProtection: return QLatin1String("abc_protection");
case Attribute::Affiliation: return QLatin1String("affil");
case Attribute::Alignment: return QLatin1String("alignment");
case Attribute::AnchorHorizontal: return QLatin1String("anchor_horizontal");
case Attribute::AnchorVertical: return QLatin1String("anchor_vertical");
case Attribute::ArrowClampHeight: return QLatin1String("arrow_clamp_height");
case Attribute::ArrowHeight: return QLatin1String("arrow_height");
case Attribute::ArrowLineWidth: return QLatin1String("arrow_line_width");
case Attribute::Arrows: return QLatin1String("arrows");
case Attribute::ArrowWidth: return QLatin1String("arrow_width");
case Attribute::Box: return QLatin1String("box");
case Attribute::Center: return QLatin1String("center_point");
case Attribute::Close: return QLatin1String("close");
case Attribute::Color: return QLatin1String("color");
case Attribute::Extent: return QLatin1String("extent");
case Attribute::Fill: return QLatin1String("fill");
case Attribute::FillColor: return QLatin1String("FillColor");
case Attribute::FillPattern: return QLatin1String("FillPattern");
case Attribute::FillStyle: return QLatin1String("FillStyle");
case Attribute::Font: return QLatin1String("font");
case Attribute::FontBold: return QLatin1String("FontBold");
case Attribute::FontItalic: return QLatin1String("FontItalic");
case Attribute::FontSize: return QLatin1String("FontSize");
case Attribute::Height: return QLatin1String("height");
case Attribute::LineColor: return QLatin1String("linecolor");
case Attribute::LineStyle: return QLatin1String("linestyle");
case Attribute::LineWidth: return QLatin1String("linewidth");
case Attribute::MarginHorizontal: return QLatin1String("margin_horizontal");
case Attribute::MarginVertical: return QLatin1String("margin_vertical");
case Attribute::Mobility: return QLatin1String("mobility");
case Attribute::SIDC: return QLatin1String("sidc");
case Attribute::SIDC_Color: return QLatin1String("sidc_color");
case Attribute::SIDC_Attributes: return QLatin1String("sidc_attributes");
case Attribute::SymbolId: return QLatin1String("symbol_id");
case Attribute::SymbolOffsetX: return QLatin1String("symbol_offsetX");
case Attribute::SymbolOffsetY: return QLatin1String("symbol_offsetY");
case Attribute::SymbolDirection: return QLatin1String("symbol_direction");
case Attribute::ForceId: return QLatin1String("force_id");
case Attribute::SymbolState: return QLatin1String("symbolState");
case Attribute::SymbolUncertainty: return QLatin1String("symbolUncertainty");
case Attribute::SymbolExplicitScale: return QLatin1String("explicitScale");
case Attribute::DamageForceId: return QLatin1String("damage_force_id");
case Attribute::Injury: return QLatin1String("injury");
case Attribute::PeMapBrightness: return QLatin1String("pe_map_brightness");
case Attribute::PeMapCenterX: return QLatin1String("pe_map_centerx");
case Attribute::PeMapCenterY: return QLatin1String("pe_map_centery");
case Attribute::PeMapSaturation: return QLatin1String("pe_map_saturation");
case Attribute::PeMapZoom: return QLatin1String("pe_map_zoom");
case Attribute::PeMapRotation: return QLatin1String("pe_map_rotation");
case Attribute::PeMapType: return QLatin1String("pe_map_type");
case Attribute::PeShowUtm: return QLatin1String("pe_show_utm");
case Attribute::PeSymbolOpacity: return QLatin1String("symbol_opacity");
case Attribute::PeSymbolFillType: return QLatin1String("pe_symbol_fill_type");
case Attribute::PeSymbolScale: return QLatin1String("pe_symbol_scale");
case Attribute::MetaDataTitle: return QLatin1String("meta_data_title");
case Attribute::MetaDataAuthor: return QLatin1String("meta_data_author");
case Attribute::MetaDataDate: return QLatin1String("meta_data_date");
case Attribute::MetaDataDesciption: return QLatin1String("meta_data_description");
case Attribute::MetaDataMinScale: return QLatin1String("meta_data_min_scale");
case Attribute::MetaDataMaxScale: return QLatin1String("meta_data_max_scale");
case Attribute::MetaPixelBasedTextBoxes: return QLatin1String("meta_pixel_based_text_boxes");
case Attribute::Rotate: return QLatin1String("rotate");
case Attribute::Rounding: return QLatin1String("rounding");
case Attribute::Start: return QLatin1String("start");
case Attribute::Text_EF: return QLatin1String("text_ef");
case Attribute::Text_G: return QLatin1String("text_g");
case Attribute::Text_H: return QLatin1String("text_h");
case Attribute::Text_KLNPJ: return QLatin1String("text_jklnp");
case Attribute::Text_M: return QLatin1String("text_m");
case Attribute::Text_T: return QLatin1String("text_t");
case Attribute::Text_V: return QLatin1String("text_v");
case Attribute::Text_W: return QLatin1String("text_w");
case Attribute::Text_XY: return QLatin1String("text_xy");
case Attribute::Text_Z: return QLatin1String("text_z");
case Attribute::UtmEast: return QLatin1String("utm_east");
case Attribute::UtmGrid: return QLatin1String("utm_grid");
case Attribute::UtmNorth: return QLatin1String("utm_north");
case Attribute::UtmZone: return QLatin1String("utm_zone");
case Attribute::Width: return QLatin1String("width");
case Attribute::att_vbg_et: return QLatin1String("w_vbg_et");
default: return QLatin1String("Unknown Attribute");
}
} // QString GeometryModelQDom::attributeToString(Attribute attribute) const
void GeometryModelQDom::init()
{
using index = QPair<GeometryModelQDom::PrimitiveType, GeometryModelQDom::Attribute>;
// Only once
if (! _staticInitDone)
{
// Create mapping between primitive-types and their string/tag-name
_primitiveTagsTypes[QLatin1String("participantSymbol")] = PrimitiveType::ParticipantSymbol;
_primitiveTagsTypes[QLatin1String("dictionarySymbol")] = PrimitiveType::DictionarySymbol;
_primitiveTagsTypes[QLatin1String("ellipse")] = PrimitiveType::Ellipse;
_primitiveTagsTypes[QLatin1String("line")] = PrimitiveType::Line;
_primitiveTagsTypes[QLatin1String("polyline")] = PrimitiveType::Polyline;
_primitiveTagsTypes[QLatin1String("rectangle")] = PrimitiveType::Rectangle;
_primitiveTagsTypes[QLatin1String("spline")] = PrimitiveType::Spline;
_primitiveTagsTypes[QLatin1String("symbol")] = PrimitiveType::Symbol;
_primitiveTagsTypes[QLatin1String("text")] = PrimitiveType::Text;
_primitiveTagsTypes[QLatin1String("node")] = PrimitiveType::Node;
_primitiveTagsTypes[rootNodeName] = PrimitiveType::RootNode;
_primitiveTagsStrings[PrimitiveType::ParticipantSymbol] = QLatin1String("participantSymbol");
_primitiveTagsStrings[PrimitiveType::DictionarySymbol] = QLatin1String("dictionarySymbol");
_primitiveTagsStrings[PrimitiveType::Ellipse] = QLatin1String("ellipse");
_primitiveTagsStrings[PrimitiveType::Line] = QLatin1String("line");
_primitiveTagsStrings[PrimitiveType::Polyline] = QLatin1String("polyline");
_primitiveTagsStrings[PrimitiveType::Rectangle] = QLatin1String("rectangle");
_primitiveTagsStrings[PrimitiveType::Spline] = QLatin1String("spline");
_primitiveTagsStrings[PrimitiveType::Symbol] = QLatin1String("symbol");
_primitiveTagsStrings[PrimitiveType::Text] = QLatin1String("text");
_primitiveTagsStrings[PrimitiveType::Node] = QLatin1String("node");
// Don't set
// _primitiveTagsStrings[PrimitiveType::RootNode] = rootNodeName;
// because the root node can not be created from interface.
// Create mapping between node-types and supported attributes
// "Unknown" is used for plan-attributes
_primitiveSupportedAttributes.insert(PrimitiveType::RootNode, Attribute::MetaDataTitle);
_primitiveSupportedAttributes.insert(PrimitiveType::RootNode, Attribute::MetaDataAuthor);
_primitiveSupportedAttributes.insert(PrimitiveType::RootNode, Attribute::MetaDataDate);
_primitiveSupportedAttributes.insert(PrimitiveType::RootNode, Attribute::MetaDataDesciption);
_primitiveSupportedAttributes.insert(PrimitiveType::RootNode, Attribute::MetaDataMinScale);
_primitiveSupportedAttributes.insert(PrimitiveType::RootNode, Attribute::MetaDataMaxScale);
_primitiveSupportedAttributes.insert(PrimitiveType::RootNode, Attribute::MetaPixelBasedTextBoxes);
_primitiveSupportedAttributes.insert(PrimitiveType::MapDefaults, Attribute::PeMapBrightness);
_primitiveSupportedAttributes.insert(PrimitiveType::MapDefaults, Attribute::PeMapCenterX);
_primitiveSupportedAttributes.insert(PrimitiveType::MapDefaults, Attribute::PeMapCenterY);
_primitiveSupportedAttributes.insert(PrimitiveType::MapDefaults, Attribute::PeMapSaturation);
_primitiveSupportedAttributes.insert(PrimitiveType::MapDefaults, Attribute::PeMapZoom);
_primitiveSupportedAttributes.insert(PrimitiveType::MapDefaults, Attribute::PeMapRotation);
_primitiveSupportedAttributes.insert(PrimitiveType::MapDefaults, Attribute::PeMapType);
_primitiveSupportedAttributes.insert(PrimitiveType::MapDefaults, Attribute::PeShowUtm);
_primitiveSupportedAttributes.insert(PrimitiveType::MapDefaults, Attribute::PeSymbolOpacity);
_primitiveSupportedAttributes.insert(PrimitiveType::MapDefaults, Attribute::PeSymbolFillType);
_primitiveSupportedAttributes.insert(PrimitiveType::MapDefaults, Attribute::PeSymbolScale);
_primitiveSupportedAttributes.insert(PrimitiveType::MapDefaults, Attribute::UtmEast);
_primitiveSupportedAttributes.insert(PrimitiveType::MapDefaults, Attribute::UtmGrid);
_primitiveSupportedAttributes.insert(PrimitiveType::MapDefaults, Attribute::UtmNorth);
_primitiveSupportedAttributes.insert(PrimitiveType::MapDefaults, Attribute::UtmZone);
_primitiveSupportedAttributes.insert(PrimitiveType::DictionarySymbol, Attribute::SIDC);
_primitiveSupportedAttributes.insert(PrimitiveType::DictionarySymbol, Attribute::SIDC_Attributes);
_primitiveSupportedAttributes.insert(PrimitiveType::ParticipantSymbol, Attribute::SIDC);
_primitiveSupportedAttributes.insert(PrimitiveType::ParticipantSymbol, Attribute::SIDC_Attributes);
_primitiveSupportedAttributes.insert(PrimitiveType::ParticipantSymbol, Attribute::ForceId);
_primitiveSupportedAttributes.insert(PrimitiveType::ParticipantSymbol, Attribute::SymbolState);
_primitiveSupportedAttributes.insert(PrimitiveType::ParticipantSymbol, Attribute::DamageForceId);
_primitiveSupportedAttributes.insert(PrimitiveType::ParticipantSymbol, Attribute::Injury);
_primitiveSupportedAttributes.insert(PrimitiveType::ParticipantSymbol, Attribute::Text_EF);
_primitiveSupportedAttributes.insert(PrimitiveType::ParticipantSymbol, Attribute::Text_G);
_primitiveSupportedAttributes.insert(PrimitiveType::ParticipantSymbol, Attribute::Text_H);
_primitiveSupportedAttributes.insert(PrimitiveType::ParticipantSymbol, Attribute::Text_KLNPJ);
_primitiveSupportedAttributes.insert(PrimitiveType::ParticipantSymbol, Attribute::Text_M);
_primitiveSupportedAttributes.insert(PrimitiveType::ParticipantSymbol, Attribute::Text_T);
_primitiveSupportedAttributes.insert(PrimitiveType::ParticipantSymbol, Attribute::Text_V);
_primitiveSupportedAttributes.insert(PrimitiveType::ParticipantSymbol, Attribute::Text_W);
_primitiveSupportedAttributes.insert(PrimitiveType::ParticipantSymbol, Attribute::Text_XY);
_primitiveSupportedAttributes.insert(PrimitiveType::ParticipantSymbol, Attribute::Text_Z);
_primitiveSupportedAttributes.insert(PrimitiveType::Ellipse, Attribute::Center);
_primitiveSupportedAttributes.insert(PrimitiveType::Ellipse, Attribute::Color);
_primitiveSupportedAttributes.insert(PrimitiveType::Ellipse, Attribute::Height);
_primitiveSupportedAttributes.insert(PrimitiveType::Ellipse, Attribute::Width);
_primitiveSupportedAttributes.insert(PrimitiveType::Ellipse, Attribute::Extent);
_primitiveSupportedAttributes.insert(PrimitiveType::Ellipse, Attribute::Fill);
_primitiveSupportedAttributes.insert(PrimitiveType::Ellipse, Attribute::FillColor);
_primitiveSupportedAttributes.insert(PrimitiveType::Ellipse, Attribute::FillPattern);
_primitiveSupportedAttributes.insert(PrimitiveType::Ellipse, Attribute::FillStyle);
_primitiveSupportedAttributes.insert(PrimitiveType::Ellipse, Attribute::LineStyle);
_primitiveSupportedAttributes.insert(PrimitiveType::Ellipse, Attribute::LineWidth);
_primitiveSupportedAttributes.insert(PrimitiveType::Ellipse, Attribute::Rotate);
_primitiveSupportedAttributes.insert(PrimitiveType::Ellipse, Attribute::Start);
_primitiveSupportedAttributes.insert(PrimitiveType::Line, Attribute::ArrowClampHeight);
_primitiveSupportedAttributes.insert(PrimitiveType::Line, Attribute::ArrowHeight);
_primitiveSupportedAttributes.insert(PrimitiveType::Line, Attribute::ArrowLineWidth);
_primitiveSupportedAttributes.insert(PrimitiveType::Line, Attribute::Arrows);
_primitiveSupportedAttributes.insert(PrimitiveType::Line, Attribute::ArrowWidth);
_primitiveSupportedAttributes.insert(PrimitiveType::Line, Attribute::Color);
_primitiveSupportedAttributes.insert(PrimitiveType::Line, Attribute::LineStyle);
_primitiveSupportedAttributes.insert(PrimitiveType::Line, Attribute::LineWidth);
_primitiveSupportedAttributes.insert(PrimitiveType::Polyline, Attribute::ArrowClampHeight);
_primitiveSupportedAttributes.insert(PrimitiveType::Polyline, Attribute::ArrowHeight);
_primitiveSupportedAttributes.insert(PrimitiveType::Polyline, Attribute::ArrowLineWidth);
_primitiveSupportedAttributes.insert(PrimitiveType::Polyline, Attribute::Arrows);
_primitiveSupportedAttributes.insert(PrimitiveType::Polyline, Attribute::ArrowWidth);
_primitiveSupportedAttributes.insert(PrimitiveType::Polyline, Attribute::Close);
_primitiveSupportedAttributes.insert(PrimitiveType::Polyline, Attribute::Color);
_primitiveSupportedAttributes.insert(PrimitiveType::Polyline, Attribute::Fill);
_primitiveSupportedAttributes.insert(PrimitiveType::Polyline, Attribute::FillColor);
_primitiveSupportedAttributes.insert(PrimitiveType::Polyline, Attribute::FillPattern);
_primitiveSupportedAttributes.insert(PrimitiveType::Polyline, Attribute::LineStyle);
_primitiveSupportedAttributes.insert(PrimitiveType::Polyline, Attribute::LineWidth);
_primitiveSupportedAttributes.insert(PrimitiveType::Rectangle, Attribute::Center);
_primitiveSupportedAttributes.insert(PrimitiveType::Rectangle, Attribute::Color);
_primitiveSupportedAttributes.insert(PrimitiveType::Rectangle, Attribute::Height);
_primitiveSupportedAttributes.insert(PrimitiveType::Rectangle, Attribute::Width);
_primitiveSupportedAttributes.insert(PrimitiveType::Rectangle, Attribute::Fill);
_primitiveSupportedAttributes.insert(PrimitiveType::Rectangle, Attribute::FillColor);
_primitiveSupportedAttributes.insert(PrimitiveType::Rectangle, Attribute::FillPattern);
_primitiveSupportedAttributes.insert(PrimitiveType::Rectangle, Attribute::LineStyle);
_primitiveSupportedAttributes.insert(PrimitiveType::Rectangle, Attribute::LineWidth);
_primitiveSupportedAttributes.insert(PrimitiveType::Rectangle, Attribute::Rotate);
_primitiveSupportedAttributes.insert(PrimitiveType::Rectangle, Attribute::Rounding);
_primitiveSupportedAttributes.insert(PrimitiveType::Spline, Attribute::ArrowClampHeight);
_primitiveSupportedAttributes.insert(PrimitiveType::Spline, Attribute::ArrowHeight);
_primitiveSupportedAttributes.insert(PrimitiveType::Spline, Attribute::ArrowLineWidth);
_primitiveSupportedAttributes.insert(PrimitiveType::Spline, Attribute::Arrows);
_primitiveSupportedAttributes.insert(PrimitiveType::Spline, Attribute::ArrowWidth);
_primitiveSupportedAttributes.insert(PrimitiveType::Spline, Attribute::Close);
_primitiveSupportedAttributes.insert(PrimitiveType::Spline, Attribute::Color);
_primitiveSupportedAttributes.insert(PrimitiveType::Spline, Attribute::Fill);
_primitiveSupportedAttributes.insert(PrimitiveType::Spline, Attribute::FillColor);
_primitiveSupportedAttributes.insert(PrimitiveType::Spline, Attribute::FillPattern);
_primitiveSupportedAttributes.insert(PrimitiveType::Spline, Attribute::LineStyle);
_primitiveSupportedAttributes.insert(PrimitiveType::Spline, Attribute::LineWidth);
_primitiveSupportedAttributes.insert(PrimitiveType::Symbol, Attribute::AbcProtection);
_primitiveSupportedAttributes.insert(PrimitiveType::Symbol, Attribute::Affiliation);
_primitiveSupportedAttributes.insert(PrimitiveType::Symbol, Attribute::Mobility);
_primitiveSupportedAttributes.insert(PrimitiveType::Symbol, Attribute::SymbolId);
_primitiveSupportedAttributes.insert(PrimitiveType::Symbol, Attribute::SymbolOffsetX);
_primitiveSupportedAttributes.insert(PrimitiveType::Symbol, Attribute::SymbolOffsetY);
_primitiveSupportedAttributes.insert(PrimitiveType::Symbol, Attribute::SymbolDirection);
_primitiveSupportedAttributes.insert(PrimitiveType::Symbol, Attribute::ForceId);
_primitiveSupportedAttributes.insert(PrimitiveType::Symbol, Attribute::SymbolState);
_primitiveSupportedAttributes.insert(PrimitiveType::Symbol, Attribute::SymbolUncertainty);
_primitiveSupportedAttributes.insert(PrimitiveType::Symbol, Attribute::SymbolExplicitScale);
_primitiveSupportedAttributes.insert(PrimitiveType::Symbol, Attribute::DamageForceId);
_primitiveSupportedAttributes.insert(PrimitiveType::Symbol, Attribute::Text_EF);
_primitiveSupportedAttributes.insert(PrimitiveType::Symbol, Attribute::Text_G);
_primitiveSupportedAttributes.insert(PrimitiveType::Symbol, Attribute::Text_H);
_primitiveSupportedAttributes.insert(PrimitiveType::Symbol, Attribute::Text_KLNPJ);
_primitiveSupportedAttributes.insert(PrimitiveType::Symbol, Attribute::Text_M);
_primitiveSupportedAttributes.insert(PrimitiveType::Symbol, Attribute::Text_T);
_primitiveSupportedAttributes.insert(PrimitiveType::Symbol, Attribute::Text_V);
_primitiveSupportedAttributes.insert(PrimitiveType::Symbol, Attribute::Text_W);
_primitiveSupportedAttributes.insert(PrimitiveType::Symbol, Attribute::Text_XY);
_primitiveSupportedAttributes.insert(PrimitiveType::Symbol, Attribute::Text_Z);
_primitiveSupportedAttributes.insert(PrimitiveType::Symbol, Attribute::att_vbg_et);
_primitiveSupportedAttributes.insert(PrimitiveType::Text, Attribute::AnchorHorizontal);
_primitiveSupportedAttributes.insert(PrimitiveType::Text, Attribute::AnchorVertical);
_primitiveSupportedAttributes.insert(PrimitiveType::Text, Attribute::Box);
_primitiveSupportedAttributes.insert(PrimitiveType::Text, Attribute::Color);
_primitiveSupportedAttributes.insert(PrimitiveType::Text, Attribute::Fill);
_primitiveSupportedAttributes.insert(PrimitiveType::Text, Attribute::FillColor);
_primitiveSupportedAttributes.insert(PrimitiveType::Text, Attribute::FillPattern);
_primitiveSupportedAttributes.insert(PrimitiveType::Text, Attribute::Font);
_primitiveSupportedAttributes.insert(PrimitiveType::Text, Attribute::FontBold);
_primitiveSupportedAttributes.insert(PrimitiveType::Text, Attribute::FontItalic);
_primitiveSupportedAttributes.insert(PrimitiveType::Text, Attribute::FontSize);
_primitiveSupportedAttributes.insert(PrimitiveType::Text, Attribute::LineColor);
_primitiveSupportedAttributes.insert(PrimitiveType::Text, Attribute::LineStyle);
_primitiveSupportedAttributes.insert(PrimitiveType::Text, Attribute::LineWidth);
_primitiveSupportedAttributes.insert(PrimitiveType::Text, Attribute::MarginHorizontal);
_primitiveSupportedAttributes.insert(PrimitiveType::Text, Attribute::MarginVertical);
_primitiveSupportedAttributes.insert(PrimitiveType::Text, Attribute::Rotate);
// Init all default-values for all required attributes
QFont defaultFont;
int fontSize = defaultFont.pixelSize();
// TODO: Find better defaults
// "Unknown" is used for plan-attributes
_attributeDefaults.insert(index(PrimitiveType::DictionarySymbol, Attribute::SIDC), QLatin1String("------------"));
_attributeDefaults.insert(index(PrimitiveType::ParticipantSymbol, Attribute::SIDC), QLatin1String("------------"));
_attributeDefaults.insert(index(PrimitiveType::ParticipantSymbol, Attribute::SIDC_Color), variant2XmlString(QColor(0, 0, 0, 0)));
_attributeDefaults.insert(index(PrimitiveType::RootNode, Attribute::MetaDataTitle), QString());
_attributeDefaults.insert(index(PrimitiveType::RootNode, Attribute::MetaDataAuthor), QString());
_attributeDefaults.insert(index(PrimitiveType::RootNode, Attribute::MetaDataDate), QString());
_attributeDefaults.insert(index(PrimitiveType::RootNode, Attribute::MetaDataDesciption), QString());
_attributeDefaults.insert(index(PrimitiveType::RootNode, Attribute::MetaDataMinScale), QString());
_attributeDefaults.insert(index(PrimitiveType::RootNode, Attribute::MetaDataMaxScale), QString());
_attributeDefaults.insert(index(PrimitiveType::Ellipse, Attribute::Center), QString());
_attributeDefaults.insert(index(PrimitiveType::Ellipse, Attribute::Color), QColor().name());
_attributeDefaults.insert(index(PrimitiveType::Ellipse, Attribute::Height), QLatin1String("0.0"));
_attributeDefaults.insert(index(PrimitiveType::Ellipse, Attribute::Width), QLatin1String("0.0"));
_attributeDefaults.insert(index(PrimitiveType::Ellipse, Attribute::Extent), QLatin1String("360"));
_attributeDefaults.insert(index(PrimitiveType::Ellipse, Attribute::Fill), QLatin1String("0"));
_attributeDefaults.insert(index(PrimitiveType::Ellipse, Attribute::FillColor), QColor().name());
_attributeDefaults.insert(index(PrimitiveType::Ellipse, Attribute::FillPattern), QLatin1String("none"));
_attributeDefaults.insert(index(PrimitiveType::Ellipse, Attribute::FillStyle), QLatin1String("pieslice"));
_attributeDefaults.insert(index(PrimitiveType::Ellipse, Attribute::LineStyle), QLatin1String("solid"));
_attributeDefaults.insert(index(PrimitiveType::Ellipse, Attribute::LineWidth), QLatin1String("0.1"));
_attributeDefaults.insert(index(PrimitiveType::Ellipse, Attribute::Rotate), QLatin1String("0"));
_attributeDefaults.insert(index(PrimitiveType::Ellipse, Attribute::Start), QLatin1String("0"));
_attributeDefaults.insert(index(PrimitiveType::Line, Attribute::ArrowClampHeight), QLatin1String("1.0"));
_attributeDefaults.insert(index(PrimitiveType::Line, Attribute::ArrowHeight), QLatin1String("1.0"));
_attributeDefaults.insert(index(PrimitiveType::Line, Attribute::ArrowLineWidth), QLatin1String("1.0"));
_attributeDefaults.insert(index(PrimitiveType::Line, Attribute::Arrows), QLatin1String("0"));
_attributeDefaults.insert(index(PrimitiveType::Line, Attribute::ArrowWidth), QLatin1String("1.0"));
_attributeDefaults.insert(index(PrimitiveType::Line, Attribute::Color), QColor().name());
_attributeDefaults.insert(index(PrimitiveType::Line, Attribute::LineStyle), QLatin1String("solid"));
_attributeDefaults.insert(index(PrimitiveType::Line, Attribute::LineWidth), QLatin1String("0.1"));
_attributeDefaults.insert(index(PrimitiveType::Polyline, Attribute::ArrowClampHeight), QLatin1String("1.0"));
_attributeDefaults.insert(index(PrimitiveType::Polyline, Attribute::ArrowHeight), QLatin1String("1.0"));
_attributeDefaults.insert(index(PrimitiveType::Polyline, Attribute::ArrowLineWidth), QLatin1String("1.0"));
_attributeDefaults.insert(index(PrimitiveType::Polyline, Attribute::Arrows), QLatin1String("0"));
_attributeDefaults.insert(index(PrimitiveType::Polyline, Attribute::ArrowWidth), QLatin1String("1.0"));
_attributeDefaults.insert(index(PrimitiveType::Polyline, Attribute::Close), QLatin1String("1"));
_attributeDefaults.insert(index(PrimitiveType::Polyline, Attribute::Color), QColor().name());
_attributeDefaults.insert(index(PrimitiveType::Polyline, Attribute::Fill), QLatin1String("0"));
_attributeDefaults.insert(index(PrimitiveType::Polyline, Attribute::FillColor), QColor().name());
_attributeDefaults.insert(index(PrimitiveType::Polyline, Attribute::FillPattern), QLatin1String("none"));
_attributeDefaults.insert(index(PrimitiveType::Polyline, Attribute::LineStyle), QLatin1String("solid"));
_attributeDefaults.insert(index(PrimitiveType::Polyline, Attribute::LineWidth), QLatin1String("0.1"));
_attributeDefaults.insert(index(PrimitiveType::Rectangle, Attribute::Center), QString());
_attributeDefaults.insert(index(PrimitiveType::Rectangle, Attribute::Color), QColor().name());
_attributeDefaults.insert(index(PrimitiveType::Rectangle, Attribute::Height), QLatin1String("0.0"));
_attributeDefaults.insert(index(PrimitiveType::Rectangle, Attribute::Width), QLatin1String("0.0"));
_attributeDefaults.insert(index(PrimitiveType::Rectangle, Attribute::Fill), QLatin1String("0"));
_attributeDefaults.insert(index(PrimitiveType::Rectangle, Attribute::FillColor), QColor().name());
_attributeDefaults.insert(index(PrimitiveType::Rectangle, Attribute::FillPattern), QLatin1String("none"));
_attributeDefaults.insert(index(PrimitiveType::Rectangle, Attribute::LineStyle), QLatin1String("solid"));
_attributeDefaults.insert(index(PrimitiveType::Rectangle, Attribute::LineWidth), QLatin1String("0.1"));
_attributeDefaults.insert(index(PrimitiveType::Rectangle, Attribute::Rotate), QLatin1String("0"));
_attributeDefaults.insert(index(PrimitiveType::Rectangle, Attribute::Rounding), QLatin1String("0.0"));
_attributeDefaults.insert(index(PrimitiveType::Spline, Attribute::ArrowClampHeight), QLatin1String("1.0"));
_attributeDefaults.insert(index(PrimitiveType::Spline, Attribute::ArrowHeight), QLatin1String("1.0"));
_attributeDefaults.insert(index(PrimitiveType::Spline, Attribute::ArrowLineWidth), QLatin1String("1.0"));
_attributeDefaults.insert(index(PrimitiveType::Spline, Attribute::Arrows), QLatin1String("0"));
_attributeDefaults.insert(index(PrimitiveType::Spline, Attribute::ArrowWidth), QLatin1String("1.0"));
_attributeDefaults.insert(index(PrimitiveType::Spline, Attribute::Close), QLatin1String("1"));
_attributeDefaults.insert(index(PrimitiveType::Spline, Attribute::Color), QColor().name());
_attributeDefaults.insert(index(PrimitiveType::Spline, Attribute::Fill), QLatin1String("0"));
_attributeDefaults.insert(index(PrimitiveType::Spline, Attribute::FillColor), QColor().name());
_attributeDefaults.insert(index(PrimitiveType::Spline, Attribute::FillPattern), QLatin1String("none"));
_attributeDefaults.insert(index(PrimitiveType::Spline, Attribute::LineStyle), QLatin1String("solid"));
_attributeDefaults.insert(index(PrimitiveType::Spline, Attribute::LineWidth), QLatin1String("0.1"));
_attributeDefaults.insert(index(PrimitiveType::Symbol, Attribute::AbcProtection), QString());
_attributeDefaults.insert(index(PrimitiveType::Symbol, Attribute::Affiliation), QString());
_attributeDefaults.insert(index(PrimitiveType::Symbol, Attribute::Mobility), QString());
_attributeDefaults.insert(index(PrimitiveType::Symbol, Attribute::SymbolId), QString());
_attributeDefaults.insert(index(PrimitiveType::Symbol, Attribute::SymbolOffsetX), QString());
_attributeDefaults.insert(index(PrimitiveType::Symbol, Attribute::SymbolOffsetY), QString());
_attributeDefaults.insert(index(PrimitiveType::Symbol, Attribute::SymbolDirection), QString());
_attributeDefaults.insert(index(PrimitiveType::Symbol, Attribute::ForceId), QString());
_attributeDefaults.insert(index(PrimitiveType::Symbol, Attribute::SymbolState), QString());
_attributeDefaults.insert(index(PrimitiveType::Symbol, Attribute::SymbolUncertainty), QString());
_attributeDefaults.insert(index(PrimitiveType::Symbol, Attribute::SymbolExplicitScale), QLatin1String("1.0"));
_attributeDefaults.insert(index(PrimitiveType::Symbol, Attribute::DamageForceId), QString());
_attributeDefaults.insert(index(PrimitiveType::Symbol, Attribute::Text_EF), QString());
_attributeDefaults.insert(index(PrimitiveType::Symbol, Attribute::Text_G), QString());
_attributeDefaults.insert(index(PrimitiveType::Symbol, Attribute::Text_H), QString());
_attributeDefaults.insert(index(PrimitiveType::Symbol, Attribute::Text_KLNPJ), QString());
_attributeDefaults.insert(index(PrimitiveType::Symbol, Attribute::Text_M), QString());
_attributeDefaults.insert(index(PrimitiveType::Symbol, Attribute::Text_T), QString());
_attributeDefaults.insert(index(PrimitiveType::Symbol, Attribute::Text_V), QString());
_attributeDefaults.insert(index(PrimitiveType::Symbol, Attribute::Text_W), QString());
_attributeDefaults.insert(index(PrimitiveType::Symbol, Attribute::Text_XY), QString());
_attributeDefaults.insert(index(PrimitiveType::Symbol, Attribute::Text_Z), QString());
_attributeDefaults.insert(index(PrimitiveType::Symbol, Attribute::att_vbg_et), QString());
_attributeDefaults.insert(index(PrimitiveType::Text, Attribute::AnchorHorizontal), QLatin1String("center"));
_attributeDefaults.insert(index(PrimitiveType::Text, Attribute::AnchorVertical), QLatin1String("center"));
_attributeDefaults.insert(index(PrimitiveType::Text, Attribute::Box), QLatin1String("0"));
_attributeDefaults.insert(index(PrimitiveType::Text, Attribute::Color), QColor().name());
_attributeDefaults.insert(index(PrimitiveType::Text, Attribute::Fill), QLatin1String("0"));
_attributeDefaults.insert(index(PrimitiveType::Text, Attribute::FillColor), QColor().name());
_attributeDefaults.insert(index(PrimitiveType::Text, Attribute::FillPattern), QLatin1String("none"));
_attributeDefaults.insert(index(PrimitiveType::Text, Attribute::Font), defaultFont.key());
_attributeDefaults.insert(index(PrimitiveType::Text, Attribute::FontBold), QLatin1String("0"));
_attributeDefaults.insert(index(PrimitiveType::Text, Attribute::FontItalic), QLatin1String("0"));
_attributeDefaults.insert(index(PrimitiveType::Text, Attribute::FontSize), QString::number(fontSize));
_attributeDefaults.insert(index(PrimitiveType::Text, Attribute::LineColor), QColor().name());
_attributeDefaults.insert(index(PrimitiveType::Text, Attribute::LineStyle), QLatin1String("solid"));
_attributeDefaults.insert(index(PrimitiveType::Text, Attribute::LineWidth), QLatin1String("0.1"));
_attributeDefaults.insert(index(PrimitiveType::Text, Attribute::MarginHorizontal), QLatin1String("1"));
_attributeDefaults.insert(index(PrimitiveType::Text, Attribute::MarginVertical), QLatin1String("1"));
_attributeDefaults.insert(index(PrimitiveType::Text, Attribute::Rotate), QLatin1String("0"));
_attributeTypes[Attribute::AbcProtection] = QVariant::Bool; // Type: bool
_attributeTypes[Attribute::Affiliation] = QVariant::UserType; // Type: Symbol::t_affil
_attributeTypes[Attribute::Alignment] = QVariant::UserType; // Type: HorizontalAlign
_attributeTypes[Attribute::AnchorHorizontal] = QVariant::UserType; // Type: HorizontalAlign
_attributeTypes[Attribute::AnchorVertical] = QVariant::UserType; // Type: t_valign
_attributeTypes[Attribute::ArrowClampHeight] = QVariant::Double; // Type: double
_attributeTypes[Attribute::ArrowHeight] = QVariant::Double; // Type: double
_attributeTypes[Attribute::ArrowLineWidth] = QVariant::Double; // Type: double
_attributeTypes[Attribute::Arrows] = QVariant::UserType; // Type: t_arrows
_attributeTypes[Attribute::ArrowWidth] = QVariant::Double; // Type: double
_attributeTypes[Attribute::Box] = QVariant::Bool; // Type: bool
_attributeTypes[Attribute::Center] = QVariant::PointF; // Type: PointF
_attributeTypes[Attribute::Close] = QVariant::Bool; // Type: bool
_attributeTypes[Attribute::Color] = QVariant::Color; // Type: QColor
_attributeTypes[Attribute::Extent] = QVariant::Double; // Type: double
_attributeTypes[Attribute::Fill] = QVariant::Bool; // Type: bool
_attributeTypes[Attribute::FillColor] = QVariant::Color; // Type: QColor
_attributeTypes[Attribute::FillPattern] = QVariant::UserType; // Type: t_fillPattern
_attributeTypes[Attribute::FillStyle] = QVariant::UserType; // Type: t_fillStyle
_attributeTypes[Attribute::Font] = QVariant::UserType; // Type: t_font
_attributeTypes[Attribute::FontBold] = QVariant::Bool; // Type: bool
_attributeTypes[Attribute::FontItalic] = QVariant::Bool; // Type: bool
_attributeTypes[Attribute::FontSize] = QVariant::Double; // Type: double
_attributeTypes[Attribute::LineColor] = QVariant::Color; // Type: QColor
_attributeTypes[Attribute::LineStyle] = QVariant::UserType; // Type: t_lineStyle
_attributeTypes[Attribute::LineWidth] = QVariant::Double; // Type: double
_attributeTypes[Attribute::MarginHorizontal] = QVariant::UserType; // Type: int
_attributeTypes[Attribute::MarginVertical] = QVariant::UserType; // Type: int
_attributeTypes[Attribute::Mobility] = QVariant::UserType; // Type: Symbol::t_mob
_attributeTypes[Attribute::SIDC] = QVariant::String; // Type: QString
_attributeTypes[Attribute::SIDC_Color] = QVariant::Color; // Type: QColor
_attributeTypes[Attribute::SIDC_Attributes] = QVariant::String; // Type: QString
_attributeTypes[Attribute::SymbolId] = QVariant::Int; // Type: int
_attributeTypes[Attribute::SymbolOffsetX] = QVariant::Int; // Type: int
_attributeTypes[Attribute::SymbolOffsetY] = QVariant::Int; // Type: int
_attributeTypes[Attribute::SymbolDirection] = QVariant::Double; // Type: double
_attributeTypes[Attribute::ForceId] = QVariant::Int; // Type: int
_attributeTypes[Attribute::SymbolState] = QVariant::UserType; // Type: SymbolTypes::t_state
_attributeTypes[Attribute::SymbolUncertainty] = QVariant::UserType; // Type: SymbolTypes::t_uncertainty
_attributeTypes[Attribute::SymbolExplicitScale] = QVariant::Double; // Type: double
_attributeTypes[Attribute::DamageForceId] = QVariant::Int; // Type: int
_attributeTypes[Attribute::Injury] = QVariant::Int; // Type: int
_attributeTypes[Attribute::PeMapBrightness] = QVariant::Double; // Type: double
_attributeTypes[Attribute::PeMapCenterX] = QVariant::Int; // Type: int
_attributeTypes[Attribute::PeMapCenterY] = QVariant::Int; // Type: int
_attributeTypes[Attribute::PeMapSaturation] = QVariant::Double; // Type: double
_attributeTypes[Attribute::PeMapZoom] = QVariant::Double; // Type: double
_attributeTypes[Attribute::PeMapRotation] = QVariant::Double; // Type: double
_attributeTypes[Attribute::PeMapType] = QVariant::UserType; // Type: t_mapType
_attributeTypes[Attribute::PeShowUtm] = QVariant::Bool; // Type: bool
_attributeTypes[Attribute::PeSymbolOpacity] = QVariant::Double; // Type: double
_attributeTypes[Attribute::PeSymbolFillType] = QVariant::UserType; // Type: SymbolTypes::t_filltype
_attributeTypes[Attribute::PeSymbolScale] = QVariant::Bool; // Type: bool
_attributeTypes[Attribute::MetaDataTitle] = QVariant::String; // Type: QString
_attributeTypes[Attribute::MetaDataAuthor] = QVariant::String; // Type: QString
_attributeTypes[Attribute::MetaDataDate] = QVariant::DateTime;
_attributeTypes[Attribute::MetaDataDesciption] = QVariant::String; // Type: QString
_attributeTypes[Attribute::MetaDataMinScale] = QVariant::Double; // Type: double
_attributeTypes[Attribute::MetaDataMaxScale] = QVariant::Double; // Type: double
_attributeTypes[Attribute::Rotate] = QVariant::Double; // Type: double
_attributeTypes[Attribute::Rounding] = QVariant::Double; // Type: double
_attributeTypes[Attribute::Start] = QVariant::Double; // Type: double
_attributeTypes[Attribute::Text_EF] = QVariant::String; // Type: QString
_attributeTypes[Attribute::Text_G] = QVariant::String; // Type: QString
_attributeTypes[Attribute::Text_H] = QVariant::String; // Type: QString
_attributeTypes[Attribute::Text_KLNPJ] = QVariant::String; // Type: QString
_attributeTypes[Attribute::Text_M] = QVariant::String; // Type: QString
_attributeTypes[Attribute::Text_T] = QVariant::String; // Type: QString
_attributeTypes[Attribute::Text_V] = QVariant::String; // Type: QString
_attributeTypes[Attribute::Text_W] = QVariant::String; // Type: QString
_attributeTypes[Attribute::Text_XY] = QVariant::String; // Type: QString
_attributeTypes[Attribute::Text_Z] = QVariant::String; // Type: QString
_attributeTypes[Attribute::UtmEast] = QVariant::Int; // Type: int
_attributeTypes[Attribute::UtmGrid] = QVariant::String; // Type: QString
_attributeTypes[Attribute::UtmNorth] = QVariant::Int; // Type: int
_attributeTypes[Attribute::UtmZone] = QVariant::String; // Type: QString
_attributeTypes[Attribute::att_vbg_et] = QVariant::UserType; // Type: t_w_vbg_et
_staticInitDone = true;
}
QDomElement root = createElement(rootNodeName);
appendChild(root);
clearUndoStack();
} // void GeometryModelQDom::init()
void GeometryModelQDom::cleanupStaticMember()
{
_primitiveTagsTypes.clear();
_primitiveTagsStrings.clear();
_primitiveSupportedAttributes.clear();
_attributeDefaults.clear();
_attributeTypes.clear();
}
GeometryModel::Node GeometryModelQDom::getMapDefaultSettingsNode() const
{
QDomElement mapSettings = firstChildElement(mapSettingsName);
if (mapSettings.isNull())
{
GeometryModelQDom *THIS = const_cast<GeometryModelQDom *>(this); // cast const away
mapSettings = THIS->createElement(mapSettingsName);
THIS->appendChild(mapSettings);
using index = QPair<GeometryModelQDom::PrimitiveType, GeometryModelQDom::Attribute>;
_attributeDefaults.insert(index(PrimitiveType::MapDefaults, Attribute::PeMapBrightness), QLatin1String("100"));
_attributeDefaults.insert(index(PrimitiveType::MapDefaults, Attribute::PeMapCenterX), QLatin1String("0.0"));
_attributeDefaults.insert(index(PrimitiveType::MapDefaults, Attribute::PeMapCenterY), QLatin1String("0.0"));
_attributeDefaults.insert(index(PrimitiveType::MapDefaults, Attribute::PeMapSaturation), QLatin1String("100"));
_attributeDefaults.insert(index(PrimitiveType::MapDefaults, Attribute::PeMapZoom), QLatin1String("1.0"));
_attributeDefaults.insert(index(PrimitiveType::MapDefaults, Attribute::PeMapRotation), QLatin1String("0.0"));
_attributeDefaults.insert(index(PrimitiveType::MapDefaults, Attribute::PeMapType), QLatin1String("MapPrimitiveType::Unknown"));
_attributeDefaults.insert(index(PrimitiveType::MapDefaults, Attribute::PeShowUtm), QLatin1String("1"));
_attributeDefaults.insert(index(PrimitiveType::MapDefaults, Attribute::UtmEast), QLatin1String("10000"));
_attributeDefaults.insert(index(PrimitiveType::MapDefaults, Attribute::UtmGrid), QLatin1String("XY"));
_attributeDefaults.insert(index(PrimitiveType::MapDefaults, Attribute::UtmNorth), QLatin1String("10000"));
_attributeDefaults.insert(index(PrimitiveType::MapDefaults, Attribute::UtmZone), QLatin1String("00Z"));
_attributeDefaults.insert(index(PrimitiveType::MapDefaults, Attribute::PeSymbolOpacity), QLatin1String("1.0"));
_attributeDefaults.insert(index(PrimitiveType::MapDefaults, Attribute::PeSymbolFillType), QLatin1String("filled"));
_attributeDefaults.insert(index(PrimitiveType::MapDefaults, Attribute::PeSymbolScale), QLatin1String("1.0"));
// Create root-node and set required attributes
QList<Attribute> modelAttributes = supportedAttributes(PrimitiveType::MapDefaults);
for (int i = 0; i < modelAttributes.size(); ++i)
{
Attribute at = modelAttributes.at(i);
THIS->setModelEditorAttribute(at, _attributeDefaults[index(PrimitiveType::MapDefaults, at)]);
}
}
return Node(Node::Implementation(mapSettings));
} // GeometryModelQDom::getMapDefaultSettingsNode
void GeometryModelQDom::transformNode(const QDomNode &node, const QTransform &t)
{
QString tag = node.nodeName();
if (!_primitiveTagsTypes.contains(tag))
{
emit modelError(tr("Can not translate node of type %1").arg(tag));
return;
}
QDomNodeList nodes = node.childNodes();
for (int i = 0; i < nodes.size(); ++i)
{
QDomElement p = nodes.at(i).toElement();
if (p.nodeName() != QLatin1String("point"))
continue;
if (!p.hasAttribute(QLatin1String("x")) || !p.hasAttribute(QLatin1String("y")))
emit modelError(tr("Invalid point in primitive of type %1").arg(tag));
else
{
bool okx, oky;
double oldx = p.toElement().attribute(QLatin1String("x")).toDouble(&okx);
double oldy = p.toElement().attribute(QLatin1String("y")).toDouble(&oky);
if (!(okx && oky))
emit modelError(tr("Invalid point in primitive of type %1").arg(tag));
else
{
QPointF point = t.map(QPointF(oldx, oldy));
p.setAttribute(QLatin1String("x"), QString::number(point.x(), 'f', CoordinateDoublePrecision));
p.setAttribute(QLatin1String("y"), QString::number(point.y(), 'f', CoordinateDoublePrecision));
}
}
}
} // void GeometryModelQDom::transformNode(QDomNode node, QTransform t)
void GeometryModelQDom::emitChangedSignal(const Node &node, Attribute att, bool coordsChanged)
{
if (!_skipChangedSignal)
emit changed(node, att, coordsChanged);
} // void GeometryModelQDom::emitChangedSignal(QDomNode node, Attribute att, bool coordsChanged)
void GeometryModelQDom::pushUndo(const QString &eventDescription)
{
if (_undoEnabled && (! _insideUndoBlock))
{
QDomElement root = firstChildElement(rootNodeName);
while (undoSteps() >= _maxUndoSteps)
{
// Size-limit reached, remove first element
_undoStack.erase(_undoStack.begin());
_undoHistory.erase(_undoHistory.begin());
}
_undoStack.push(root.cloneNode());
_undoHistory.push(eventDescription);
}
if (_insideUndoBlock)
_undoHistoryBlock = eventDescription;
} // void GeometryModelQDom::pushUndo(const QString &eventDescription)
GeometryModel::Node GeometryModelQDom::popUndo()
{
if (_undoEnabled && (! _insideUndoBlock))
{
_undoHistory.pop();
return Node(Node::Implementation(_undoStack.pop()));
}
return Node();
} // void GeometryModelQDom::pushUndo()
bool GeometryModelQDom::parseSymbolAttributeString(const QString &sidcAttributes, QMap<QString, QVariant> &attrMap) const
{
attrMap.clear();
if (sidcAttributes.isEmpty()) return true;
bool ok = true;
const QVector<QStringRef> sidcAttrList = sidcAttributes.splitRef(QLatin1Char(';'));
for (const QStringRef &attr : sidcAttrList)
{
const QVector<QStringRef> &attrPair = attr.split(QLatin1Char('='));
if (attrPair.size() != 2)
{
ok = false;
QString errorString = tr("%1 Parsing symbol attribute list failed. %2").arg(QString::fromStdString(LOGFUNCTION), attr.toString());
emit const_cast<GeometryModelQDom*>(this)->attributeError(errorString);
continue;
}
attrMap[attrPair.first().toString()] = attrPair.last().toString();
}
return ok;
} // bool GeometryModelQDom::parseSymbolAttributeString( const QString & sidcAttributes, QMap<QString,QVariant> & attrMap ) const
QString GeometryModelQDom::buildSymbolAttributeString(const QMap<QString, QVariant> &attrMap) const
{
QString attributeString;
QMap<QString, QVariant>::const_iterator iter = attrMap.cbegin();
while (attrMap.cend() != iter)
{
const QString &key = iter.key();
const QString &val = iter.value().toString();
if (!val.isEmpty())
{
if (key.isEmpty())
{
QString errorString = tr("%1 Empty key found").arg(QString::fromStdString(LOGFUNCTION));
emit const_cast<GeometryModelQDom*>(this)->attributeError(errorString);
++iter;
continue;
}
if (val.contains(QLatin1Char('=')) || val.contains(QLatin1Char(';')))
{
QString errorString = tr("%1 Attribute value has illegal characters <;=> : %2").arg(QString::fromStdString(LOGFUNCTION), val);
emit const_cast<GeometryModelQDom*>(this)->attributeError(errorString);
++iter;
continue;
}
if (!attributeString.isEmpty()) attributeString += QLatin1Char(';');
attributeString += QStringLiteral("%1=%2").arg(key, val);
}
++iter;
}
return attributeString;
} // QString GeometryModelQDom::buildSymbolAttributeString(const QMap<QString, QVariant> & attrMap) const
} // namespace SituationMap