GCC Code Coverage Report


Directory: QGVCore/
File: QGVCore/QGVScene.cpp
Date: 2024-12-03 11:07:38
Exec Total Coverage
Lines: 0 162 0.0%
Branches: 0 62 0.0%

Line Branch Exec Source
1 /***************************************************************
2 QGVCore
3 Copyright (c) 2014, Bergont Nicolas, All rights reserved.
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 3.0 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library.
17 ***************************************************************/
18 #include "QGVScene.h"
19 // The following include allows the automoc to detect, that it must moc this
20 // class
21 #include <QGVCore.h>
22 #include <QGVEdge.h>
23 #include <QGVEdgePrivate.h>
24 #include <QGVGraphPrivate.h>
25 #include <QGVGvcPrivate.h>
26 #include <QGVNode.h>
27 #include <QGVNodePrivate.h>
28 #include <QGVSubGraph.h>
29
30 #include <QDebug>
31
32 #include "moc_QGVScene.cpp"
33
34 QGVScene::QGVScene(const QString &name, QObject *parent)
35 : QGraphicsScene(parent), _label(NULL) {
36 _context = new QGVGvcPrivate(gvContext());
37 _graph =
38 new QGVGraphPrivate(agopen(name.toLocal8Bit().data(), Agdirected, NULL));
39 // setGraphAttribute("fontname", QFont().family());
40 }
41
42 QGVScene::~QGVScene() {
43 gvFreeLayout(_context->context(), _graph->graph());
44 agclose(_graph->graph());
45 gvFreeContext(_context->context());
46 delete _graph;
47 delete _context;
48 }
49
50 void QGVScene::setGraphAttribute(const QString &name, const QString &value) {
51 agattr(_graph->graph(), AGRAPH, name.toLocal8Bit().data(),
52 value.toLocal8Bit().data());
53 }
54
55 void QGVScene::setNodeAttribute(const QString &name, const QString &value) {
56 agattr(_graph->graph(), AGNODE, name.toLocal8Bit().data(),
57 value.toLocal8Bit().data());
58 }
59
60 void QGVScene::setEdgeAttribute(const QString &name, const QString &value) {
61 agattr(_graph->graph(), AGEDGE, name.toLocal8Bit().data(),
62 value.toLocal8Bit().data());
63 }
64
65 QGVNode *QGVScene::addNode(const QString &label) {
66 Agnode_t *node = agnode(_graph->graph(), NULL, true);
67 if (node == NULL) {
68 qWarning() << "Invalid node :" << label;
69 return 0;
70 }
71 QGVNode *item = new QGVNode(new QGVNodePrivate(node), this);
72 item->setLabel(label);
73 addItem(item);
74 _nodes.append(item);
75 return item;
76 }
77
78 QGVEdge *QGVScene::addEdge(QGVNode *source, QGVNode *target,
79 const QString &label) {
80 Agedge_t *edge = agedge(_graph->graph(), source->_node->node(),
81 target->_node->node(), NULL, true);
82 if (edge == NULL) {
83 qWarning() << "Invalid egde :" << label;
84 return 0;
85 }
86
87 QGVEdge *item = new QGVEdge(new QGVEdgePrivate(edge), this);
88 item->setLabel(label);
89 addItem(item);
90 _edges.append(item);
91 return item;
92 }
93
94 QGVSubGraph *QGVScene::addSubGraph(const QString &name, bool cluster) {
95 Agraph_t *sgraph;
96 if (cluster)
97 sgraph =
98 agsubg(_graph->graph(), ("cluster_" + name).toLocal8Bit().data(), true);
99 else
100 sgraph = agsubg(_graph->graph(), name.toLocal8Bit().data(), true);
101
102 if (sgraph == NULL) {
103 qWarning() << "Invalid subGraph :" << name;
104 return 0;
105 }
106
107 QGVSubGraph *item = new QGVSubGraph(new QGVGraphPrivate(sgraph), this);
108 addItem(item);
109 _subGraphs.append(item);
110 return item;
111 }
112
113 void QGVScene::setRootNode(QGVNode *node) {
114 Q_ASSERT(_nodes.contains(node));
115 char root[] = "root";
116 agset(_graph->graph(), root, node->label().toLocal8Bit().data());
117 }
118
119 void QGVScene::setNodePositionAttribute() {
120 foreach (QGVNode *node, _nodes) {
121 node->setAttribute("pos",
122 node->posToAttributeString().toLocal8Bit().constData());
123 node->setAttribute("pin", "true");
124 }
125 }
126
127 void QGVScene::loadLayout(const QString &text) {
128 _graph->setGraph(QGVCore::agmemread2(text.toLocal8Bit().constData()));
129
130 if (gvLayout(_context->context(), _graph->graph(), "dot") != 0) {
131 qCritical() << "Layout render error" << agerrors()
132 << QString::fromLocal8Bit(aglasterr());
133 return;
134 }
135
136 // Debug output
137 // gvRenderFilename(_context->context(), _graph->graph(), "png", "debug.png");
138
139 // Read nodes and edges
140 for (Agnode_t *node = agfstnode(_graph->graph()); node != NULL;
141 node = agnxtnode(_graph->graph(), node)) {
142 QGVNode *inode = new QGVNode(new QGVNodePrivate(node), this);
143 inode->updateLayout();
144 addItem(inode);
145 _nodes.append(inode);
146 for (Agedge_t *edge = agfstout(_graph->graph(), node); edge != NULL;
147 edge = agnxtout(_graph->graph(), edge)) {
148 QGVEdge *iedge = new QGVEdge(new QGVEdgePrivate(edge), this);
149 iedge->updateLayout();
150 addItem(iedge);
151 _edges.append(iedge);
152 }
153 }
154 update();
155 }
156
157 void QGVScene::applyLayout(const QString &algorithm) {
158 if (gvLayout(_context->context(), _graph->graph(),
159 algorithm.toLocal8Bit().data()) != 0) {
160 /*
161 * Si plantage ici :
162 * - Verifier que les dll sont dans le repertoire d'execution
163 * - Verifie que le fichier "configN" est dans le repertoire d'execution !
164 */
165 qCritical() << "Layout render error" << agerrors()
166 << QString::fromLocal8Bit(aglasterr());
167 return;
168 }
169
170 // Debug output
171 // gvRenderFilename(_context->context(), _graph->graph(), "canon",
172 // "debug.dot"); gvRenderFilename(_context->context(), _graph->graph(), "png",
173 // "debug.png");
174
175 // Update items layout
176 foreach (QGVNode *node, _nodes) node->updateLayout();
177
178 foreach (QGVEdge *edge, _edges) edge->updateLayout();
179
180 foreach (QGVSubGraph *sgraph, _subGraphs) sgraph->updateLayout();
181
182 // Graph label
183 textlabel_t *xlabel = GD_label(_graph->graph());
184 if (xlabel) {
185 if (_label == NULL)
186 _label = addText(xlabel->text);
187 else
188 _label->setPlainText(xlabel->text);
189 _label->setPos(QGVCore::centerToOrigin(
190 QGVCore::toPoint(xlabel->pos, QGVCore::graphHeight(_graph->graph())),
191 xlabel->dimen.x, -4));
192 }
193
194 update();
195 }
196
197 void QGVScene::render(const QString &algorithm) {
198 gvRender(_context->context(), _graph->graph(), algorithm.toLocal8Bit().data(),
199 NULL);
200 }
201
202 void QGVScene::render(const QString algorithm, const QString filename) {
203 gvRenderFilename(_context->context(), _graph->graph(),
204 algorithm.toLocal8Bit().data(),
205 filename.toLocal8Bit().data());
206 }
207
208 void QGVScene::freeLayout() {
209 gvFreeLayout(_context->context(), _graph->graph());
210 }
211
212 void QGVScene::clear() {
213 _nodes.clear();
214 _edges.clear();
215 _subGraphs.clear();
216 QGraphicsScene::clear();
217 _label = NULL;
218 _graph->setGraph(agopen("graph", Agdirected, NULL));
219 }
220
221 #include <QGraphicsSceneContextMenuEvent>
222 void QGVScene::contextMenuEvent(
223 QGraphicsSceneContextMenuEvent *contextMenuEvent) {
224 QGraphicsItem *item = itemAt(contextMenuEvent->scenePos(), QTransform());
225 if (item) {
226 item->setSelected(true);
227 if (item->type() == QGVNode::Type)
228 emit nodeContextMenu(qgraphicsitem_cast<QGVNode *>(item));
229 else if (item->type() == QGVEdge::Type)
230 emit edgeContextMenu(qgraphicsitem_cast<QGVEdge *>(item));
231 else if (item->type() == QGVSubGraph::Type)
232 emit subGraphContextMenu(qgraphicsitem_cast<QGVSubGraph *>(item));
233 else
234 emit graphContextMenuEvent();
235 }
236 QGraphicsScene::contextMenuEvent(contextMenuEvent);
237 }
238
239 void QGVScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *mouseEvent) {
240 QGraphicsItem *item = itemAt(mouseEvent->scenePos(), QTransform());
241 if (item) {
242 if (item->type() == QGVNode::Type)
243 emit nodeDoubleClick(qgraphicsitem_cast<QGVNode *>(item));
244 else if (item->type() == QGVEdge::Type)
245 emit edgeDoubleClick(qgraphicsitem_cast<QGVEdge *>(item));
246 else if (item->type() == QGVSubGraph::Type)
247 emit subGraphDoubleClick(qgraphicsitem_cast<QGVSubGraph *>(item));
248 }
249 QGraphicsScene::mouseDoubleClickEvent(mouseEvent);
250 }
251
252 void QGVScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) {
253 QGraphicsItem *item = itemAt(mouseEvent->scenePos(), QTransform());
254 if (item) {
255 if (item->type() == QGVNode::Type)
256 emit nodeMouseRelease(qgraphicsitem_cast<QGVNode *>(item));
257 }
258 QGraphicsScene::mouseReleaseEvent(mouseEvent);
259 }
260
261 #include <QPainter>
262 #include <QVarLengthArray>
263 void QGVScene::drawBackground(QPainter *painter, const QRectF &rect) {
264 const int gridSize = 25;
265
266 const qreal left = int(rect.left()) - (int(rect.left()) % gridSize);
267 const qreal top = int(rect.top()) - (int(rect.top()) % gridSize);
268
269 QVarLengthArray<QLineF, 100> lines;
270
271 for (qreal x = left; x < rect.right(); x += gridSize)
272 lines.append(QLineF(x, rect.top(), x, rect.bottom()));
273 for (qreal y = top; y < rect.bottom(); y += gridSize)
274 lines.append(QLineF(rect.left(), y, rect.right(), y));
275
276 painter->setRenderHint(QPainter::Antialiasing, false);
277
278 painter->setPen(QColor(Qt::lightGray).lighter(110));
279 painter->drawLines(lines.data(), lines.size());
280 painter->setPen(Qt::black);
281 // painter->drawRect(sceneRect());
282 }
283
284 bool QGVScene::writeGraph(const QString filename) {
285 if (_graph->graph() == NULL) return false;
286 FILE *pFile = fopen(filename.toLocal8Bit(), "w");
287 if (pFile != NULL) {
288 agwrite(_graph->graph(), pFile);
289 fclose(pFile);
290 return true;
291 } else {
292 perror("Could not open file to write the DOT graph");
293 return false;
294 }
295 }
296