diff options
author | Berthold Stoeger <bstoeger@mail.tuwien.ac.at> | 2019-03-12 22:35:43 +0100 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2019-04-12 18:19:07 +0300 |
commit | 8e1f736d2b608784e1ea942ec8579d2361691c43 (patch) | |
tree | c6c9c60d112e95158a69b692a1ca32b0923a39d3 | |
parent | e99c4c90592c9dba17d5cbb9a99d0bf458fb53d2 (diff) | |
download | subsurface-8e1f736d2b608784e1ea942ec8579d2361691c43.tar.gz |
Undo: make dive site removal undoable
Create a new undo-command for deleting dive sites. If there are dives
associated with that site, the dives will be removed. The frontend
is not yet updated in such a case, as that infrastructure is in a
different PR.
Connect the trashcan icon of the dive site table to the undo command.
Currently, this code is in the dive site model, which makes little
sense, but is how the TableView class works. We might want to change
that when cylinder and weight editing are made undoable.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
-rw-r--r-- | desktop-widgets/CMakeLists.txt | 2 | ||||
-rw-r--r-- | desktop-widgets/command.cpp | 7 | ||||
-rw-r--r-- | desktop-widgets/command.h | 4 | ||||
-rw-r--r-- | desktop-widgets/command_divesite.cpp | 83 | ||||
-rw-r--r-- | desktop-widgets/command_divesite.h | 31 | ||||
-rw-r--r-- | qt-models/divelocationmodel.cpp | 25 | ||||
-rw-r--r-- | qt-models/divelocationmodel.h | 2 |
7 files changed, 153 insertions, 1 deletions
diff --git a/desktop-widgets/CMakeLists.txt b/desktop-widgets/CMakeLists.txt index efccfcc26..c494f1a8b 100644 --- a/desktop-widgets/CMakeLists.txt +++ b/desktop-widgets/CMakeLists.txt @@ -62,6 +62,8 @@ set(SUBSURFACE_INTERFACE command_base.h command_divelist.cpp command_divelist.h + command_divesite.cpp + command_divesite.h configuredivecomputerdialog.cpp configuredivecomputerdialog.h divecomputermanagementdialog.cpp diff --git a/desktop-widgets/command.cpp b/desktop-widgets/command.cpp index 2e2982860..80a233404 100644 --- a/desktop-widgets/command.cpp +++ b/desktop-widgets/command.cpp @@ -2,6 +2,7 @@ #include "command.h" #include "command_divelist.h" +#include "command_divesite.h" namespace Command { @@ -76,4 +77,10 @@ void mergeDives(const QVector <dive *> &dives) execute(new MergeDives(dives)); } +// Dive site related commands +void deleteDiveSites(const QVector <dive_site *> &sites) +{ + execute(new DeleteDiveSites(sites)); +} + } // namespace Command diff --git a/desktop-widgets/command.h b/desktop-widgets/command.h index dfc79a9e6..77920a81c 100644 --- a/desktop-widgets/command.h +++ b/desktop-widgets/command.h @@ -38,6 +38,10 @@ void splitDives(dive *d, duration_t time); void splitDiveComputer(dive *d, int dc_num); void mergeDives(const QVector <dive *> &dives); +// 3) Dive-site related commands + +void deleteDiveSites(const QVector <dive_site *> &sites); + } // namespace Command #endif // COMMAND_H diff --git a/desktop-widgets/command_divesite.cpp b/desktop-widgets/command_divesite.cpp new file mode 100644 index 000000000..d4c5d87b8 --- /dev/null +++ b/desktop-widgets/command_divesite.cpp @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "command_divesite.h" +#include "core/divesite.h" +#include "core/subsurface-qt/DiveListNotifier.h" + +namespace Command { + +// Helper functions to add / remove a set of dive sites + +// Add a set of dive sites to the core. The dives that were associated with +// that dive site will be restored to that dive site. +static std::vector<dive_site *> addDiveSites(std::vector<OwningDiveSitePtr> &sites) +{ + std::vector<dive_site *> res; + res.reserve(sites.size()); + + for (OwningDiveSitePtr &ds: sites) { + // Readd the dives that belonged to this site + for (int i = 0; i < ds->dives.nr; ++i) { + // TODO: send dive site changed signal + ds->dives.dives[i]->dive_site = ds.get(); + } + + // Add dive site to core, but remember a non-owning pointer first. + res.push_back(ds.get()); + int idx = register_dive_site(ds.release()); // Return ownership to backend. + emit diveListNotifier.diveSiteAdded(res.back(), idx); // Inform frontend of new dive site. + } + + // Clear vector of unused owning pointers + sites.clear(); + + return res; +} + +// Remove a set of dive sites. Get owning pointers to them. The dives are set to +// being at no dive site, but the dive site will retain a list of dives, so +// that the dives can be readded to the site on undo. +static std::vector<OwningDiveSitePtr> removeDiveSites(std::vector<dive_site *> &sites) +{ + std::vector<OwningDiveSitePtr> res; + res.reserve(sites.size()); + + for (dive_site *ds: sites) { + // Reset the dive_site field of the affected dives + for (int i = 0; i < ds->dives.nr; ++i) { + // TODO: send dive site changed signal + ds->dives.dives[i]->dive_site = nullptr; + } + + // Remove dive site from core and take ownership. + int idx = unregister_dive_site(ds); + res.emplace_back(ds); + emit diveListNotifier.diveSiteDeleted(ds, idx); // Inform frontend of removed dive site. + } + + sites.clear(); + + return res; +} + +DeleteDiveSites::DeleteDiveSites(const QVector<dive_site *> &sites) : sitesToRemove(sites.toStdVector()) +{ + setText(tr("delete %n dive site(s)", "", sites.size())); +} + +bool DeleteDiveSites::workToBeDone() +{ + return !sitesToRemove.empty(); +} + +void DeleteDiveSites::redo() +{ + sitesToAdd = std::move(removeDiveSites(sitesToRemove)); +} + +void DeleteDiveSites::undo() +{ + sitesToRemove = std::move(addDiveSites(sitesToAdd)); +} + +} // namespace Command diff --git a/desktop-widgets/command_divesite.h b/desktop-widgets/command_divesite.h new file mode 100644 index 000000000..9c4f93058 --- /dev/null +++ b/desktop-widgets/command_divesite.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0 +// Note: this header file is used by the undo-machinery and should not be included elsewhere. + +#ifndef COMMAND_DIVESITE_H +#define COMMAND_DIVESITE_H + +#include "command_base.h" + +#include <QVector> + +// We put everything in a namespace, so that we can shorten names without polluting the global namespace +namespace Command { + +class DeleteDiveSites : public Base { +public: + DeleteDiveSites(const QVector<dive_site *> &sites); +private: + bool workToBeDone() override; + + // For redo + std::vector<dive_site *> sitesToRemove; + + // For undo + std::vector<OwningDiveSitePtr> sitesToAdd; + void undo() override; + void redo() override; +}; + +} // namespace Command + +#endif // COMMAND_DIVESITE_H diff --git a/qt-models/divelocationmodel.cpp b/qt-models/divelocationmodel.cpp index 383de43ca..ebdffc185 100644 --- a/qt-models/divelocationmodel.cpp +++ b/qt-models/divelocationmodel.cpp @@ -5,8 +5,12 @@ #include "core/qthelper.h" #include "core/divesite.h" #include "core/metrics.h" +#ifndef SUBSURFACE_MOBILE #include "cleanertablemodel.h" // for trashIcon(); -#include <QDebug> +#include "desktop-widgets/mainwindow.h" // to place message box +#include "desktop-widgets/command.h" +#include <QMessageBox> +#endif #include <QLineEdit> #include <QIcon> #include <core/gettextfromc.h> @@ -219,6 +223,25 @@ QStringList DiveSiteSortedModel::allSiteNames() const return locationNames; } +#ifndef SUBSURFACE_MOBILE +// TODO: Remove from model. It doesn't make sense to call the model here, which calls the undo command, +// which in turn calls the model. +void DiveSiteSortedModel::remove(const QModelIndex &index) +{ + if (index.column() != LocationInformationModel::REMOVE) + return; + struct dive_site *ds = get_dive_site(mapToSource(index).row(), &dive_site_table); + if (!ds) + return; + if (ds->dives.nr > 0 && + QMessageBox::warning(MainWindow::instance(), tr("Delete dive site?"), + tr("This dive site has %n dive(s). Do you really want to delete it?\n", "", ds->dives.nr), + QMessageBox::Yes|QMessageBox::No) == QMessageBox::No) + return; + Command::deleteDiveSites(QVector<dive_site *>{ds}); +} +#endif + GeoReferencingOptionsModel *GeoReferencingOptionsModel::instance() { static GeoReferencingOptionsModel *self = new GeoReferencingOptionsModel(); diff --git a/qt-models/divelocationmodel.h b/qt-models/divelocationmodel.h index f2bcc7cf7..34ac34c04 100644 --- a/qt-models/divelocationmodel.h +++ b/qt-models/divelocationmodel.h @@ -42,6 +42,8 @@ class DiveSiteSortedModel : public QSortFilterProxyModel { private: bool filterAcceptsRow(int sourceRow, const QModelIndex &source_parent) const override; bool lessThan(const QModelIndex &i1, const QModelIndex &i2) const override; +public slots: + void remove(const QModelIndex &index); public: DiveSiteSortedModel(); QStringList allSiteNames() const; |