/** ** ** @RDE_HEADER@ ** Do all the work for complex selection operations. ** $Id$ ** $HeadURL$ ** $Author$ ** ** ----------------------------------------------------------------------------------------------- ** ** Hardware-Environment: Intel-PC ** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5 ** ** Language ........: C++ 11 ** ** ----------------------------------------------------------------------------------------------- ** ** Author ...........: Jörg Turla, SPD G, Tel. 3132 ** ** ----------------------------------------------------------------------------------------------- ** ** Notes .........: ** ** 25.07.2016, JT : First edition for use with Qt5 ** ** ----------------------------------------------------------------------------------------------- */ #include "symbol_favourites.h" #include "plan_editor.h" #include #include #include #include #include #include namespace PlanEditor { static const char *const attributeKeyName = "name"; static const char *const attributeKeySymbolCode = "sidc"; class DomNodeVisitor { public: DomNodeVisitor() = default; virtual ~DomNodeVisitor() = default; DomNodeVisitor(const DomNodeVisitor &) = delete; DomNodeVisitor &operator = (const DomNodeVisitor &) = delete; bool traverse(const QDomNode &node) { if (node.isNull()) return true; if (!apply(node)) return false; const QDomNodeList &childList = node.childNodes(); for (int i = 0; i < childList.size(); ++i) { if (!traverse(childList.at(i))) return false; } return postApply(node); } // void traverse( const QDomNode & node ) bool traverse(const QDomDocument &domDoc) { return traverse(static_cast(domDoc)); } private: virtual bool apply(const QDomNode &) = 0; virtual bool postApply(const QDomNode &) { return true; } }; // DomVisitor class ListNodes : public DomNodeVisitor { QList m_sidcNodes; QStringList m_sidcList; QList m_scopeNodes; QStringList m_scopeList; bool apply(const QDomNode &node) override; public: explicit ListNodes(const QDomDocument &domDoc) : DomNodeVisitor() , m_sidcNodes() , m_sidcList() , m_scopeNodes() , m_scopeList() { traverse(domDoc); } virtual ~ListNodes() = default; const QList &nodeScopeList() const { return m_scopeNodes; } const QList &nodeSidcList() const { return m_sidcNodes; } const QStringList &scopeList() const { return m_scopeList; } const QStringList &sidcList() const { return m_sidcList; } }; // ListNodes class FindSidc : public DomNodeVisitor { QDomNode m_sidcNode; QString m_sidc; bool apply(const QDomNode &node) override; public: FindSidc(const QDomDocument &domDoc, const QString &sidc) : DomNodeVisitor(), m_sidcNode(), m_sidc(sidc) { traverse(domDoc); } virtual ~FindSidc() = default; bool found() const { return !m_sidcNode.isNull(); } QDomNode sidcNode() const { return m_sidcNode; } }; // FindSidc class FindScope : public DomNodeVisitor { QDomNode m_scopeNode; QString m_scope; bool apply(const QDomNode &node) override; public: FindScope(const QDomDocument &domDoc, const QString &scope) : DomNodeVisitor(), m_scopeNode(), m_scope(scope) { traverse(domDoc); } virtual ~FindScope() = default; bool found() const { return !m_scopeNode.isNull(); } QDomNode scopeNode() const { return m_scopeNode; } }; // FindScope class SymbolFavouritesDom; class IncludeOperator : public DomNodeVisitor { SymbolFavouritesDom &m_mainFavourites; QString m_currentScope; bool apply(const QDomNode &node) override; bool postApply(const QDomNode &node) override; public: IncludeOperator(SymbolFavouritesDom &mainFavourites, const SymbolFavourites &toInclude); virtual ~IncludeOperator() = default; }; // IncludeOperator class CopyScopeOperator : public DomNodeVisitor { SymbolFavourites &m_scopeFavourites; QString m_scope; bool m_doCut; unsigned int m_symbolCount; bool apply(const QDomNode &node) override; bool postApply(const QDomNode &node) override; public: CopyScopeOperator(const SymbolFavouritesDom &mainFavourites, const QString &scope, SymbolFavourites &scopeFavourites); virtual ~CopyScopeOperator() = default; bool scopeIsNotEmpty() const { return m_symbolCount; } }; // CopyScopeOperator class VisitorVisitor : public DomNodeVisitor { const SymbolFavourites::SymbolVisitor &m_symbolVisitor; QString m_currentScope; bool apply(const QDomNode &node) override; bool postApply(const QDomNode &node) override; public: VisitorVisitor(const QDomDocument &domDoc, const SymbolFavourites::SymbolVisitor &symbolVisitor) : DomNodeVisitor() , m_symbolVisitor(symbolVisitor) , m_currentScope() { traverse(domDoc); } // VisitorVisitor( const QDomDocument & domDoc, const SymbolFavourites::SymbolVisitor & symbolVisitor ) virtual ~VisitorVisitor() = default; }; SymbolFavourites::SymbolFavourites() : QObject(nullptr) {;} class SymbolFavouritesDom : public SymbolFavourites, virtual protected QDomDocument { Q_OBJECT friend FindScope; friend FindSidc; friend ListNodes; friend IncludeOperator; friend CopyScopeOperator; friend VisitorVisitor; public: enum class NodeType { Anything, Scope, Symbol }; // NodeType SymbolFavouritesDom() : QDomDocument(QLatin1String(m_rootNodeName) + QLatin1String("Document")), m_logger(getLogger("SymbolFavourites")) { if (!m_initStaticDone) initStatic(); QDomElement root = createElement(QLatin1String(m_rootNodeName)); appendChild(root); } virtual ~SymbolFavouritesDom() = default; QStringList sidcList() const override { ListNodes listSidc(*this); return listSidc.sidcList(); } // QStringList sidcList() const QStringList scopeList() const override { ListNodes listScope(*this); return listScope.scopeList(); } // QStringList scopeList() const void addScope(const QString &scope) override { if (scope.isEmpty()) return; FindScope findScope(*this, scope); if (!findScope.found()) addScopeNode(scope); } // void addScope( const QString & scope ) void addSymbolFavourite(const QString &sidc, const QString &scope, const QString &name) override { FindSidc findSidc(*this, sidc); if (findSidc.found()) { // remove sidc node when already exists removeSymbolNode(QDomNode(), findSidc.sidcNode()); } QDomNode scopeNode = firstChildElement(QLatin1String(m_rootNodeName)); if (!scope.isEmpty()) { FindScope findScope(*this, scope); if (!findScope.found()) scopeNode = addScopeNode(scope); else scopeNode = findScope.scopeNode(); } addSymbolNode(scopeNode, scope, name, sidc); } // void addSymbolFavourite( const QString & sidc, const QString & scope, const QString & name ) override bool isFavourite(const QString &sidc) const override { FindSidc findSidc(*this, sidc); return findSidc.found(); } // bool isFavourite( const QString & sidc ) const QString scope(const QString &sidc) const override { FindSidc findSidc(*this, sidc); if (findSidc.found()) { QDomElement symbolNode = findSidc.sidcNode().toElement(); if (!symbolNode.isNull()) { QDomElement scopeNode = symbolNode.parentNode().toElement(); if (!scopeNode.isNull()) { // In case of symbol node has any scope it is parent of root node // and scope is then an empty string. return scopeNode.attribute(QLatin1String(attributeKeyName), QString()); } } } return QString(); } // QString scope( const QString & sidc ) const QString name(const QString &sidc) const override { FindSidc findSidc(*this, sidc); if (findSidc.found()) { QDomElement symbolNode = findSidc.sidcNode().toElement(); if (!symbolNode.isNull()) return symbolNode.attribute(QLatin1String(attributeKeyName)); } return QString(); } // QString name( const QString & sidc ) const void removeSymbolFavourite(const QString &sidc) override { FindSidc findSidc(*this, sidc); if (findSidc.found()) { // remove sidc node when already exists removeSymbolNode(QDomNode(), findSidc.sidcNode()); } } // void removeSymbolFavourite( const QString & sidc ) void removeScope(const QString &scope) override { FindScope findScope(*this, scope); if (findScope.found()) removeScopeNode(findScope.scopeNode()); } // void removeScope( const QString & scope ) void includeSymbolFavourites(const SymbolFavourites &toInclude) override { IncludeOperator incOp(*this, toInclude); } // void includeSymbolFavourites( const SymbolFavourites & toInclude ) bool copyScope(const QString &scope, SymbolFavourites &scopeSymbols) override { CopyScopeOperator copyOp(*this, scope, scopeSymbols); return copyOp.scopeIsNotEmpty(); } // bool copyScope( const QString & scope, SymbolFavourites & scopeSymbols ) QString toString() override { return QDomDocument::toString(3); } class UpdateVisitor : public SymbolFavourites::SymbolVisitor { public: UpdateVisitor(SymbolFavouritesDom *fav, bool construction) : m_favourites(fav), m_construction(construction) {;} private: SymbolFavouritesDom *m_favourites; bool m_construction; bool apply(const QString &scope) const override { if (m_construction) m_favourites -> emitSignalNewScope(scope); else m_favourites -> emitSignalDeleteScope(scope); return true; } bool apply(const QString &scope, const QString &name, const QString &sidc) const override { Q_UNUSED(name); if (m_construction) m_favourites -> emitSignalNewSymbol(scope, sidc); else m_favourites -> emitSignalDeleteSymbol(sidc); return true; } }; // UpdateVisitor bool contentFromString(const QString &xml) override { if (xml.isEmpty()) return true; const QString &backup = toString(); QString errorMsg; int errorLine; int errorColumn; if (!setContent(xml, &errorMsg, &errorLine, &errorColumn)) { ERROR_LOG(m_logger) << LOGFUNCTION << " parsing xml input failed: " << errorMsg << " at line " << errorLine << " , column " << errorColumn; setContent(backup); return false; } VisitorVisitor update(*this, UpdateVisitor(this, true)); return true; } // bool contentFromString(const QString & xml) override bool contentFromDevice(QIODevice *device) override { if (nullptr == device) return false; const QString &backup = toString(); QString errorMsg; int errorLine; int errorColumn; if (!setContent(device, &errorMsg, &errorLine, &errorColumn)) { ERROR_LOG(m_logger) << LOGFUNCTION << " parsing xml input failed: " << errorMsg << " at line " << errorLine << " , column " << errorColumn; setContent(backup); return false; } VisitorVisitor update(*this, UpdateVisitor(this, true)); return true; } // bool contentFromDevice( const QIODevice * device ) override void traverse(const SymbolVisitor &symbolVisitor) override { VisitorVisitor visitorVisitor(*this, symbolVisitor); } void emitSignalNewScope(const QString &scope) { emit signalNewScope(scope); } void emitSignalNewSymbol(const QString &scope, const QString &sidc) { emit signalNewSymbol(scope, sidc); } void emitSignalDeleteScope(const QString &scope) { emit signalDeleteScope(scope); } void emitSignalDeleteSymbol(const QString &sidc) { emit signalDeleteSymbol(sidc); } private: QDomElement addScopeNode(const QString &scope) { QDomElement root = firstChildElement(QLatin1String(m_rootNodeName)); QDomElement scopeNode = createElement(m_nodeTagStrings[NodeType::Scope]); scopeNode.setAttribute(QLatin1String(attributeKeyName), scope); root.appendChild(scopeNode); emitSignalNewScope(scope); return scopeNode; } // QDomElement addScopeNode( const QString & scope ) QDomElement addSymbolNode(QDomNode &scopeNode, const QString &scope, const QString &name, const QString &sidc) { QDomElement symbolNode = createElement(m_nodeTagStrings[NodeType::Symbol]); symbolNode.setAttribute(QLatin1String(attributeKeyName), name); symbolNode.setAttribute(QLatin1String(attributeKeySymbolCode), sidc); scopeNode.appendChild(symbolNode); emit signalNewSymbol(scope, sidc); return symbolNode; } // QDomElement addSymbolNode( QDomNode & scopeNode, const QString & name, const QString & sidc ) void removeScopeNode(const QDomNode &scopeNode) { QDomNode parent = scopeNode.parentNode(); if (!parent.isNull()) { const QDomNodeList &childList = scopeNode.childNodes(); for (int i = 0; i < childList.size(); ++i) removeSymbolNode(scopeNode, childList.at(i)); if (isSignalConnected(QMetaMethod::fromSignal(&SymbolFavourites::signalDeleteScope))) { const QDomElement &scopeElem = scopeNode.toElement(); const QString &scope = scopeElem.attribute(QLatin1String(attributeKeyName), QString());; emit signalDeleteScope(scope); } parent.removeChild(scopeNode); } } // void removeScopeNode( QDomNode & scopeNode ) void removeSymbolNode(const QDomNode &scopeNode, const QDomNode &symbolNode) { if (symbolNode.isNull()) return; QDomNode parent = scopeNode; if (parent.isNull()) parent = symbolNode.parentNode(); if (!parent.isNull()) { if (isSignalConnected(QMetaMethod::fromSignal(&SymbolFavourites::signalDeleteSymbol))) { const QDomElement &symbolElem = symbolNode.toElement(); const QString &sidc = symbolElem.attribute(QLatin1String(attributeKeySymbolCode), QString());; emit signalDeleteSymbol(sidc); } parent.removeChild(symbolNode); } } // void removeSymbolNode( const QDomNode & symbolNode ) Logger &m_logger; static bool m_initStaticDone; static const char *const m_rootNodeName; static QMap m_nodeTags; static QMap m_nodeTagStrings; static NodeType nodeType(const QDomNode &node) { const QString &tag = node.nodeName(); return (m_nodeTags.contains(tag)) ? m_nodeTags[tag] : NodeType::Anything; } // NodeType nodeType( const QDomNode & node ) static void initStatic(); }; // SymbolFavouritesDom SymbolFavourites *SymbolFavourites::create() { return new SymbolFavouritesDom(); } SymbolFavourites *SymbolFavourites::createFromString(const QString &xml) { SymbolFavouritesDom *domDoc = new SymbolFavouritesDom(); if (domDoc->contentFromString(xml)) return domDoc; delete domDoc; return nullptr; } // SymbolFavourites * SymbolFavourites::createFromString( const QString & xml ) SymbolFavourites *SymbolFavourites::createFromDevice(QIODevice *device) { SymbolFavouritesDom *domDoc = new SymbolFavouritesDom(); if (domDoc->contentFromDevice(device)) return domDoc; delete domDoc; return nullptr; } // SymbolFavourites * SymbolFavourites::createFromDevice( QIODevice * device ) const char *const SymbolFavouritesDom::m_rootNodeName = "SymbolFavourites"; bool SymbolFavouritesDom::m_initStaticDone = false; QMap SymbolFavouritesDom::m_nodeTags; QMap SymbolFavouritesDom::m_nodeTagStrings; void SymbolFavouritesDom::initStatic() { m_nodeTags[QLatin1String("Scope")] = NodeType::Scope; m_nodeTags[QLatin1String("Symbol")] = NodeType::Symbol; m_nodeTagStrings[NodeType::Scope ] = QLatin1String("Scope"); m_nodeTagStrings[NodeType::Symbol] = QLatin1String("Symbol"); m_initStaticDone = true; } // void SymbolFavouritesDom::initStatic() bool ListNodes::apply(const QDomNode &node) { const QString &tag = node.nodeName(); if (SymbolFavouritesDom::m_nodeTags.contains(tag)) { switch (SymbolFavouritesDom::m_nodeTags[tag]) { case SymbolFavouritesDom::NodeType::Symbol: { QDomElement e = node.toElement(); if (e.hasAttribute(QLatin1String(attributeKeySymbolCode))) { m_sidcNodes += node; m_sidcList += e.attribute(QLatin1String(attributeKeySymbolCode)); } } break; case SymbolFavouritesDom::NodeType::Scope: { QDomElement e = node.toElement(); if (e.hasAttribute(QLatin1String(attributeKeyName))) { m_scopeNodes += node; m_scopeList += e.attribute(QLatin1String(attributeKeyName)); } } break; default : break; } } return true; } // bool ListNodes::apply( const QDomNode & node ) bool FindSidc::apply(const QDomNode &node) { const QString &tag = node.nodeName(); if (SymbolFavouritesDom::m_nodeTags.contains(tag)) { if (SymbolFavouritesDom::NodeType::Symbol == SymbolFavouritesDom::m_nodeTags[tag]) { QDomElement e = node.toElement(); if (e.attribute(QLatin1String(attributeKeySymbolCode)) == m_sidc) { m_sidcNode = node; return false; } } } return true; } // bool FindSidc::apply( const QDomNode & node ) bool FindScope::apply(const QDomNode &node) { const QString &tag = node.nodeName(); if (SymbolFavouritesDom::m_nodeTags.contains(tag)) { if (SymbolFavouritesDom::NodeType::Scope == SymbolFavouritesDom::m_nodeTags[tag]) { QDomElement e = node.toElement(); if (e.attribute(QLatin1String(attributeKeyName)) == m_scope) { m_scopeNode = node; return false; } } } return true; } // bool FindScope::apply( const QDomNode & node ) IncludeOperator::IncludeOperator(SymbolFavouritesDom &mainFavourites, const SymbolFavourites &toInclude) : DomNodeVisitor() , m_mainFavourites(mainFavourites) , m_currentScope() { const SymbolFavouritesDom *toIncludeDom = dynamic_cast(&toInclude); if (toIncludeDom) traverse(*toIncludeDom); else ERROR_LOG(mainFavourites.m_logger) << LOGFUNCTION << " Type mismatch: SymbolFavourites toInclude have wrong type."; } // IncludeOperator::IncludeOperator( SymbolFavouritesDom & mainFavourites, SymbolFavouritesDom & toInclude ) bool IncludeOperator::apply(const QDomNode &node) { const QString &tag = node.nodeName(); switch (SymbolFavouritesDom::m_nodeTags[tag]) { case SymbolFavouritesDom::NodeType::Scope: { QDomElement elmt = node.toElement(); const QString &scope = elmt.attribute(QLatin1String(attributeKeyName)); m_mainFavourites.addScope(scope); m_currentScope = scope; } break; case SymbolFavouritesDom::NodeType::Symbol: { QDomElement elmt = node.toElement(); const QString &name = elmt.attribute(QLatin1String(attributeKeyName)); const QString &sidc = elmt.attribute(QLatin1String(attributeKeySymbolCode)); m_mainFavourites.addSymbolFavourite(sidc, m_currentScope, name); } break; default : break; } return true; } // bool IncludeOperator::apply( const QDomNode & node ) bool IncludeOperator::postApply(const QDomNode &node) { // if scope node has been processed reset m_currentScope const QString &tag = node.nodeName(); if (SymbolFavouritesDom::NodeType::Scope == SymbolFavouritesDom::m_nodeTags[tag]) m_currentScope.clear(); return true; } // bool IncludeOperator::postApply( const QDomNode & node ) CopyScopeOperator::CopyScopeOperator(const SymbolFavouritesDom &mainFavourites, const QString &scope, SymbolFavourites &scopeFavourites) : DomNodeVisitor() , m_scopeFavourites(scopeFavourites) , m_scope(scope) , m_doCut(false) , m_symbolCount(0) { traverse(mainFavourites); } // CopyScopeOperator::CopyScopeOperator( SymbolFavouritesDom & mainFavourites, const QString & scope, SymbolFavouritesDom & scopeFavourites ) bool CopyScopeOperator::apply(const QDomNode &node) { const QString &tag = node.nodeName(); switch (SymbolFavouritesDom::m_nodeTags[tag]) { case SymbolFavouritesDom::NodeType::Scope: { QDomElement elmt = node.toElement(); const QString &scope = elmt.attribute(QLatin1String(attributeKeyName)); if (scope == m_scope) { m_scopeFavourites.addScope(scope); m_doCut = true; } } break; case SymbolFavouritesDom::NodeType::Symbol: { if (m_doCut) { QDomElement elmt = node.toElement(); const QString &name = elmt.attribute(QLatin1String(attributeKeyName)); const QString &sidc = elmt.attribute(QLatin1String(attributeKeySymbolCode)); m_scopeFavourites.addSymbolFavourite(sidc, m_scope, name); m_symbolCount++; } } break; default: break; } return true; } // bool CopyScopeOperator::apply( const QDomNode & node ) bool CopyScopeOperator::postApply(const QDomNode &node) { if (m_doCut) { // if scope node has been processed reset m_currentScope const QString &tag = node.nodeName(); if (SymbolFavouritesDom::NodeType::Scope == SymbolFavouritesDom::m_nodeTags[tag]) { m_doCut = false; return false; } } return true; } // bool CopyScopeOperator::postApply( const QDomNode & node ) bool VisitorVisitor::apply(const QDomNode &node) { const QString &tag = node.nodeName(); switch (SymbolFavouritesDom::m_nodeTags[tag]) { case SymbolFavouritesDom::NodeType::Scope: { QDomElement elmt = node.toElement(); m_currentScope = elmt.attribute(QLatin1String(attributeKeyName)); return m_symbolVisitor.apply(m_currentScope); } break; case SymbolFavouritesDom::NodeType::Symbol: { QDomElement elmt = node.toElement(); const QString &name = elmt.attribute(QLatin1String(attributeKeyName)); const QString &sidc = elmt.attribute(QLatin1String(attributeKeySymbolCode)); return m_symbolVisitor.apply(m_currentScope, name, sidc); } break; default: break; } return true; } // bool VisitorVisitor::apply( const QDomNode & node ) bool VisitorVisitor::postApply(const QDomNode &node) { const QString &tag = node.nodeName(); if (SymbolFavouritesDom::NodeType::Scope == SymbolFavouritesDom::m_nodeTags[tag]) m_currentScope.clear(); return true; } // bool VisitorVisitor::postApply( const QDomNode & node ) bool SymbolFavourites::SymbolVisitor::apply(const QString &) const { return true; } bool SymbolFavourites::SymbolVisitor::apply(const QString &, const QString &, const QString &) const { return true; } } // namespace PlanEditor #include "symbol_favourites.moc"