summaryrefslogtreecommitdiffstats
path: root/desktop-widgets/command_edit.cpp
diff options
context:
space:
mode:
authorGravatar Berthold Stoeger <bstoeger@mail.tuwien.ac.at>2019-01-25 18:27:31 +0100
committerGravatar Dirk Hohndel <dirk@hohndel.org>2019-04-12 18:19:07 +0300
commit9e603cbe2bbcae1822859b284c39dd804bf321fb (patch)
tree9b4091c07aeea8b4abe65593ab07abc2c7326a52 /desktop-widgets/command_edit.cpp
parent8858bfa1f8cf30cc4eb070fb6e709f7051e61241 (diff)
downloadsubsurface-9e603cbe2bbcae1822859b284c39dd804bf321fb.tar.gz
Undo: implement rudimentary undo of dive-notes editing
Implement a first rudimentary dive-editing command. The main code resides in a base class Command::Edit, which calls virtual functions to read / set the fields and extract the field name. Implement an example: editing of dive notes. This dose not yet update the UI on undo / redo. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Diffstat (limited to 'desktop-widgets/command_edit.cpp')
-rw-r--r--desktop-widgets/command_edit.cpp93
1 files changed, 93 insertions, 0 deletions
diff --git a/desktop-widgets/command_edit.cpp b/desktop-widgets/command_edit.cpp
new file mode 100644
index 000000000..f39f9339d
--- /dev/null
+++ b/desktop-widgets/command_edit.cpp
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "command_edit.h"
+#include "core/divelist.h"
+
+namespace Command {
+
+template<typename T>
+EditBase<T>::EditBase(const QVector<dive *> &divesIn, T newValue, T oldValue) :
+ value(std::move(newValue)),
+ old(std::move(oldValue)),
+ dives(divesIn.toStdVector())
+{
+ // If there is nothing to do, clear the dives vector.
+ // This signals that no action has to be taken.
+ if (old == value)
+ dives.clear();
+}
+
+// This is quite hackish: we can't use virtual functions in the constructor and
+// therefore can't initialize the list of dives [the values of the dives are
+// accessed by virtual functions]. Therefore, we (mis)use the fact that workToBeDone()
+// is called exactly once before adding the Command to the system and perform this here.
+// To be more explicit about this, we might think about renaming workToBeDone() to init().
+template<typename T>
+bool EditBase<T>::workToBeDone()
+{
+ std::vector<dive *> divesNew;
+ divesNew.reserve(dives.size());
+ for (dive *d: dives) {
+ if (data(d) == old)
+ divesNew.push_back(d);
+ }
+ dives = std::move(divesNew);
+
+ // Create a text for the menu entry. In the case of multiple dives add the number
+ size_t num_dives = dives.size();
+ if (num_dives > 0)
+ //: remove the part in parantheses for %n = 1
+ setText(tr("Edit %1 (%n dive(s))", "", num_dives).arg(fieldName()));
+
+ return num_dives;
+}
+
+template<typename T>
+void EditBase<T>::undo()
+{
+ if (dives.empty()) {
+ qWarning("Edit command called with empty dives list (shouldn't happen)");
+ return;
+ }
+
+ for (dive *d: dives) {
+ set(d, value);
+ invalidate_dive_cache(d); // Ensure that dive is written in git_save()
+ }
+
+ std::swap(old, value);
+
+ mark_divelist_changed(true);
+}
+
+// We have to manually instantiate the constructors of the EditBase class,
+// because the base class is never constructed and the derived classes
+// don't have their own constructor. They simply delegate to the base
+// class by virtue of a "using" declaration.
+template
+EditBase<QString>::EditBase(const QVector<dive *> &dives, QString oldValue, QString newValue);
+
+// Undo and redo do the same as just the stored value is exchanged
+template<typename T>
+void EditBase<T>::redo()
+{
+ undo();
+}
+
+void EditNotes::set(struct dive *d, QString s) const
+{
+ free(d->notes);
+ d->notes = strdup(qPrintable(s));
+}
+
+QString EditNotes::data(struct dive *d) const
+{
+ return QString(d->notes);
+}
+
+QString EditNotes::fieldName() const
+{
+ return tr("notes");
+}
+
+} // namespace Command