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>&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
