GCC Code Coverage Report
Directory: QGVCore/ Exec Total Coverage
File: QGVCore/QGVScene.cpp Lines: 0 163 0.0 %
Date: 2024-03-31 10:30:44 Branches: 0 86 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
}