Newer
Older
/***************************************************************
QGVCore
Copyright (c) 2014, Bergont Nicolas, All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
***************************************************************/
Joachim Langenbach
committed
// The following include allows the automoc to detect, that it must moc this class
#include "moc_QGVScene.cpp"
Joachim Langenbach
committed
#include <QGVNode.h>
#include <QGVEdge.h>
#include <QGVSubGraph.h>
#include <QGVCore.h>
#include <QGVGraphPrivate.h>
#include <QGVGvcPrivate.h>
#include <QGVEdgePrivate.h>
#include <QGVNodePrivate.h>
QGVScene::QGVScene(const QString &name, QObject *parent) : QGraphicsScene(parent)
{
Joachim Langenbach
committed
_context = new QGVGvcPrivate(gvContext());
_graph = new QGVGraphPrivate(agopen(name.toLocal8Bit().data(), Agdirected, NULL));
//setGraphAttribute("fontname", QFont().family());
}
QGVScene::~QGVScene()
{
Joachim Langenbach
committed
gvFreeLayout(_context->context(), _graph->graph());
agclose(_graph->graph());
gvFreeContext(_context->context());
delete _graph;
delete _context;
}
void QGVScene::setGraphAttribute(const QString &name, const QString &value)
{
Joachim Langenbach
committed
agattr(_graph->graph(), AGRAPH, name.toLocal8Bit().data(), value.toLocal8Bit().data());
}
void QGVScene::setNodeAttribute(const QString &name, const QString &value)
{
Joachim Langenbach
committed
agattr(_graph->graph(), AGNODE, name.toLocal8Bit().data(), value.toLocal8Bit().data());
}
void QGVScene::setEdgeAttribute(const QString &name, const QString &value)
{
Joachim Langenbach
committed
agattr(_graph->graph(), AGEDGE, name.toLocal8Bit().data(), value.toLocal8Bit().data());
Joachim Langenbach
committed
Agnode_t *node = agnode(_graph->graph(), NULL, TRUE);
if(node == NULL)
{
qWarning()<<"Invalid node :"<<label;
return 0;
}
Joachim Langenbach
committed
QGVNode *item = new QGVNode(new QGVNodePrivate(node), this);
item->setLabel(label);
addItem(item);
_nodes.append(item);
return item;
}
QGVEdge *QGVScene::addEdge(QGVNode *source, QGVNode *target, const QString &label)
{
Joachim Langenbach
committed
Agedge_t* edge = agedge(_graph->graph(), source->_node->node(), target->_node->node(), NULL, TRUE);
if(edge == NULL)
{
qWarning()<<"Invalid egde :"<<label;
return 0;
}
Joachim Langenbach
committed
QGVEdge *item = new QGVEdge(new QGVEdgePrivate(edge), this);
item->setLabel(label);
addItem(item);
_edges.append(item);
return item;
QGVSubGraph *QGVScene::addSubGraph(const QString &name, bool cluster)
Joachim Langenbach
committed
sgraph = agsubg(_graph->graph(), ("cluster_" + name).toLocal8Bit().data(), TRUE);
Joachim Langenbach
committed
sgraph = agsubg(_graph->graph(), name.toLocal8Bit().data(), TRUE);
if(sgraph == NULL)
{
qWarning()<<"Invalid subGraph :"<<name;
return 0;
}
Joachim Langenbach
committed
QGVSubGraph *item = new QGVSubGraph(new QGVGraphPrivate(sgraph), this);
addItem(item);
_subGraphs.append(item);
return item;
}
void QGVScene::setRootNode(QGVNode *node)
{
Q_ASSERT(_nodes.contains(node));
char root[] = "root";
agset(_graph->graph(), root, node->label().toLocal8Bit().data());
Joachim Langenbach
committed
_graph->setGraph(QGVCore::agmemread2(text.toLocal8Bit().constData()));
Joachim Langenbach
committed
if(gvLayout(_context->context(), _graph->graph(), "dot") != 0)
{
qCritical()<<"Layout render error"<<agerrors()<<QString::fromLocal8Bit(aglasterr());
return;
}
Joachim Langenbach
committed
//gvRenderFilename(_context->context(), _graph->graph(), "png", "debug.png");
Joachim Langenbach
committed
for (Agnode_t* node = agfstnode(_graph->graph()); node != NULL; node = agnxtnode(_graph->graph(), node))
Joachim Langenbach
committed
QGVNode *inode = new QGVNode(new QGVNodePrivate(node), this);
Joachim Langenbach
committed
for (Agedge_t* edge = agfstout(_graph->graph(), node); edge != NULL; edge = agnxtout(_graph->graph(), edge))
Joachim Langenbach
committed
QGVEdge *iedge = new QGVEdge(new QGVEdgePrivate(edge), this);
gvFreeLayout(_context->context(), _graph->graph());
if(gvLayout(_context->context(), _graph->graph(), "dot") != 0)
/*
* Si plantage ici :
* - Verifier que les dll sont dans le repertoire d'execution
* - Verifie que le fichier "configN" est dans le repertoire d'execution !
*/
qCritical()<<"Layout render error"<<agerrors()<<QString::fromLocal8Bit(aglasterr());
return;
}
//Debug output
Joachim Langenbach
committed
//gvRenderFilename(_context->context(), _graph->graph(), "canon", "debug.dot");
//gvRenderFilename(_context->context(), _graph->graph(), "png", "debug.png");
foreach(QGVNode* node, _nodes)
node->updateLayout();
foreach(QGVEdge* edge, _edges)
edge->updateLayout();
foreach(QGVSubGraph* sgraph, _subGraphs)
sgraph->updateLayout();
Joachim Langenbach
committed
textlabel_t *xlabel = GD_label(_graph->graph());
if(xlabel)
{
QGraphicsTextItem *item = addText(xlabel->text);
Joachim Langenbach
committed
item->setPos(QGVCore::centerToOrigin(QGVCore::toPoint(xlabel->pos, QGVCore::graphHeight(_graph->graph())), xlabel->dimen.x, -4));
Joachim Langenbach
committed
gvFreeLayout(_context->context(), _graph->graph());
_nodes.clear();
_edges.clear();
_subGraphs.clear();
QGraphicsScene::clear();
}
#include <QGraphicsSceneContextMenuEvent>
void QGVScene::contextMenuEvent(QGraphicsSceneContextMenuEvent *contextMenuEvent)
{
QGraphicsItem *item = itemAt(contextMenuEvent->scenePos(), QTransform());
if(item->type() == QGVNode::Type)
emit nodeContextMenu(qgraphicsitem_cast<QGVNode*>(item));
else if(item->type() == QGVEdge::Type)
emit edgeContextMenu(qgraphicsitem_cast<QGVEdge*>(item));
else if(item->type() == QGVSubGraph::Type)
emit subGraphContextMenu(qgraphicsitem_cast<QGVSubGraph*>(item));
else
emit graphContextMenuEvent();
}
QGraphicsScene::contextMenuEvent(contextMenuEvent);
}
void QGVScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
QGraphicsItem *item = itemAt(mouseEvent->scenePos(), QTransform());
if(item->type() == QGVNode::Type)
emit nodeDoubleClick(qgraphicsitem_cast<QGVNode*>(item));
else if(item->type() == QGVEdge::Type)
emit edgeDoubleClick(qgraphicsitem_cast<QGVEdge*>(item));
else if(item->type() == QGVSubGraph::Type)
emit subGraphDoubleClick(qgraphicsitem_cast<QGVSubGraph*>(item));
void QGVScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
QGraphicsItem *item = itemAt(mouseEvent->scenePos(), QTransform());
if(item)
{
if(item->type() == QGVNode::Type)
emit nodeMouseRelease (qgraphicsitem_cast<QGVNode*>(item));
}
QGraphicsScene::mouseReleaseEvent(mouseEvent);
}
#include <QVarLengthArray>
#include <QPainter>
void QGVScene::drawBackground(QPainter * painter, const QRectF & rect)
{
const int gridSize = 25;
const qreal left = int(rect.left()) - (int(rect.left()) % gridSize);
const qreal top = int(rect.top()) - (int(rect.top()) % gridSize);
QVarLengthArray<QLineF, 100> lines;
for (qreal x = left; x < rect.right(); x += gridSize)
lines.append(QLineF(x, rect.top(), x, rect.bottom()));
for (qreal y = top; y < rect.bottom(); y += gridSize)
lines.append(QLineF(rect.left(), y, rect.right(), y));
painter->setRenderHint(QPainter::Antialiasing, false);
painter->setPen(QColor(Qt::lightGray).lighter(110));
painter->drawLines(lines.data(), lines.size());
painter->setPen(Qt::black);
//painter->drawRect(sceneRect());
}