undo view and stack in place. Only the add node action can be undone jet.

master
Denes Matetelki 14 years ago
parent c5d93d6902
commit eb4ff4f43c

@ -0,0 +1,43 @@
#ifndef COMMANDS_H
#define COMMANDS_H
#include <QUndoCommand>
#include <exception>
#include "graphlogic.h"
class GraphLogic;
class NoActiveNodeException : public std::exception
{
public:
const char* what() const throw();
};
class CannotPlaceNewNodeException : public std::exception
{
public:
const char* what() const throw();
};
class InsertNodeCommand : public QUndoCommand
{
public:
InsertNodeCommand(GraphLogic *graphLogic);
void undo();
void redo();
private:
GraphLogic *m_graphLogic;
Node *m_node;
QPointF m_pos;
Node *m_activeNode;
};
#endif // COMMANDS_H

@ -2,12 +2,15 @@
#define GRAPHLOGIC_H
#include <QObject>
#include <QUndoStack>
#include "node.h"
#include "graphwidget.h"
#include "commands.h"
class GraphWidget;
class InsertNodeCommand;
class GraphLogic : public QObject
{
@ -16,6 +19,7 @@ class GraphLogic : public QObject
public:
explicit GraphLogic(GraphWidget *parent = 0);
void setUndoStack(QUndoStack *stack);
bool processKeyEvent(QKeyEvent *event);
void addFirstNode();
@ -28,17 +32,17 @@ public:
public slots:
// commands from toolbars:
void insertNode(); // will be undoable
void removeNode(); // will be undoable
void nodeEdited(); // will be undoable
void scaleUp(); // will be undoable
void scaleDown(); // will be undoable
void insertNode();
void removeNode(); /// @todo Rewrite as an undo action
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(); // will be undoable
void removeEdge(); // will be undoable
void addEdge(); /// @todo Rewrite as an undo action
void removeEdge(); /// @todo Rewrite as an undo action
void hintMode();
void insertPicture(const QString &picture); // will be undoable
void insertPicture(const QString &picture); /// @todo Rewrite as an undo action
void nodeChanged();
void nodeSelected();
@ -47,7 +51,7 @@ public slots:
signals:
void contentChanged();
void contentChanged(const bool& changed = true);
void notification(const QString &msg);
private:
@ -57,9 +61,9 @@ private:
void moveLeft();
void moveRight();
void move(const int &x, const int &y); // will be undoable
void setNodeColor(const QColor &color); // will be undoable
void setNodeTextColor(const QColor &color); // will be undoable
void move(const int &x, const int &y); /// @todo Rewrite as an undo action
void setNodeColor(const QColor &color); /// @todo Rewrite as an undo action
void setNodeTextColor(const QColor &color); /// @todo Rewrite as an undo action
// hint mode
void appendNumber(const int &unm);
@ -93,7 +97,10 @@ private:
bool m_edgeDeleting;
std::map<int, void(GraphLogic::*)(void)> m_memberMap;
QUndoStack *m_undoStack;
friend class InsertNodeCommand;
};
#endif // GRAPHLOGIC_H

@ -4,6 +4,7 @@
#include <QMainWindow>
#include <QSystemTrayIcon>
#include <QSignalMapper>
#include <QUndoView>
#include "graphwidget.h"
@ -46,6 +47,7 @@ public slots:
// toolbars
void showMainToolbar(const bool &show = true);
void showStatusIconToolbar(const bool &show = true);
void showUdoToolbar(const bool &show = true);
// handle changed content at quit
void quit();
@ -55,13 +57,11 @@ protected:
// handle changed content at exit events
void closeEvent(QCloseEvent * event);
// show/hide toolbars, otherwise pass on the event to GraphWidget
void keyPressEvent(QKeyEvent *event);
private:
void setUpMainToolbar();
void setUpStatusIconToolbar();
void setupMainToolbar();
void setupStatusIconToolbar();
void setupEditToolbar();
void setTitle(const QString &title);
Ui::MainWindow *m_ui;
@ -99,6 +99,15 @@ private:
QAction *m_delegate;
QAction *m_maybe;
QSignalMapper *m_signalMapper;
QUndoStack *m_undoStack;
QUndoView *m_undoView;
QAction *m_undo;
QAction *m_redo;
QAction *m_mainToolbar;
QAction *m_iconToolbar;
QAction *m_undoToolbar;
};
#endif // MAINWINDOW_H

@ -23,6 +23,7 @@ public:
void addEdge(Edge *edge, bool startsFromThisNode);
void deleteEdge(Node *otherEnd);
void removeEdgeFromList(Edge *edge);
void removeEdges();
// graph traversal
QList<Edge *> edgesFrom(const bool &excludeSecondaries = true) const;

@ -21,7 +21,8 @@ SOURCES += src/main.cpp \
src/node.cpp \
src/edge.cpp \
src/systemtray.cpp \
src/argumentparser.cpp
src/argumentparser.cpp \
src/commands.cpp
HEADERS += include/mainwindow.h \
@ -30,7 +31,8 @@ HEADERS += include/mainwindow.h \
include/node.h \
include/edge.h \
include/systemtray.h \
include/argumentparser.h
include/argumentparser.h \
include/commands.h
FORMS += ui/mainwindow.ui

@ -0,0 +1,77 @@
#include "include/commands.h"
#include <QDebug>
#include <math.h>
InsertNodeCommand::InsertNodeCommand(GraphLogic *graphLogic)
: m_graphLogic(graphLogic)
, m_node(0)
, m_activeNode(m_graphLogic->m_activeNode)
{
if (!m_activeNode)
throw NoActiveNodeException();
setText(QObject::tr("New node added to ").append(
m_activeNode == m_graphLogic->m_nodeList.first() ?
QObject::tr("Base node") :
QString("\"").append(m_activeNode->toPlainText().append("\""))));
m_graphLogic->nodeLostFocus();
// get the biggest angle between the edges of the Node.
double angle(m_activeNode->calculateBiggestAngle());
// let the distance between the current and new Node be 100 pixels
qreal length(100);
m_pos = m_activeNode->sceneBoundingRect().center() +
QPointF(length * cos(angle), length * sin(angle)) -
Node::newNodeCenter;
QRectF rect (m_graphLogic->m_graphWidget->scene()->sceneRect().topLeft(),
m_graphLogic->m_graphWidget->scene()->sceneRect().bottomRight()
- Node::newNodeBottomRigth);
if (!rect.contains(m_pos))
throw CannotPlaceNewNodeException();
// add a new node which inherits the color and textColor
m_node = m_graphLogic->nodeFactory();
m_node->setColor(m_activeNode->color());
m_node->setTextColor(m_activeNode->textColor());
m_node->setHtml(QString(""));
}
void InsertNodeCommand::undo()
{
m_graphLogic->m_nodeList.removeAll(m_node);
m_graphLogic->m_graphWidget->scene()->removeItem(m_node);
m_node->removeEdges();
m_graphLogic->setActiveNode(m_activeNode);
emit m_graphLogic->contentChanged(false);
}
void InsertNodeCommand::redo()
{
m_graphLogic->m_graphWidget->scene()->addItem(m_node);
m_graphLogic->m_nodeList.append(m_node);
m_node->setPos(m_pos);
m_graphLogic->addEdge(m_activeNode, m_node);
m_graphLogic->setActiveNode(m_node);
if (m_graphLogic->m_graphWidget->hasFocus())
m_graphLogic->nodeEdited();
emit m_graphLogic->contentChanged();
// it we are in hint mode, the numbers shall be re-calculated
if (m_graphLogic->m_showingNodeNumbers)
m_graphLogic->showNodeNumbers();
}

@ -4,6 +4,9 @@
#include <QColorDialog>
#include <QApplication>
#include <QScrollBar>
#include <QUndoCommand>
#include "include/commands.h"
GraphLogic::GraphLogic(GraphWidget *parent)
: QObject(parent)
@ -53,6 +56,11 @@ GraphLogic::GraphLogic(GraphWidget *parent)
(Qt::Key_Delete, &GraphLogic::removeNode));
}
void GraphLogic::setUndoStack(QUndoStack *stack)
{
m_undoStack = stack;
}
bool GraphLogic::processKeyEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Escape)
@ -99,6 +107,8 @@ bool GraphLogic::processKeyEvent(QKeyEvent *event)
void GraphLogic::addFirstNode()
{
Node *node = nodeFactory();
m_graphWidget->scene()->addItem(node);
m_nodeList.append(node);
node->setHtml(
QString("<img src=:/qtmindmap.svg width=50 height=50></img>"));
@ -145,6 +155,8 @@ bool GraphLogic::readContentFromXmlFile(const QString &fileName)
if(!e.isNull())
{
Node *node = nodeFactory();
m_graphWidget->scene()->addItem(node);
m_nodeList.append(node);
node->setHtml(e.attribute("htmlContent"));
node->setPos(e.attribute("x").toFloat(),
e.attribute("y").toFloat());
@ -282,52 +294,16 @@ void GraphLogic::writeContentToPngFile(const QString &fileName)
void GraphLogic::insertNode()
{
nodeLostFocus();
if (!m_activeNode)
try
{
emit notification(tr("No active node."));
return;
QUndoCommand *insertNodeCommand = new InsertNodeCommand(this);
m_undoStack->push(insertNodeCommand);
}
// get the biggest angle between the edges of the Node.
double angle(m_activeNode->calculateBiggestAngle());
// let the distance between the current and new Node be 100 pixels
qreal length(100);
QPointF pos(length * cos(angle), length * sin(angle));
QPointF newPos(m_activeNode->sceneBoundingRect().center() +
pos - Node::newNodeCenter);
QRectF rect (m_graphWidget->scene()->sceneRect().topLeft(),
m_graphWidget->scene()->sceneRect().bottomRight()
- Node::newNodeBottomRigth);
if (!rect.contains(newPos))
catch (std::exception &e)
{
emit notification(tr("New node would be placed outside of the scene"));
emit notification(e.what());
return;
}
// add a new node which inherits the color and textColor
Node *node = nodeFactory();
node->setColor(m_activeNode->color());
node->setTextColor(m_activeNode->textColor());
node->setHtml(QString(""));
node->setPos(newPos);
addEdge(m_activeNode, node);
// set it the active Node and editable, so the user can edit it at once
setActiveNode(node);
nodeEdited();
emit contentChanged();
// it we are in hint mode, the numbers shall be re-calculated
if (m_showingNodeNumbers)
showNodeNumbers();
}
void GraphLogic::removeNode()
@ -695,9 +671,6 @@ Node * GraphLogic::nodeFactory()
this, SLOT(nodeMoved(QGraphicsSceneMouseEvent*)));
connect(node, SIGNAL(nodeLostFocus()), this, SLOT(nodeLostFocus()));
m_graphWidget->scene()->addItem(node);
m_nodeList.append(node);
return node;
}

@ -28,6 +28,8 @@ GraphWidget::GraphWidget(MainWindow *parent)
m_graphlogic = new GraphLogic(this);
}
void GraphWidget::newScene()
{
m_graphlogic->removeAllNodes();

@ -27,18 +27,21 @@ MainWindow::MainWindow(QWidget *parent) :
setCentralWidget(m_graphicsView);
m_graphicsView->hide();
connect(m_graphicsView->graphLogic(), SIGNAL(contentChanged()),
this, SLOT(contentChanged()));
connect(m_graphicsView->graphLogic(), SIGNAL(contentChanged(const bool&)),
this, SLOT(contentChanged(const bool&)));
connect(m_graphicsView->graphLogic(), SIGNAL(notification(QString)),
this, SLOT(statusBarMsg(QString)));
// setup toolbars, don't show them
setUpMainToolbar();
setupMainToolbar();
m_ui->mainToolBar->hide();
setUpStatusIconToolbar();
setupStatusIconToolbar();
m_ui->statusIcons_toolBar->hide();
setupEditToolbar();
m_ui->undoToolBar->hide();
}
MainWindow::~MainWindow()
@ -270,6 +273,13 @@ void MainWindow::showStatusIconToolbar(const bool &show)
false);
}
void MainWindow::showUdoToolbar(const bool &show)
{
m_ui->undoToolBar->setVisible(show ?
!m_ui->undoToolBar->isVisible() :
false);
}
void MainWindow::quit()
{
if (m_contentChanged && !closeFile())
@ -285,27 +295,7 @@ void MainWindow::closeEvent(QCloseEvent * event)
event->accept();
}
void MainWindow::keyPressEvent(QKeyEvent *event)
{
// inactive action does not listen to signals
if (event->modifiers() & Qt::ControlModifier)
{
if (event->key() == Qt::Key_M)
{
showMainToolbar();
return;
}
if (event->key() == Qt::Key_I)
{
showStatusIconToolbar();
return;
}
}
QMainWindow::keyPressEvent(event);
}
void MainWindow::setUpMainToolbar()
void MainWindow::setupMainToolbar()
{
// why can't I do this with qtcreator? (adding actions to toolbar)
@ -368,7 +358,6 @@ void MainWindow::setUpMainToolbar()
SLOT(hintMode()));
m_showMainToolbar = new QAction(tr("Show main toolbar\n(Ctrl m)"), this);
m_showMainToolbar->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_M));
connect(m_showMainToolbar, SIGNAL(activated()), this,
SLOT(showMainToolbar()));
@ -398,7 +387,7 @@ void MainWindow::setUpMainToolbar()
m_ui->mainToolBar->addAction(m_showStatusIconToolbar);
}
void MainWindow::setUpStatusIconToolbar()
void MainWindow::setupStatusIconToolbar()
{
// map signals so actions can send icon name
m_signalMapper = new QSignalMapper(this);
@ -465,11 +454,46 @@ void MainWindow::setUpStatusIconToolbar()
m_ui->statusIcons_toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
}
void MainWindow::setupEditToolbar()
{
m_undoStack = new QUndoStack(this);
m_undoView = new QUndoView(m_undoStack,this);
m_ui->undoToolBar->addWidget(m_undoView);
m_undo = m_undoStack->createUndoAction(this, tr("&Undo"));
m_undo->setShortcuts(QKeySequence::Undo);
m_redo = m_undoStack->createRedoAction(this, tr("&Redo"));
m_redo->setShortcuts(QKeySequence::Redo);
m_ui->menuEdit->addAction(m_undo);
m_ui->menuEdit->addAction(m_redo);
m_ui->menuEdit->addSeparator();
m_mainToolbar = new QAction(tr("main toolbar"), this);
m_mainToolbar->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_M));
connect(m_mainToolbar, SIGNAL(activated()),
this, SLOT (showMainToolbar()));
m_iconToolbar = new QAction(tr("icon toolbar"), this);
m_iconToolbar->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_I));
connect(m_iconToolbar, SIGNAL(activated()),
this, SLOT (showStatusIconToolbar()));
m_undoToolbar = new QAction(tr("undo toolbar"), this);
m_undoToolbar->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_U));
connect(m_undoToolbar, SIGNAL(activated()),
this, SLOT (showUdoToolbar()));
m_ui->menuEdit->addAction(m_mainToolbar);
m_ui->menuEdit->addAction(m_iconToolbar);
m_ui->menuEdit->addAction(m_undoToolbar);
m_graphicsView->graphLogic()->setUndoStack(m_undoStack);
}
void MainWindow::setTitle(const QString &title)
{
title.isEmpty() ?
setWindowTitle("QtMindMap") :
setWindowTitle(QString(title).append(" - QtMindMap"));
}

@ -35,16 +35,7 @@ Node::Node()
Node::~Node()
{
// dtor of Edge will call removeEdgeFromList on booth nodes.
foreach (EdgeElement element, m_edgeList)
{
Edge *tmp = element.edge;
tmp->sourceNode()->removeEdgeFromList(tmp);
tmp->destNode()->removeEdgeFromList(tmp);
/// @bug crashes sometimes
delete tmp;
}
removeEdges();
}
void Node::addEdge(Edge *edge, bool startsFromThisNode)
@ -85,6 +76,19 @@ void Node::removeEdgeFromList(Edge *edge)
}
}
void Node::removeEdges()
{
foreach (EdgeElement element, m_edgeList)
{
Edge *tmp = element.edge;
tmp->sourceNode()->removeEdgeFromList(tmp);
tmp->destNode()->removeEdgeFromList(tmp);
/// @bug crashes sometimes
delete tmp;
}
}
// edges from this Node. Exclude secondaries if needed (calc subtree)
QList<Edge *> Node::edgesFrom(const bool &excludeSecondaries) const
{

@ -14,7 +14,7 @@
<string>QtMindMap</string>
</property>
<property name="windowIcon">
<iconset resource="qtmindmap.qrc">
<iconset resource="../images/qtmindmap.qrc">
<normaloff>:/qtmindmap.svg</normaloff>:/qtmindmap.svg</iconset>
</property>
<widget class="QWidget" name="centralWidget"/>
@ -24,7 +24,7 @@
<x>0</x>
<y>0</y>
<width>600</width>
<height>23</height>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
@ -47,7 +47,13 @@
</property>
<addaction name="actionAbout_QtMindMap"/>
</widget>
<widget class="QMenu" name="menuEdit">
<property name="title">
<string>&amp;Edit</string>
</property>
</widget>
<addaction name="menuFile"/>
<addaction name="menuEdit"/>
<addaction name="menuHelp"/>
</widget>
<widget class="QToolBar" name="mainToolBar">
@ -76,6 +82,17 @@
<bool>false</bool>
</attribute>
</widget>
<widget class="QToolBar" name="undoToolBar">
<property name="windowTitle">
<string>undo toolbar</string>
</property>
<attribute name="toolBarArea">
<enum>LeftToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>true</bool>
</attribute>
</widget>
<action name="actionNew">
<property name="enabled">
<bool>true</bool>
@ -163,10 +180,20 @@
<string>&amp;Keys</string>
</property>
</action>
<action name="actionUndo">
<property name="text">
<string>Undo</string>
</property>
</action>
<action name="actionRedo">
<property name="text">
<string>Redo</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources>
<include location="qtmindmap.qrc"/>
<include location="../images/qtmindmap.qrc"/>
</resources>
<connections/>
<slots>

Loading…
Cancel
Save