On Tue, Feb 10, 2015 at 7:32 PM, Tomaz Canabrava <[email protected]> wrote:
>
> I never used Undo / Redo framework before, but why didn't you used the
> QUndoGroup / QUndoCommand / QUndoStack classes and created your own?
>

Now the attached patches use QUndoStack and QUndoCommand.


>
>
> Tomaz
>
> _______________________________________________
> subsurface mailing list
> [email protected]
> http://lists.subsurface-divelog.org/cgi-bin/mailman/listinfo/subsurface
>
>
From 120be3981901e8fef6d9291ec3c93b9ad989afe1 Mon Sep 17 00:00:00 2001
From: Grace Karanja <[email protected]>
Date: Wed, 11 Feb 2015 09:10:34 +0300
Subject: [PATCH 1/4] Reverse undo buffer

Reverse all the code using the UndoBuffer class so that we can
use the QUndoStack and QUndoCommand classes. These are Qt's own
inbuild undo framework classes, offering a better undo/redo
process.

Signed-off-by: Grace Karanja <[email protected]>
---
 qt-ui/divelistview.cpp |  4 ---
 qt-ui/mainwindow.cpp   | 19 ------------
 qt-ui/mainwindow.h     |  5 ----
 qt-ui/mainwindow.ui    |  4 +--
 qt-ui/undobuffer.cpp   | 78 --------------------------------------------------
 qt-ui/undobuffer.h     | 39 -------------------------
 subsurface.pro         |  6 ++--
 7 files changed, 3 insertions(+), 152 deletions(-)
 delete mode 100644 qt-ui/undobuffer.cpp
 delete mode 100644 qt-ui/undobuffer.h

diff --git a/qt-ui/divelistview.cpp b/qt-ui/divelistview.cpp
index 6d86422..b866a1a 100644
--- a/qt-ui/divelistview.cpp
+++ b/qt-ui/divelistview.cpp
@@ -14,7 +14,6 @@
 #include <QKeyEvent>
 #include <QFileDialog>
 #include "qthelper.h"
-#include "undobuffer.h"
 
 //                                #  Date  Rtg Dpth  Dur  Tmp Wght Suit  Cyl  Gas  SAC  OTU  CNS  Loc
 static int defaultWidth[] =    {  70, 140, 90,  50,  50,  50,  50,  70,  50,  50,  70,  50,  50, 500};
@@ -735,9 +734,6 @@ void DiveListView::deleteDive()
 	for_each_dive (i, d) {
 		if (!d->selected)
 			continue;
-		struct dive* undo_entry = alloc_dive();
-		copy_dive(get_dive(i), undo_entry);
-		MainWindow::instance()->undoBuffer->recordbefore("Delete Dive", undo_entry);
 		delete_single_dive(i);
 		i--; // so the next dive isn't skipped... it's now #i
 		lastDiveNr = i;
diff --git a/qt-ui/mainwindow.cpp b/qt-ui/mainwindow.cpp
index 163ff7d..9908e24 100644
--- a/qt-ui/mainwindow.cpp
+++ b/qt-ui/mainwindow.cpp
@@ -36,7 +36,6 @@
 #include "usermanual.h"
 #endif
 #include <QNetworkProxy>
-#include "undobuffer.h"
 
 MainWindow *MainWindow::m_Instance = NULL;
 
@@ -108,7 +107,6 @@ MainWindow::MainWindow() : QMainWindow(),
 	connect(DivePlannerPointsModel::instance(), SIGNAL(planCreated()), this, SLOT(planCreated()));
 	connect(DivePlannerPointsModel::instance(), SIGNAL(planCanceled()), this, SLOT(planCanceled()));
 	connect(plannerDetails->printPlan(), SIGNAL(pressed()), divePlannerWidget(), SLOT(printDecoPlan()));
-	connect(ui.menu_Edit, SIGNAL(aboutToShow()), this, SLOT(checkForUndoAndRedo()));
 #ifdef NO_PRINTING
 	ui.printPlan->hide();
 	ui.menuFile->removeAction(ui.actionPrint);
@@ -182,7 +180,6 @@ MainWindow::MainWindow() : QMainWindow(),
 	toolBar->setContentsMargins(zeroMargins);
 
 	updateManager = new UpdateManager(this);
-	undoBuffer = new UndoBuffer(this);
 }
 
 MainWindow::~MainWindow()
@@ -1502,22 +1499,6 @@ void MainWindow::on_actionFilterTags_triggered()
 		ui.multiFilter->setVisible(true);
 }
 
-void MainWindow::on_action_Undo_triggered()
-{
-	undoBuffer->undo();
-}
-
-void MainWindow::on_action_Redo_triggered()
-{
-	undoBuffer->redo();
-}
-
-void MainWindow::checkForUndoAndRedo()
-{
-	ui.action_Undo->setEnabled(undoBuffer->canUndo());
-	ui.action_Redo->setEnabled(undoBuffer->canRedo());
-}
-
 void MainWindow::registerApplicationState(const QByteArray& state, QWidget *topLeft, QWidget *topRight, QWidget *bottomLeft, QWidget *bottomRight)
 {
 	applicationState[state] = WidgetForQuadrant(topLeft, topRight, bottomLeft, bottomRight);
diff --git a/qt-ui/mainwindow.h b/qt-ui/mainwindow.h
index 716968b..5ee085c 100644
--- a/qt-ui/mainwindow.h
+++ b/qt-ui/mainwindow.h
@@ -34,7 +34,6 @@ class DivePlannerWidget;
 class ProfileWidget2;
 class PlannerDetails;
 class PlannerSettingsWidget;
-class UndoBuffer;
 
 enum MainWindowTitleFormat {
 	MWTF_DEFAULT,
@@ -89,7 +88,6 @@ public:
 	void printPlan();
 	void checkSurvey(QSettings *s);
 	void setApplicationState(const QByteArray& state);
-	UndoBuffer *undoBuffer;
 private
 slots:
 	/* file menu action */
@@ -159,9 +157,6 @@ slots:
 	void on_paste_triggered();
 	void on_actionFilterTags_triggered();
 	void on_actionConfigure_Dive_Computer_triggered();
-	void on_action_Undo_triggered();
-	void on_action_Redo_triggered();
-	void checkForUndoAndRedo();
 
 protected:
 	void closeEvent(QCloseEvent *);
diff --git a/qt-ui/mainwindow.ui b/qt-ui/mainwindow.ui
index ced02c9..b6cd4a3 100644
--- a/qt-ui/mainwindow.ui
+++ b/qt-ui/mainwindow.ui
@@ -50,7 +50,7 @@
      <x>0</x>
      <y>0</y>
      <width>861</width>
-     <height>32</height>
+     <height>25</height>
     </rect>
    </property>
    <widget class="QMenu" name="menuFile">
@@ -130,8 +130,6 @@
     <property name="title">
      <string>&amp;Edit</string>
     </property>
-    <addaction name="action_Undo"/>
-    <addaction name="action_Redo"/>
    </widget>
    <addaction name="menuFile"/>
    <addaction name="menu_Edit"/>
diff --git a/qt-ui/undobuffer.cpp b/qt-ui/undobuffer.cpp
deleted file mode 100644
index 4ee0cf6..0000000
--- a/qt-ui/undobuffer.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-#include "undobuffer.h"
-#include "mainwindow.h"
-
-UndoBuffer::UndoBuffer(QObject *parent) : QObject(parent)
-{
-	curIdx = 0;
-}
-
-UndoBuffer::~UndoBuffer()
-{
-
-}
-
-bool UndoBuffer::canUndo()
-{
-	return curIdx > 0;
-}
-
-bool UndoBuffer::canRedo()
-{
-	return curIdx < list.count();
-}
-
-void UndoBuffer::redo()
-{
-	current()->redo();
-	curIdx++;
-	if (curIdx > list.count())
-		curIdx = list.count() - 1;
-}
-
-void UndoBuffer::undo()
-{
-	current()->undo();
-	curIdx = list.indexOf(current());
-}
-
-void UndoBuffer::recordbefore(QString commandName, dive *affectedDive)
-{
-	UndoCommand *cmd = new UndoCommand(commandName, affectedDive);
-	//If we are within the list, clear the extra UndoCommands.
-	if (list.count() > 0) {
-		if (curIdx + 1 < list.count()) {
-			for (int i = curIdx + 1; i < list.count(); i++) {
-				list.removeAt(i);
-			}
-		}
-	}
-	list.append(cmd);
-	curIdx = list.count();
-}
-
-void UndoBuffer::recordAfter(dive *affectedDive)
-{
-	list.at(curIdx - 1)->setStateAfter(affectedDive);
-}
-
-
-
-UndoCommand::UndoCommand(QString commandName, dive *affectedDive)
-{
-	name = commandName;
-	stateBefore = affectedDive;
-}
-
-void UndoCommand::undo()
-{
-	if (name == "Delete Dive") {
-		record_dive(stateBefore);
-		MainWindow::instance()->recreateDiveList();
-	}
-}
-
-void UndoCommand::redo()
-{
-	//To be implemented
-}
-
diff --git a/qt-ui/undobuffer.h b/qt-ui/undobuffer.h
deleted file mode 100644
index 9fac147..0000000
--- a/qt-ui/undobuffer.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef UNDOBUFFER_H
-#define UNDOBUFFER_H
-
-#include <QObject>
-#include "dive.h"
-
-class UndoCommand {
-private:
-	dive* stateBefore;
-	dive* stateAfter;
-	QString name;
-
-public:
-	explicit UndoCommand(QString commandName, dive* affectedDive);
-	void setStateAfter(dive* affectedDive) { stateAfter = affectedDive; }
-	void undo();
-	void redo();
-};
-
-class UndoBuffer : public QObject
-{
-	Q_OBJECT
-public:
-	explicit UndoBuffer(QObject *parent = 0);
-	~UndoBuffer();
-	bool canUndo();
-	bool canRedo();
-	UndoCommand *current() const { return list.at(curIdx - 1); }
-private:
-	QList<UndoCommand*> list;
-	int curIdx;
-public slots:
-	void redo();
-	void undo();
-	void recordbefore(QString commandName, dive *affectedDive);
-	void recordAfter(dive *affectedDive);
-};
-
-#endif // UNDOBUFFER_H
diff --git a/subsurface.pro b/subsurface.pro
index e59b323..5fb6ab5 100644
--- a/subsurface.pro
+++ b/subsurface.pro
@@ -104,8 +104,7 @@ HEADERS = \
 	qt-ui/statistics/statisticsbar.h \
 	qt-ui/statistics/yearstatistics.h \
 	qt-ui/diveshareexportdialog.h \
-	qt-ui/filtermodels.h \
-	qt-ui/undobuffer.h
+	qt-ui/filtermodels.h
 
 android: HEADERS -= \
 	qt-ui/usermanual.h \
@@ -199,8 +198,7 @@ SOURCES =  \
 	qt-ui/statistics/statisticsbar.cpp \
 	qt-ui/statistics/monthstatistics.cpp \
 	qt-ui/diveshareexportdialog.cpp \
-	qt-ui/filtermodels.cpp \
-	qt-ui/undobuffer.cpp
+	qt-ui/filtermodels.cpp
 
 android: SOURCES += android.cpp
 else: win32: SOURCES += windows.c
-- 
1.9.1

From 54f254a8461a937a021a68819847e5d77f9f1117 Mon Sep 17 00:00:00 2001
From: Grace Karanja <[email protected]>
Date: Wed, 11 Feb 2015 09:26:17 +0300
Subject: [PATCH 2/4] Add undo stack

Add an instance of QUndoStack in the mainwindow, and add undo/redo
actions in the edit menu. The QUndoStack will have a collection
of QUndoCommands to process the undo and redo events.
---
 qt-ui/mainwindow.cpp | 11 +++++++++++
 qt-ui/mainwindow.h   |  2 ++
 2 files changed, 13 insertions(+)

diff --git a/qt-ui/mainwindow.cpp b/qt-ui/mainwindow.cpp
index 9908e24..a0e4f12 100644
--- a/qt-ui/mainwindow.cpp
+++ b/qt-ui/mainwindow.cpp
@@ -36,6 +36,7 @@
 #include "usermanual.h"
 #endif
 #include <QNetworkProxy>
+#include <QUndoStack>
 
 MainWindow *MainWindow::m_Instance = NULL;
 
@@ -180,6 +181,16 @@ MainWindow::MainWindow() : QMainWindow(),
 	toolBar->setContentsMargins(zeroMargins);
 
 	updateManager = new UpdateManager(this);
+
+	undoStack = new QUndoStack(this);
+	QAction *undoAction = undoStack->createUndoAction(this, tr("&Undo"));
+	QAction *redoAction = undoStack->createRedoAction(this, tr("&Redo"));
+	undoAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Z));
+	redoAction->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Z));
+	QList<QAction*>undoRedoActions;
+	undoRedoActions.append(undoAction);
+	undoRedoActions.append(redoAction);
+	ui.menu_Edit->addActions(undoRedoActions);
 }
 
 MainWindow::~MainWindow()
diff --git a/qt-ui/mainwindow.h b/qt-ui/mainwindow.h
index 5ee085c..25771d6 100644
--- a/qt-ui/mainwindow.h
+++ b/qt-ui/mainwindow.h
@@ -34,6 +34,7 @@ class DivePlannerWidget;
 class ProfileWidget2;
 class PlannerDetails;
 class PlannerSettingsWidget;
+class QUndoStack;
 
 enum MainWindowTitleFormat {
 	MWTF_DEFAULT,
@@ -88,6 +89,7 @@ public:
 	void printPlan();
 	void checkSurvey(QSettings *s);
 	void setApplicationState(const QByteArray& state);
+	QUndoStack *undoStack;
 private
 slots:
 	/* file menu action */
-- 
1.9.1

From 8aab295975ec1f7eb6dc8a6f361d64d9fab16f04 Mon Sep 17 00:00:00 2001
From: Grace Karanja <[email protected]>
Date: Wed, 11 Feb 2015 09:28:43 +0300
Subject: [PATCH 3/4] Add a structure to hold undo commands

Add the undocommands.cpp / undocommands.h files, which will hold a
collection of classes that will hold undo commands.
---
 qt-ui/undocommands.cpp | 16 ++++++++++++++++
 qt-ui/undocommands.h   | 17 +++++++++++++++++
 subsurface.pro         |  6 ++++--
 3 files changed, 37 insertions(+), 2 deletions(-)
 create mode 100644 qt-ui/undocommands.cpp
 create mode 100644 qt-ui/undocommands.h

diff --git a/qt-ui/undocommands.cpp b/qt-ui/undocommands.cpp
new file mode 100644
index 0000000..f76f021
--- /dev/null
+++ b/qt-ui/undocommands.cpp
@@ -0,0 +1,16 @@
+#include "undocommands.h"
+
+UndoDeleteDive::UndoDeleteDive(QList<dive *> diveList)
+{
+
+}
+
+void UndoDeleteDive::undo()
+{
+
+}
+
+void UndoDeleteDive::redo()
+{
+
+}
diff --git a/qt-ui/undocommands.h b/qt-ui/undocommands.h
new file mode 100644
index 0000000..9a7803f
--- /dev/null
+++ b/qt-ui/undocommands.h
@@ -0,0 +1,17 @@
+#ifndef UNDOCOMMANDS_H
+#define UNDOCOMMANDS_H
+
+#include <QUndoCommand>
+#include "dive.h"
+
+class UndoDeleteDive : public QUndoCommand {
+public:
+	UndoDeleteDive(QList<struct dive*> diveList);
+	virtual void undo();
+	virtual void redo();
+
+private:
+	QList<struct dive*> dives;
+};
+
+#endif // UNDOCOMMANDS_H
diff --git a/subsurface.pro b/subsurface.pro
index 5fb6ab5..d65c94f 100644
--- a/subsurface.pro
+++ b/subsurface.pro
@@ -104,7 +104,8 @@ HEADERS = \
 	qt-ui/statistics/statisticsbar.h \
 	qt-ui/statistics/yearstatistics.h \
 	qt-ui/diveshareexportdialog.h \
-	qt-ui/filtermodels.h
+	qt-ui/filtermodels.h \
+	qt-ui/undocommands.h
 
 android: HEADERS -= \
 	qt-ui/usermanual.h \
@@ -198,7 +199,8 @@ SOURCES =  \
 	qt-ui/statistics/statisticsbar.cpp \
 	qt-ui/statistics/monthstatistics.cpp \
 	qt-ui/diveshareexportdialog.cpp \
-	qt-ui/filtermodels.cpp
+	qt-ui/filtermodels.cpp \
+	qt-ui/undocommands.cpp
 
 android: SOURCES += android.cpp
 else: win32: SOURCES += windows.c
-- 
1.9.1

From 216ddfa8e367c3c2379adc3898fefffeacd22671 Mon Sep 17 00:00:00 2001
From: Grace Karanja <[email protected]>
Date: Wed, 11 Feb 2015 10:57:56 +0300
Subject: [PATCH 4/4] Add option to undo deleted dives

Add ability to undo deleted dives by storing a list of the
deleted dives in a QUndoCommand.

Signed-off-by: Grace Karanja <[email protected]>
---
 qt-ui/divelistview.cpp |  7 +++++++
 qt-ui/undocommands.cpp | 26 +++++++++++++++++++++++---
 2 files changed, 30 insertions(+), 3 deletions(-)

diff --git a/qt-ui/divelistview.cpp b/qt-ui/divelistview.cpp
index b866a1a..e4ccb72 100644
--- a/qt-ui/divelistview.cpp
+++ b/qt-ui/divelistview.cpp
@@ -14,6 +14,7 @@
 #include <QKeyEvent>
 #include <QFileDialog>
 #include "qthelper.h"
+#include "undocommands.h"
 
 //                                #  Date  Rtg Dpth  Dur  Tmp Wght Suit  Cyl  Gas  SAC  OTU  CNS  Loc
 static int defaultWidth[] =    {  70, 140, 90,  50,  50,  50,  50,  70,  50,  50,  70,  50,  50, 500};
@@ -731,13 +732,19 @@ void DiveListView::deleteDive()
 	// so instead of using the for_each_dive macro I'm using an explicit for loop
 	// to make this easier to understand
 	int lastDiveNr = -1;
+	QList<struct dive*> deletedDives; //a list of all deleted dives to be stored in the undo command
 	for_each_dive (i, d) {
 		if (!d->selected)
 			continue;
+		struct dive* undo_entry = alloc_dive();
+		copy_dive(get_dive(i), undo_entry);
+		deletedDives.append(undo_entry);
 		delete_single_dive(i);
 		i--; // so the next dive isn't skipped... it's now #i
 		lastDiveNr = i;
 	}
+	UndoDeleteDive *undoEntry = new UndoDeleteDive(deletedDives);
+	MainWindow::instance()->undoStack->push(undoEntry);
 	if (amount_selected == 0) {
 		MainWindow::instance()->cleanUpEmpty();
 	}
diff --git a/qt-ui/undocommands.cpp b/qt-ui/undocommands.cpp
index f76f021..8c58c7c 100644
--- a/qt-ui/undocommands.cpp
+++ b/qt-ui/undocommands.cpp
@@ -1,16 +1,36 @@
 #include "undocommands.h"
+#include "mainwindow.h"
+#include "divelist.h"
 
 UndoDeleteDive::UndoDeleteDive(QList<dive *> diveList)
 {
-
+	dives = diveList;
+	setText("delete dive");
+	if (dives.count() > 1)
+		setText(QString("delete %1 dives").arg(QString::number(dives.count())));
 }
 
 void UndoDeleteDive::undo()
 {
-
+	for (int i = 0; i < dives.count(); i++)
+		record_dive(dives.at(i));
+	mark_divelist_changed(true);
+	MainWindow::instance()->refreshDisplay();
 }
 
 void UndoDeleteDive::redo()
 {
-
+	QList<struct dive*> newList;
+	for (int i = 0; i < dives.count(); i++) {
+		//make a copy of the dive before deleting it
+		struct dive* d = alloc_dive();
+		copy_dive(dives.at(i), d);
+		newList.append(d);
+		//delete the dive
+		delete_single_dive(get_divenr(dives.at(i)));
+	}
+	mark_divelist_changed(true);
+	MainWindow::instance()->refreshDisplay();
+	dives.clear();
+	dives = newList;
 }
-- 
1.9.1

_______________________________________________
subsurface mailing list
[email protected]
http://lists.subsurface-divelog.org/cgi-bin/mailman/listinfo/subsurface

Reply via email to