diff options
author | Berthold Stoeger <bstoeger@mail.tuwien.ac.at> | 2019-01-25 18:27:31 +0100 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2019-04-12 18:19:07 +0300 |
commit | 9e603cbe2bbcae1822859b284c39dd804bf321fb (patch) | |
tree | 9b4091c07aeea8b4abe65593ab07abc2c7326a52 /desktop-widgets/command_edit.cpp | |
parent | 8858bfa1f8cf30cc4eb070fb6e709f7051e61241 (diff) | |
download | subsurface-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.cpp | 93 |
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 |