Dear all,

I've been working on implementing an undo/redo framework. The
attached patches are what I've done so far. I only have undo working
for the deleted dives.

This is not in anyway fully working, just a view of what I have done so that
you can point me in the right direction

Thanks!

-
Grace K.
From b3e44d087bd4ce4e92e9a9beed8230eeb4d1fbbd Mon Sep 17 00:00:00 2001
From: Grace Karanja <[email protected]>
Date: Mon, 9 Feb 2015 09:44:10 +0100
Subject: [PATCH 4/4] Add ability to undo deleted dives

Before the dive is deleted, a copy is made and passed to the
undo buffer. When edit->undo is clicked, this dive is restored
to the dive list.

Signed-off-by: Grace Karanja <[email protected]>
---
 qt-ui/divelistview.cpp |  4 ++++
 qt-ui/undobuffer.cpp   | 36 +++++++++++++++++++++++++++---------
 qt-ui/undobuffer.h     |  4 +++-
 3 files changed, 34 insertions(+), 10 deletions(-)

diff --git a/qt-ui/divelistview.cpp b/qt-ui/divelistview.cpp
index ec54af9..89b851a 100644
--- a/qt-ui/divelistview.cpp
+++ b/qt-ui/divelistview.cpp
@@ -11,6 +11,7 @@
 #include <QSettings>
 #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};
@@ -730,6 +731,9 @@ 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/undobuffer.cpp b/qt-ui/undobuffer.cpp
index b0c1d26..4ee0cf6 100644
--- a/qt-ui/undobuffer.cpp
+++ b/qt-ui/undobuffer.cpp
@@ -1,8 +1,9 @@
 #include "undobuffer.h"
+#include "mainwindow.h"
 
 UndoBuffer::UndoBuffer(QObject *parent) : QObject(parent)
 {
-
+	curIdx = 0;
 }
 
 UndoBuffer::~UndoBuffer()
@@ -12,32 +13,46 @@ 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);
 }
 
 
@@ -50,11 +65,14 @@ UndoCommand::UndoCommand(QString commandName, dive *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
index beae8e3..9fac147 100644
--- a/qt-ui/undobuffer.h
+++ b/qt-ui/undobuffer.h
@@ -12,7 +12,7 @@ private:
 
 public:
 	explicit UndoCommand(QString commandName, dive* affectedDive);
-	void setStateAfter(dive* affectedDive);
+	void setStateAfter(dive* affectedDive) { stateAfter = affectedDive; }
 	void undo();
 	void redo();
 };
@@ -25,7 +25,9 @@ public:
 	~UndoBuffer();
 	bool canUndo();
 	bool canRedo();
+	UndoCommand *current() const { return list.at(curIdx - 1); }
 private:
+	QList<UndoCommand*> list;
 	int curIdx;
 public slots:
 	void redo();
-- 
1.9.1

From 091542cd2468f995f1d737846a785da10fbc38a3 Mon Sep 17 00:00:00 2001
From: Grace Karanja <[email protected]>
Date: Mon, 9 Feb 2015 09:30:27 +0100
Subject: [PATCH 3/4] Add UndoCommand class

Add a class to handle all undo/redo events. Whenever a user
action affects a dive, an undo command will be created. A list of
these commands will be stored in the UndoBuffer, to allow for
moving forwards/backwards in the list.

Signed-off-by: Grace Karanja <[email protected]>
---
 qt-ui/undobuffer.cpp | 18 ++++++++++++++++++
 qt-ui/undobuffer.h   | 13 +++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/qt-ui/undobuffer.cpp b/qt-ui/undobuffer.cpp
index 92c0dee..b0c1d26 100644
--- a/qt-ui/undobuffer.cpp
+++ b/qt-ui/undobuffer.cpp
@@ -40,3 +40,21 @@ void UndoBuffer::recordAfter(dive *affectedDive)
 
 }
 
+
+
+UndoCommand::UndoCommand(QString commandName, dive *affectedDive)
+{
+	name = commandName;
+	stateBefore = affectedDive;
+}
+
+void UndoCommand::undo()
+{
+
+}
+
+void UndoCommand::redo()
+{
+
+}
+
diff --git a/qt-ui/undobuffer.h b/qt-ui/undobuffer.h
index a292d3b..beae8e3 100644
--- a/qt-ui/undobuffer.h
+++ b/qt-ui/undobuffer.h
@@ -4,6 +4,19 @@
 #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);
+	void undo();
+	void redo();
+};
+
 class UndoBuffer : public QObject
 {
 	Q_OBJECT
-- 
1.9.1

From fa4f42b22f8ae91928d1efd60ed60087e2521f5d Mon Sep 17 00:00:00 2001
From: Grace Karanja <[email protected]>
Date: Mon, 9 Feb 2015 09:24:32 +0100
Subject: [PATCH 2/4] Add menu entries for undo/redo

Add an edit menu with undo and redo submenus, and connect them to
the UndoBuffer class. The submenus are only enabled when needed.

Signed-off-by: Grace Karanja <[email protected]>
---
 qt-ui/mainwindow.cpp | 19 +++++++++++++++++++
 qt-ui/mainwindow.h   |  5 +++++
 qt-ui/mainwindow.ui  | 26 +++++++++++++++++++++++++-
 3 files changed, 49 insertions(+), 1 deletion(-)

diff --git a/qt-ui/mainwindow.cpp b/qt-ui/mainwindow.cpp
index 3142f5a..57af5e0 100644
--- a/qt-ui/mainwindow.cpp
+++ b/qt-ui/mainwindow.cpp
@@ -31,6 +31,7 @@
 #include "usermanual.h"
 #endif
 #include <QNetworkProxy>
+#include "undobuffer.h"
 
 MainWindow *MainWindow::m_Instance = NULL;
 
@@ -77,6 +78,7 @@ MainWindow::MainWindow() : QMainWindow(),
 	connect(DivePlannerPointsModel::instance(), SIGNAL(planCreated()), this, SLOT(planCreated()));
 	connect(DivePlannerPointsModel::instance(), SIGNAL(planCanceled()), this, SLOT(planCanceled()));
 	connect(ui.printPlan, SIGNAL(pressed()), ui.divePlannerWidget, SLOT(printDecoPlan()));
+	connect(ui.menu_Edit, SIGNAL(aboutToShow()), this, SLOT(checkForUndoAndRedo()));
 #ifdef NO_PRINTING
 	ui.printPlan->hide();
 #endif
@@ -152,6 +154,7 @@ MainWindow::MainWindow() : QMainWindow(),
 	toolBar->setContentsMargins(zeroMargins);
 
 	updateManager = new UpdateManager(this);
+	undoBuffer = new UndoBuffer(this);
 }
 
 MainWindow::~MainWindow()
@@ -1466,3 +1469,19 @@ void MainWindow::on_actionFilterTags_triggered()
 	else
 		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());
+}
diff --git a/qt-ui/mainwindow.h b/qt-ui/mainwindow.h
index 2364caa..641c9ec 100644
--- a/qt-ui/mainwindow.h
+++ b/qt-ui/mainwindow.h
@@ -30,6 +30,7 @@ class QWebView;
 class QSettings;
 class UpdateManager;
 class UserManual;
+class UndoBuffer;
 
 enum MainWindowTitleFormat {
 	MWTF_DEFAULT,
@@ -82,6 +83,7 @@ public:
 	void setPlanNotes(const char *notes);
 	void printPlan();
 	void checkSurvey(QSettings *s);
+	UndoBuffer *undoBuffer;
 private
 slots:
 	/* file menu action */
@@ -151,6 +153,9 @@ 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 8ffb8bb..9507b5f 100644
--- a/qt-ui/mainwindow.ui
+++ b/qt-ui/mainwindow.ui
@@ -195,7 +195,7 @@ p, li { white-space: pre-wrap; }
      <x>0</x>
      <y>0</y>
      <width>1682</width>
-     <height>27</height>
+     <height>25</height>
     </rect>
    </property>
    <widget class="QMenu" name="menuFile">
@@ -271,7 +271,15 @@ p, li { white-space: pre-wrap; }
     <addaction name="actionDownloadWeb"/>
     <addaction name="actionDivelogs_de"/>
    </widget>
+   <widget class="QMenu" name="menu_Edit">
+    <property name="title">
+     <string>&amp;Edit</string>
+    </property>
+    <addaction name="action_Undo"/>
+    <addaction name="action_Redo"/>
+   </widget>
    <addaction name="menuFile"/>
+   <addaction name="menu_Edit"/>
    <addaction name="menuImport"/>
    <addaction name="menuLog"/>
    <addaction name="menuView"/>
@@ -813,6 +821,22 @@ p, li { white-space: pre-wrap; }
     <string>User &amp;survey</string>
    </property>
   </action>
+  <action name="action_Undo">
+   <property name="text">
+    <string>&amp;Undo</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+Z</string>
+   </property>
+  </action>
+  <action name="action_Redo">
+   <property name="text">
+    <string>&amp;Redo</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+Shift+Z</string>
+   </property>
+  </action>
  </widget>
  <customwidgets>
   <customwidget>
-- 
1.9.1

From ce968daea4d8d7f76dc58b2d464d3446f11c677d Mon Sep 17 00:00:00 2001
From: Grace Karanja <[email protected]>
Date: Mon, 9 Feb 2015 09:17:38 +0100
Subject: [PATCH 1/4] Create UndoBuffer class

Add an empty UndoBuffer class. This will be built up on to
implement a working undo/redo mechanism.

Signed-off-by: Grace Karanja <[email protected]>
---
 qt-ui/undobuffer.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++
 qt-ui/undobuffer.h   | 24 ++++++++++++++++++++++++
 subsurface.pro       |  6 ++++--
 3 files changed, 70 insertions(+), 2 deletions(-)
 create mode 100644 qt-ui/undobuffer.cpp
 create mode 100644 qt-ui/undobuffer.h

diff --git a/qt-ui/undobuffer.cpp b/qt-ui/undobuffer.cpp
new file mode 100644
index 0000000..92c0dee
--- /dev/null
+++ b/qt-ui/undobuffer.cpp
@@ -0,0 +1,42 @@
+#include "undobuffer.h"
+
+UndoBuffer::UndoBuffer(QObject *parent) : QObject(parent)
+{
+
+}
+
+UndoBuffer::~UndoBuffer()
+{
+
+}
+
+bool UndoBuffer::canUndo()
+{
+
+}
+
+bool UndoBuffer::canRedo()
+{
+
+}
+
+void UndoBuffer::redo()
+{
+
+}
+
+void UndoBuffer::undo()
+{
+
+}
+
+void UndoBuffer::recordbefore(QString commandName, dive *affectedDive)
+{
+
+}
+
+void UndoBuffer::recordAfter(dive *affectedDive)
+{
+
+}
+
diff --git a/qt-ui/undobuffer.h b/qt-ui/undobuffer.h
new file mode 100644
index 0000000..a292d3b
--- /dev/null
+++ b/qt-ui/undobuffer.h
@@ -0,0 +1,24 @@
+#ifndef UNDOBUFFER_H
+#define UNDOBUFFER_H
+
+#include <QObject>
+#include "dive.h"
+
+class UndoBuffer : public QObject
+{
+	Q_OBJECT
+public:
+	explicit UndoBuffer(QObject *parent = 0);
+	~UndoBuffer();
+	bool canUndo();
+	bool canRedo();
+private:
+	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 2cc6b09..000806f 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/undobuffer.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/undobuffer.cpp
 
 android: SOURCES += android.cpp
 else: win32: SOURCES += windows.c
-- 
1.9.1

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

Reply via email to