From 77960e146a277f02487c70c5278c7081eaa5dbf1 Mon Sep 17 00:00:00 2001 From: Denes Matetelki Date: Mon, 4 Jul 2011 21:14:10 +0200 Subject: [PATCH] add/remove edge are undo commands --- include/commands.h | 55 ++++++++++++++++++++++ include/graphlogic.h | 16 ++++--- src/commands.cpp | 108 +++++++++++++++++++++++++++++++++++++++++++ src/graphlogic.cpp | 45 ++---------------- 4 files changed, 178 insertions(+), 46 deletions(-) diff --git a/include/commands.h b/include/commands.h index 705011e..59ce39a 100644 --- a/include/commands.h +++ b/include/commands.h @@ -9,6 +9,8 @@ class GraphLogic; +// exceptions: + class NoActiveNodeException : public std::exception { public: @@ -27,7 +29,20 @@ public: const char* what() const throw(); }; +class BaseNodeCannotBeEdgeTargetException : public std::exception +{ +public: + const char* what() const throw(); +}; + +class EdgeExistsBetweenNodesException : public std::exception +{ +public: + const char* what() const throw(); +}; + +// commands: class InsertNodeCommand : public QUndoCommand { @@ -70,4 +85,44 @@ private: QList m_edgeList; }; +class AddEdgeCommand : public QUndoCommand +{ + +public: + + AddEdgeCommand(GraphLogic *graphLogic, Node *source, Node *destinaion); + + void undo(); + void redo(); + +private: + + GraphLogic *m_graphLogic; + + Node *m_activeNode; + Node *m_source; + Node *m_destination; + Edge *m_edge; +}; + +class RemoveEdgeCommand : public QUndoCommand +{ + +public: + + RemoveEdgeCommand(GraphLogic *graphLogic, Node *source, Node *destinaion); + + void undo(); + void redo(); + +private: + + GraphLogic *m_graphLogic; + + Node *m_activeNode; + Node *m_source; + Node *m_destination; + Edge *m_edge; +}; + #endif // COMMANDS_H diff --git a/include/graphlogic.h b/include/graphlogic.h index 541847c..5acd7d8 100644 --- a/include/graphlogic.h +++ b/include/graphlogic.h @@ -13,6 +13,8 @@ class GraphWidget; class InsertNodeCommand; class RemoveNodeCommand; +class AddEdgeCommand; +class RemoveEdgeCommand; class GraphLogic : public QObject { @@ -34,15 +36,15 @@ public: public slots: // commands from toolbars: - void insertNode(); - void removeNode(); /// @todo Rewrite as an undo action + void insertNode(); // undo command + void removeNode(); // undo command void nodeEdited(); /// @todo Rewrite as an undo action void scaleUp(); /// @todo Rewrite as an undo action void scaleDown(); /// @todo Rewrite as an undo action void nodeColor(); void nodeTextColor(); - void addEdge(); /// @todo Rewrite as an undo action - void removeEdge(); /// @todo Rewrite as an undo action + void addEdge(); + void removeEdge(); void hintMode(); void insertPicture(const QString &picture); /// @todo Rewrite as an undo action @@ -78,8 +80,8 @@ private: // functions on the edges QList allEdges() const; - void addEdge(Node *source, Node *destination); - void removeEdge(Node* source, Node *destination); + void addEdge(Node *source, Node *destination); // undo command + void removeEdge(Node* source, Node *destination); // undo command // hint mode's nodenumber handling functions void showNodeNumbers(); @@ -104,6 +106,8 @@ private: friend class InsertNodeCommand; friend class RemoveNodeCommand; + friend class AddEdgeCommand; + friend class RemoveEdgeCommand; }; #endif // GRAPHLOGIC_H diff --git a/src/commands.cpp b/src/commands.cpp index 99259c6..d73960b 100644 --- a/src/commands.cpp +++ b/src/commands.cpp @@ -23,6 +23,17 @@ const char* CannotDeleteBaseNodeException::what() const throw() return QObject::tr("Base node cannot be deleted.").toStdString().c_str(); } +const char* BaseNodeCannotBeEdgeTargetException::what() const throw() +{ + return QObject::tr("Base node cannot be a target.").toStdString().c_str(); +} + +const char* EdgeExistsBetweenNodesException::what() const throw() +{ + return QObject::tr("There is already an edge between these two nodes."). + toStdString().c_str(); +} + InsertNodeCommand::InsertNodeCommand(GraphLogic *graphLogic) : m_graphLogic(graphLogic) @@ -191,3 +202,100 @@ void RemoveNodeCommand::redo() if (m_graphLogic->m_showingNodeNumbers) m_graphLogic->showNodeNumbers(); } + +AddEdgeCommand::AddEdgeCommand(GraphLogic *graphLogic, Node *source, Node *destinaion) + : m_graphLogic(graphLogic) + , m_activeNode(m_graphLogic->m_activeNode) + , m_source(source) + , m_destination(destinaion) +{ + if (!m_activeNode) + throw NoActiveNodeException(); + + if (m_destination == m_graphLogic->m_nodeList.first()) + throw BaseNodeCannotBeEdgeTargetException(); + + + if (m_source->isConnected(m_destination)) + throw EdgeExistsBetweenNodesException(); + + setText(QObject::tr("Edge added between \"").append( + m_source->toPlainText()).append( + QObject::tr("\" and \"").append( + m_destination->toPlainText()).append("\""))); + + + // aviod the graph beeing acyclic. (ok, Nodes having multiple parents) + bool sec(false); + if (!m_destination->edgesToThis().empty()) + { + emit m_graphLogic->notification( + QObject::tr("The graph is acyclic, edge added as secondary edge.")); + sec = true; + } + + m_edge = new Edge(m_source, m_destination); + m_edge->setColor(m_destination->color()); + m_edge->setWidth(m_destination->scale()*2 + 1); + + // The Edge is secondary, because the Node already has a parent + // (it is already a destination of another Edge) + m_edge->setSecondary(sec); +} + +void AddEdgeCommand::undo() +{ + m_source->removeEdge(m_edge); + m_destination->removeEdge(m_edge); + m_graphLogic->m_graphWidget->scene()->removeItem(m_edge); + + m_graphLogic->setActiveNode(m_activeNode); + + emit m_graphLogic->contentChanged(false); +} + +void AddEdgeCommand::redo() +{ + m_source->addEdge(m_edge, true); + m_destination->addEdge(m_edge, false); + + m_graphLogic->m_graphWidget->scene()->addItem(m_edge); + + m_graphLogic->setActiveNode(m_destination); + emit m_graphLogic->contentChanged(); +} + +RemoveEdgeCommand::RemoveEdgeCommand(GraphLogic *graphLogic, Node *source, Node *destinaion) + : m_graphLogic(graphLogic) + , m_activeNode(m_graphLogic->m_activeNode) + , m_source(source) + , m_destination(destinaion) + , m_edge(source->edgeTo(destinaion)) +{ + setText(QObject::tr("Edge releted between \"").append( + m_source->toPlainText()).append( + QObject::tr("\" and \"").append( + m_destination->toPlainText()).append("\""))); +} + +void RemoveEdgeCommand::undo() +{ + m_source->addEdge(m_edge, true); + m_destination->addEdge(m_edge, false); + + m_graphLogic->m_graphWidget->scene()->addItem(m_edge); + + m_graphLogic->setActiveNode(m_destination); + emit m_graphLogic->contentChanged(false); +} + +void RemoveEdgeCommand::redo() +{ + m_source->removeEdge(m_edge); + m_destination->removeEdge(m_edge); + m_graphLogic->m_graphWidget->scene()->removeItem(m_edge); + + m_graphLogic->setActiveNode(m_activeNode); + + emit m_graphLogic->contentChanged(); +} diff --git a/src/graphlogic.cpp b/src/graphlogic.cpp index 985a1b3..a396ac9 100644 --- a/src/graphlogic.cpp +++ b/src/graphlogic.cpp @@ -699,51 +699,16 @@ QList GraphLogic::allEdges() const void GraphLogic::addEdge(Node *source, Node *destination) { - if (!m_activeNode) + try { - emit notification(tr("No active node.")); - return; + QUndoCommand *addEdgeCommand = new AddEdgeCommand(this, source, destination); + m_undoStack->push(addEdgeCommand); } - - if (destination == m_nodeList.first()) + catch (std::exception &e) { - setActiveNode(destination); - emit notification( - tr("Root element cannot be an edge target.")); + emit notification(e.what()); return; } - - if (source->isConnected(destination)) - { - setActiveNode(destination); - emit notification( - tr("There is already an edge between these two nodes.")); - } - else - { - // aviod the graph beeing acyclic. (ok, Nodes having multiple parents) - bool sec(false); - if (!destination->edgesToThis().empty()) - { - emit notification( - tr("The graph is acyclic, edge added as secondary edge.")); - sec = true; - } - Edge *edge = new Edge(source, destination); - source->addEdge(edge, true); - destination->addEdge(edge, false); - - edge->setColor(destination->color()); - edge->setWidth(destination->scale()*2 + 1); - - // The Edge is secondary, because the Node already has a parent - // (it is already a destination of another Edge) - edge->setSecondary(sec); - m_graphWidget->scene()->addItem(edge); - - setActiveNode(destination); - emit contentChanged(); - } } void GraphLogic::removeEdge(Node *source, Node *destination)