299 lines
8.0 KiB
C++
299 lines
8.0 KiB
C++
#include "basicGraphicsScene.h"
|
|
|
|
#include "abstractNodeGeometry.h"
|
|
#include "connectionGraphicsObject.h"
|
|
#include "connectionIdUtils.h"
|
|
#include "defaultHorizontalNodeGeometry.h"
|
|
#include "defaultNodePainter.h"
|
|
#include "defaultVerticalNodeGeometry.h"
|
|
//#include "GraphicsView.hpp"
|
|
#include "nodeGraphicsObject.h"
|
|
|
|
#include <QUndoStack>
|
|
|
|
#include <QtWidgets/QFileDialog>
|
|
#include <QtWidgets/QGraphicsSceneMoveEvent>
|
|
|
|
#include <QtCore/QBuffer>
|
|
#include <QtCore/QByteArray>
|
|
#include <QtCore/QDataStream>
|
|
#include <QtCore/QFile>
|
|
#include <QtCore/QJsonArray>
|
|
#include <QtCore/QJsonDocument>
|
|
#include <QtCore/QJsonObject>
|
|
#include <QtCore/QtGlobal>
|
|
|
|
|
|
BasicGraphicsScene::BasicGraphicsScene(AbstractGraphModel &graphModel, QObject *parent)
|
|
: QGraphicsScene(parent)
|
|
, _graphModel(graphModel)
|
|
, _nodeGeometry(QSharedPointer<DefaultHorizontalNodeGeometry>(new DefaultHorizontalNodeGeometry(_graphModel)))
|
|
, _nodePainter(QSharedPointer<DefaultNodePainter>())
|
|
, _nodeDrag(false)
|
|
, _undoStack(new QUndoStack(this))
|
|
, _orientation(Qt::Horizontal)
|
|
{
|
|
setItemIndexMethod(QGraphicsScene::NoIndex);
|
|
|
|
connect(&_graphModel,
|
|
&AbstractGraphModel::connectionCreated,
|
|
this,
|
|
&BasicGraphicsScene::onConnectionCreated);
|
|
|
|
connect(&_graphModel,
|
|
&AbstractGraphModel::connectionDeleted,
|
|
this,
|
|
&BasicGraphicsScene::onConnectionDeleted);
|
|
|
|
connect(&_graphModel,
|
|
&AbstractGraphModel::nodeCreated,
|
|
this,
|
|
&BasicGraphicsScene::onNodeCreated);
|
|
|
|
connect(&_graphModel,
|
|
&AbstractGraphModel::nodeDeleted,
|
|
this,
|
|
&BasicGraphicsScene::onNodeDeleted);
|
|
|
|
connect(&_graphModel,
|
|
&AbstractGraphModel::nodePositionUpdated,
|
|
this,
|
|
&BasicGraphicsScene::onNodePositionUpdated);
|
|
|
|
connect(&_graphModel,
|
|
&AbstractGraphModel::nodeUpdated,
|
|
this,
|
|
&BasicGraphicsScene::onNodeUpdated);
|
|
|
|
connect(this, &BasicGraphicsScene::nodeClicked, this, &BasicGraphicsScene::onNodeClicked);
|
|
|
|
connect(&_graphModel, &AbstractGraphModel::modelReset, this, &BasicGraphicsScene::onModelReset);
|
|
|
|
traverseGraphAndPopulateGraphicsObjects();
|
|
}
|
|
|
|
BasicGraphicsScene::~BasicGraphicsScene() = default;
|
|
|
|
AbstractGraphModel const &BasicGraphicsScene::graphModel() const
|
|
{
|
|
return _graphModel;
|
|
}
|
|
|
|
AbstractGraphModel &BasicGraphicsScene::graphModel()
|
|
{
|
|
return _graphModel;
|
|
}
|
|
|
|
AbstractNodeGeometry &BasicGraphicsScene::nodeGeometry()
|
|
{
|
|
return *_nodeGeometry;
|
|
}
|
|
|
|
AbstractNodePainter &BasicGraphicsScene::nodePainter()
|
|
{
|
|
return *_nodePainter;
|
|
}
|
|
|
|
void BasicGraphicsScene::setNodePainter(QSharedPointer<AbstractNodePainter> newPainter)
|
|
{
|
|
_nodePainter = std::move(newPainter);
|
|
}
|
|
|
|
QUndoStack &BasicGraphicsScene::undoStack()
|
|
{
|
|
return *_undoStack;
|
|
}
|
|
|
|
QSharedPointer<ConnectionGraphicsObject> const &BasicGraphicsScene::makeDraftConnection(
|
|
ConnectionId const incompleteConnectionId)
|
|
{
|
|
_draftConnection = QSharedPointer<ConnectionGraphicsObject>(new ConnectionGraphicsObject(*this, incompleteConnectionId));
|
|
|
|
_draftConnection->grabMouse();
|
|
|
|
return _draftConnection;
|
|
}
|
|
|
|
void BasicGraphicsScene::resetDraftConnection()
|
|
{
|
|
_draftConnection.reset();
|
|
}
|
|
|
|
void BasicGraphicsScene::clearScene()
|
|
{
|
|
auto const &allNodeIds = graphModel().allNodeIds();
|
|
|
|
for (auto nodeId : allNodeIds) {
|
|
graphModel().deleteNode(nodeId);
|
|
}
|
|
}
|
|
|
|
NodeGraphicsObject *BasicGraphicsScene::nodeGraphicsObject(NodeId nodeId)
|
|
{
|
|
NodeGraphicsObject *ngo = nullptr;
|
|
auto it = _nodeGraphicsObjects.find(nodeId);
|
|
if (it != _nodeGraphicsObjects.end()) {
|
|
ngo = it->data();
|
|
}
|
|
|
|
return ngo;
|
|
}
|
|
|
|
ConnectionGraphicsObject *BasicGraphicsScene::connectionGraphicsObject(ConnectionId connectionId)
|
|
{
|
|
ConnectionGraphicsObject *cgo = nullptr;
|
|
auto it = _connectionGraphicsObjects.find(connectionId);
|
|
if (it != _connectionGraphicsObjects.end()) {
|
|
cgo = it->data();
|
|
}
|
|
|
|
return cgo;
|
|
}
|
|
|
|
void BasicGraphicsScene::setOrientation(Qt::Orientation const orientation)
|
|
{
|
|
if (_orientation != orientation) {
|
|
_orientation = orientation;
|
|
|
|
switch (_orientation) {
|
|
case Qt::Horizontal:
|
|
_nodeGeometry = QSharedPointer<DefaultHorizontalNodeGeometry>(new DefaultHorizontalNodeGeometry(_graphModel));
|
|
break;
|
|
|
|
case Qt::Vertical:
|
|
_nodeGeometry = QSharedPointer<DefaultVerticalNodeGeometry>(new DefaultVerticalNodeGeometry(_graphModel));
|
|
break;
|
|
}
|
|
|
|
onModelReset();
|
|
}
|
|
}
|
|
|
|
QMenu *BasicGraphicsScene::createSceneMenu(QPointF const scenePos)
|
|
{
|
|
Q_UNUSED(scenePos);
|
|
return nullptr;
|
|
}
|
|
|
|
void BasicGraphicsScene::traverseGraphAndPopulateGraphicsObjects()
|
|
{
|
|
auto allNodeIds = _graphModel.allNodeIds();
|
|
|
|
// First create all the nodes.
|
|
for (NodeId const nodeId : allNodeIds) {
|
|
_nodeGraphicsObjects[nodeId] = QSharedPointer<NodeGraphicsObject>(new NodeGraphicsObject(*this, nodeId));
|
|
}
|
|
|
|
// Then for each node check output connections and insert them.
|
|
for (NodeId const nodeId : allNodeIds) {
|
|
auto nOutPorts = _graphModel.nodeData<PortCount>(nodeId, NodeRole::OutPortCount);
|
|
|
|
for (PortIndex index = 0; index < nOutPorts; ++index) {
|
|
auto const &outConnectionIds = _graphModel.connections(nodeId, PortType::Out, index);
|
|
|
|
for (auto cid : outConnectionIds) {
|
|
_connectionGraphicsObjects[cid] = QSharedPointer<ConnectionGraphicsObject>(new ConnectionGraphicsObject(*this,cid));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void BasicGraphicsScene::updateAttachedNodes(ConnectionId const connectionId,
|
|
PortType const portType)
|
|
{
|
|
auto node = nodeGraphicsObject(getNodeId(portType, connectionId));
|
|
|
|
if (node) {
|
|
node->update();
|
|
}
|
|
}
|
|
|
|
void BasicGraphicsScene::onConnectionDeleted(ConnectionId const connectionId)
|
|
{
|
|
auto it = _connectionGraphicsObjects.find(connectionId);
|
|
if (it != _connectionGraphicsObjects.end()) {
|
|
_connectionGraphicsObjects.erase(it);
|
|
}
|
|
|
|
// TODO: do we need it?
|
|
if (_draftConnection && _draftConnection->connectionId() == connectionId) {
|
|
_draftConnection.reset();
|
|
}
|
|
|
|
updateAttachedNodes(connectionId, PortType::Out);
|
|
updateAttachedNodes(connectionId, PortType::In);
|
|
|
|
Q_EMIT modified(this);
|
|
}
|
|
|
|
void BasicGraphicsScene::onConnectionCreated(ConnectionId const connectionId)
|
|
{
|
|
_connectionGraphicsObjects[connectionId]
|
|
= QSharedPointer<ConnectionGraphicsObject>(new ConnectionGraphicsObject(*this, connectionId));
|
|
|
|
updateAttachedNodes(connectionId, PortType::Out);
|
|
updateAttachedNodes(connectionId, PortType::In);
|
|
|
|
Q_EMIT modified(this);
|
|
}
|
|
|
|
void BasicGraphicsScene::onNodeDeleted(NodeId const nodeId)
|
|
{
|
|
auto it = _nodeGraphicsObjects.find(nodeId);
|
|
if (it != _nodeGraphicsObjects.end()) {
|
|
_nodeGraphicsObjects.erase(it);
|
|
|
|
Q_EMIT modified(this);
|
|
}
|
|
}
|
|
|
|
void BasicGraphicsScene::onNodeCreated(NodeId const nodeId)
|
|
{
|
|
_nodeGraphicsObjects[nodeId] = QSharedPointer<NodeGraphicsObject>(new NodeGraphicsObject(*this, nodeId));
|
|
|
|
Q_EMIT modified(this);
|
|
}
|
|
|
|
void BasicGraphicsScene::onNodePositionUpdated(NodeId const nodeId)
|
|
{
|
|
auto node = nodeGraphicsObject(nodeId);
|
|
if (node) {
|
|
node->setPos(_graphModel.nodeData(nodeId, NodeRole::Position).value<QPointF>());
|
|
node->update();
|
|
_nodeDrag = true;
|
|
}
|
|
}
|
|
|
|
void BasicGraphicsScene::onNodeUpdated(NodeId const nodeId)
|
|
{
|
|
auto node = nodeGraphicsObject(nodeId);
|
|
|
|
if (node) {
|
|
node->setGeometryChanged();
|
|
|
|
_nodeGeometry->recomputeSize(nodeId);
|
|
|
|
node->update();
|
|
node->moveConnections();
|
|
}
|
|
}
|
|
|
|
void BasicGraphicsScene::onNodeClicked(NodeId const nodeId)
|
|
{
|
|
if (_nodeDrag) {
|
|
Q_EMIT nodeMoved(nodeId, _graphModel.nodeData(nodeId, NodeRole::Position).value<QPointF>());
|
|
Q_EMIT modified(this);
|
|
}
|
|
_nodeDrag = false;
|
|
}
|
|
|
|
void BasicGraphicsScene::onModelReset()
|
|
{
|
|
_connectionGraphicsObjects.clear();
|
|
_nodeGraphicsObjects.clear();
|
|
|
|
clear();
|
|
|
|
traverseGraphAndPopulateGraphicsObjects();
|
|
}
|