1 /*
2     This file is part of Rocs.
3     SPDX-FileCopyrightText: 2006-2007 Gael de Chalendar <kleag@free.fr>
4     SPDX-FileCopyrightText: 2012-2014 Andreas Cord-Landwehr <cordlandwehr@kde.org>
5     SPDX-License-Identifier: GPL-2.0-only
6 */
7 
8 
9 #include "dotgrammarhelper.h"
10 #include "dotgrammar.h"
11 #include "graphdocument.h"
12 #include "node.h"
13 #include "edge.h"
14 #include "logging_p.h"
15 
16 #include <QFile>
17 
18 extern DotParser::DotGraphParsingHelper* phelper;
19 
20 using namespace GraphTheory;
21 
22 namespace DotParser
23 {
24 
DotGraphParsingHelper()25 DotGraphParsingHelper::DotGraphParsingHelper():
26     attributeId(),
27     valid(),
28     attributed(),
29     unprocessedAttributes(),
30     graphAttributes(),
31     nodeAttributes(),
32     edgeAttributes(),
33     graphAttributeStack(),
34     nodeAttributeStack(),
35     edgeAttributeStack(),
36     edgebounds(),
37     currentNode(),
38     currentEdge(),
39     nodeMap()
40 {
41 }
42 
setObjectAttributes(QObject * graphElement,const AttributesMap & attributes)43 void DotGraphParsingHelper::setObjectAttributes(QObject *graphElement, const AttributesMap &attributes)
44 {
45     AttributesMap::const_iterator iter;
46     iter = attributes.constBegin();
47     for (; iter != attributes.constEnd(); ++iter) {
48         if (iter.key() == "label" && strcmp(graphElement->metaObject()->className(), "Edge") == 0) {
49             QString label = iter.value();
50             label.replace("\\n", "\n");
51             graphElement->setProperty("name", label);
52         } else {
53             graphElement->setProperty(iter.key().toUtf8(), iter.value());
54         }
55     }
56 }
57 
setDocumentAttributes()58 void DotGraphParsingHelper::setDocumentAttributes()
59 {
60     setObjectAttributes(document.data(), graphAttributes);
61 }
62 
setSubGraphAttributes()63 void DotGraphParsingHelper::setSubGraphAttributes()
64 {
65     // not implemented
66 }
67 
setNodeAttributes()68 void DotGraphParsingHelper::setNodeAttributes()
69 {
70     if (!currentNode) {
71         return;
72     }
73     AttributesMap::ConstIterator iter;
74     iter = nodeAttributes.constBegin();
75     for (; iter != nodeAttributes.constEnd(); ++iter) {
76         if (!currentNode->dynamicProperties().contains(iter.key())) {
77             currentNode->type()->addDynamicProperty(iter.key());
78         }
79         QString key = iter.key(); // do not overwrite labels
80         if (key == "name") {
81             key = "dot_name";
82         }
83         currentNode->setDynamicProperty(key, iter.value());
84     }
85 }
86 
setEdgeAttributes()87 void DotGraphParsingHelper::setEdgeAttributes()
88 {
89     if (!currentEdge) {
90         return;
91     }
92     AttributesMap::ConstIterator iter;
93     iter = edgeAttributes.constBegin();
94     for (; iter != edgeAttributes.constEnd(); ++iter) {
95         if (!currentEdge->dynamicProperties().contains(iter.key())) {
96             currentEdge->type()->addDynamicProperty(iter.key());
97         }
98         currentEdge->setDynamicProperty(iter.key(), iter.value());
99     }
100 }
101 
applyAttributedList()102 void DotGraphParsingHelper::applyAttributedList()
103 {
104     if (attributed == "graph") {
105         if (unprocessedAttributes.find("bb") != unprocessedAttributes.end()) {
106             std::vector< int > v;
107             parseIntegers(unprocessedAttributes["bb"].toStdString().c_str(), v);
108 //             if (v.size() >= 4) {
109 //                 qCDebug(GRAPHTHEORY_FILEFORMAT) << "setting width and height to " << v[2] << v[3];
110 //             }
111         }
112         AttributesMap::const_iterator it, it_end;
113         it = unprocessedAttributes.constBegin();
114         it_end = unprocessedAttributes.constEnd();
115         for (; it != it_end; it++) {
116             graphAttributes[it.key()] = it.value();
117         }
118     } else if (attributed == "node") {
119         AttributesMap::const_iterator it, it_end;
120         it = unprocessedAttributes.constBegin();
121         it_end = unprocessedAttributes.constEnd();
122         for (; it != it_end; it++) {
123             nodeAttributes[it.key()] = it.value();
124         }
125     } else if (attributed == "edge") {
126         AttributesMap::const_iterator it, it_end;
127         it = unprocessedAttributes.constBegin();
128         it_end = unprocessedAttributes.constEnd();
129         for (; it != it_end; it++) {
130             edgeAttributes[it.key()] = it.value();
131         }
132     }
133     unprocessedAttributes.clear();
134 }
135 
createNode(const QString & name)136 void DotGraphParsingHelper::createNode(const QString &name)
137 {
138     edgebounds.clear(); //TODO explain meaning of this
139 
140     if (nodeMap.contains(name)) {
141         qCCritical(GRAPHTHEORY_FILEFORMAT) << "Omitting data element, identifying label is already used: "<< name;
142         return;
143     }
144     currentNode = GraphTheory::Node::create(document);
145     if (!currentNode->type()->dynamicProperties().contains("name")) {
146         currentNode->type()->addDynamicProperty("name");
147     }
148     currentNode->setDynamicProperty("name", name);
149     nodeMap.insert(name, currentNode);
150 }
151 
createSubGraph()152 void DotGraphParsingHelper::createSubGraph()
153 {
154     // currently not implemented
155 }
156 
setSubGraphId(const QString & identifier)157 void DotGraphParsingHelper::setSubGraphId(const QString &identifier)
158 {
159     Q_UNUSED(identifier);
160     // currently not implemented
161 }
162 
leaveSubGraph()163 void DotGraphParsingHelper::leaveSubGraph()
164 {
165     // currently not implemented
166 }
167 
createEdge()168 void DotGraphParsingHelper::createEdge()
169 {
170     QString fromId, toId;
171 
172     if (edgebounds.isEmpty()) {
173         return;
174     }
175     fromId = edgebounds.first();
176     edgebounds.removeFirst();
177     while (!edgebounds.isEmpty()) {
178         toId = edgebounds.first();
179         edgebounds.removeFirst();
180 
181         // if necessary create from id
182         if (!nodeMap.contains(fromId)) {
183             NodePtr from = Node::create(document);
184             from->setDynamicProperty("name", fromId);
185             if (from->dynamicProperties().contains("name")) {
186                 from->type()->addDynamicProperty("name");
187             }
188             nodeMap.insert(fromId, from);
189             currentNode = from;
190             setNodeAttributes();
191         }
192         NodePtr from = nodeMap[fromId];
193 
194         // if necessary create to node
195         if (!nodeMap.contains(toId)) {
196             NodePtr to = Node::create(document);
197             if (to->dynamicProperties().contains("name")) {
198                 to->type()->addDynamicProperty("name");
199             }
200             to->setDynamicProperty("name", toId);
201             nodeMap.insert(toId, to);
202             currentNode = to;
203             setNodeAttributes();
204         }
205         NodePtr to = nodeMap[toId];
206 
207         currentEdge = Edge::create(from, to);
208 //         qCDebug(GRAPHTHEORY_FILEFORMAT) << "Creating new edge: " << from->identifier() << " -> " << to->identifier();
209         setEdgeAttributes();
210 
211         fromId = toId;
212     }
213     edgebounds.clear();
214 }
215 
216 }
217