summaryrefslogtreecommitdiffstats
path: root/commands
diff options
context:
space:
mode:
authorGravatar Berthold Stoeger <bstoeger@mail.tuwien.ac.at>2020-02-23 11:43:50 +0100
committerGravatar Berthold Stoeger <bstoeger@mail.tuwien.ac.at>2020-04-07 00:13:34 +0200
commitaa7b0cadb2f737e65d490f4ad026f5df09a394f0 (patch)
tree8dae2a4a9a002e2e3e7d82e420de62e84d0c8020 /commands
parent36754d3399dab9155fac50e9451dcd325c7c73c0 (diff)
downloadsubsurface-aa7b0cadb2f737e65d490f4ad026f5df09a394f0.tar.gz
undo: add cylinder undo commands by copy & paste
Do a simple copy & paste followed by a simple search & replace to generate cylinder undo commands from weight undo commands. Obviously, this is still missing the necessary code to keep the dive-data consistent after cylinder editing. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Diffstat (limited to 'commands')
-rw-r--r--commands/command.cpp15
-rw-r--r--commands/command.h3
-rw-r--r--commands/command_edit.cpp180
-rw-r--r--commands/command_edit.h40
4 files changed, 237 insertions, 1 deletions
diff --git a/commands/command.cpp b/commands/command.cpp
index 1fb968778..5d71e6725 100644
--- a/commands/command.cpp
+++ b/commands/command.cpp
@@ -293,6 +293,21 @@ int editWeight(int index, weightsystem_t ws, bool currentDiveOnly)
return execute_edit(new EditWeight(index, ws, currentDiveOnly));
}
+int addCylinder(bool currentDiveOnly)
+{
+ return execute_edit(new AddCylinder(currentDiveOnly));
+}
+
+int removeCylinder(int index, bool currentDiveOnly)
+{
+ return execute_edit(new RemoveCylinder(index, currentDiveOnly));
+}
+
+int editCylinder(int index, cylinder_t cyl, bool currentDiveOnly)
+{
+ return execute_edit(new EditCylinder(index, cyl, currentDiveOnly));
+}
+
// Trip editing related commands
void editTripLocation(dive_trip *trip, const QString &s)
{
diff --git a/commands/command.h b/commands/command.h
index e19d093cb..b8024c03d 100644
--- a/commands/command.h
+++ b/commands/command.h
@@ -90,6 +90,9 @@ void editProfile(dive *d); // dive computer(s) and cylinder(s) will be reset!
int addWeight(bool currentDiveOnly);
int removeWeight(int index, bool currentDiveOnly);
int editWeight(int index, weightsystem_t ws, bool currentDiveOnly);
+int addCylinder(bool currentDiveOnly);
+int removeCylinder(int index, bool currentDiveOnly);
+int editCylinder(int index, cylinder_t cyl, bool currentDiveOnly);
#ifdef SUBSURFACE_MOBILE
// Edits a dive and creates a divesite (if createDs != NULL) or edits a divesite (if changeDs != NULL).
// Takes ownership of newDive and createDs!
diff --git a/commands/command_edit.cpp b/commands/command_edit.cpp
index 46c206c98..c06ef1ffa 100644
--- a/commands/command_edit.cpp
+++ b/commands/command_edit.cpp
@@ -8,6 +8,7 @@
#include "core/subsurface-string.h"
#include "core/tag.h"
#include "qt-models/weightsysteminfomodel.h"
+#include "qt-models/tankinfomodel.h"
#ifdef SUBSURFACE_MOBILE
#include "qt-models/divelocationmodel.h"
#endif
@@ -917,6 +918,7 @@ bool EditWeightBase::workToBeDone()
return !dives.empty();
}
+// ***** Remove Weight *****
RemoveWeight::RemoveWeight(int index, bool currentDiveOnly) :
EditWeightBase(index, currentDiveOnly)
{
@@ -943,6 +945,7 @@ void RemoveWeight::redo()
}
}
+// ***** Edit Weight *****
EditWeight::EditWeight(int index, weightsystem_t wsIn, bool currentDiveOnly) :
EditWeightBase(index, currentDiveOnly),
new_ws(empty_weightsystem)
@@ -999,6 +1002,183 @@ void EditWeight::undo()
redo();
}
+// ***** Add Cylinder *****
+AddCylinder::AddCylinder(bool currentDiveOnly) :
+ EditDivesBase(currentDiveOnly),
+ cyl(empty_cylinder)
+{
+ if (dives.empty())
+ return;
+ else if (dives.size() == 1)
+ setText(tr("Add cylinder"));
+ else
+ setText(tr("Add cylinder (%n dive(s))", "", dives.size()));
+ cyl = create_new_cylinder(dives[0]);
+}
+
+AddCylinder::~AddCylinder()
+{
+ free_cylinder(cyl);
+}
+
+bool AddCylinder::workToBeDone()
+{
+ return true;
+}
+
+void AddCylinder::undo()
+{
+ for (dive *d: dives) {
+ if (d->cylinders.nr <= 0)
+ continue;
+ remove_cylinder(d, d->cylinders.nr - 1);
+ emit diveListNotifier.cylinderRemoved(d, d->cylinders.nr);
+ }
+}
+
+void AddCylinder::redo()
+{
+ for (dive *d: dives) {
+ add_cloned_cylinder(&d->cylinders, cyl);
+ emit diveListNotifier.cylinderAdded(d, d->cylinders.nr - 1);
+ }
+}
+
+static int find_cylinder_index(const struct dive *d, const cylinder_t &cyl)
+{
+ for (int idx = 0; idx < d->cylinders.nr; ++idx) {
+ if (same_cylinder(d->cylinders.cylinders[idx], cyl))
+ return idx;
+ }
+ return -1;
+}
+
+EditCylinderBase::EditCylinderBase(int index, bool currentDiveOnly) :
+ EditDivesBase(currentDiveOnly),
+ cyl(empty_cylinder)
+{
+ // Get the old cylinder, bail if index is invalid
+ if (!current || index < 0 || index >= current->cylinders.nr) {
+ dives.clear();
+ return;
+ }
+ cyl = clone_cylinder(current->cylinders.cylinders[index]);
+
+ std::vector<dive *> divesNew;
+ divesNew.reserve(dives.size());
+ indexes.reserve(dives.size());
+
+ for (dive *d: dives) {
+ if (d == current) {
+ divesNew.push_back(d);
+ indexes.push_back(index);
+ continue;
+ }
+ int idx = find_cylinder_index(d, cyl);
+ if (idx >= 0) {
+ divesNew.push_back(d);
+ indexes.push_back(idx);
+ }
+ }
+ dives = std::move(divesNew);
+}
+
+EditCylinderBase::~EditCylinderBase()
+{
+ free_cylinder(cyl);
+}
+
+bool EditCylinderBase::workToBeDone()
+{
+ return !dives.empty();
+}
+
+// ***** Remove Cylinder *****
+RemoveCylinder::RemoveCylinder(int index, bool currentDiveOnly) :
+ EditCylinderBase(index, currentDiveOnly)
+{
+ if (dives.size() == 1)
+ setText(tr("Remove cylinder"));
+ else
+ setText(tr("Remove cylinder (%n dive(s))", "", dives.size()));
+}
+
+void RemoveCylinder::undo()
+{
+ for (size_t i = 0; i < dives.size(); ++i) {
+ add_to_cylinder_table(&dives[i]->cylinders, indexes[i], clone_cylinder(cyl));
+ emit diveListNotifier.cylinderAdded(dives[i], indexes[i]);
+ }
+}
+
+void RemoveCylinder::redo()
+{
+ for (size_t i = 0; i < dives.size(); ++i) {
+ remove_cylinder(dives[i], indexes[i]);
+ emit diveListNotifier.cylinderRemoved(dives[i], indexes[i]);
+ }
+}
+
+// ***** Edit Cylinder *****
+EditCylinder::EditCylinder(int index, cylinder_t cylIn, bool currentDiveOnly) :
+ EditCylinderBase(index, currentDiveOnly),
+ new_cyl(empty_cylinder)
+{
+ if (dives.empty())
+ return;
+
+ if (dives.size() == 1)
+ setText(tr("Edit cylinder"));
+ else
+ setText(tr("Edit cylinder (%n dive(s))", "", dives.size()));
+
+ // Try to untranslate the cylinder type
+ new_cyl = clone_cylinder(cylIn);
+ QString vString(new_cyl.type.description);
+ for (int i = 0; i < MAX_TANK_INFO && tank_info[i].name; ++i) {
+ if (gettextFromC::tr(tank_info[i].name) == vString) {
+ free_cylinder(new_cyl);
+ new_cyl.type.description = copy_string(tank_info[i].name);
+ break;
+ }
+ }
+
+ // If that doesn't change anything, do nothing
+ if (same_cylinder(cyl, new_cyl)) {
+ dives.clear();
+ return;
+ }
+
+ TankInfoModel *tim = TankInfoModel::instance();
+ QModelIndexList matches = tim->match(tim->index(0, 0), Qt::DisplayRole, gettextFromC::tr(new_cyl.type.description));
+ if (!matches.isEmpty()) {
+ if (new_cyl.type.size.mliter != cyl.type.size.mliter)
+ tim->setData(tim->index(matches.first().row(), TankInfoModel::ML), new_cyl.type.size.mliter);
+ if (new_cyl.type.workingpressure.mbar != cyl.type.workingpressure.mbar)
+ tim->setData(tim->index(matches.first().row(), TankInfoModel::BAR), new_cyl.type.workingpressure.mbar / 1000.0);
+ }
+}
+
+EditCylinder::~EditCylinder()
+{
+ free_cylinder(new_cyl);
+}
+
+void EditCylinder::redo()
+{
+ for (size_t i = 0; i < dives.size(); ++i) {
+ set_cylinder(dives[i], indexes[i], new_cyl);
+ emit diveListNotifier.cylinderEdited(dives[i], indexes[i]);
+ }
+ std::swap(cyl, new_cyl);
+}
+
+// Undo and redo do the same as just the stored value is exchanged
+void EditCylinder::undo()
+{
+ redo();
+}
+
#ifdef SUBSURFACE_MOBILE
EditDive::EditDive(dive *oldDiveIn, dive *newDiveIn, dive_site *createDs, dive_site *editDs, location_t dsLocationIn)
diff --git a/commands/command_edit.h b/commands/command_edit.h
index e99ce2407..88f359fba 100644
--- a/commands/command_edit.h
+++ b/commands/command_edit.h
@@ -377,6 +377,45 @@ private:
void redo() override;
};
+class AddCylinder : public EditDivesBase {
+public:
+ AddCylinder(bool currentDiveOnly);
+ ~AddCylinder();
+private:
+ cylinder_t cyl;
+ void undo() override;
+ void redo() override;
+ bool workToBeDone() override;
+};
+
+class EditCylinderBase : public EditDivesBase {
+protected:
+ EditCylinderBase(int index, bool currentDiveOnly);
+ ~EditCylinderBase();
+
+ cylinder_t cyl;
+ std::vector<int> indexes; // An index for each dive in the dives vector.
+ bool workToBeDone() override;
+};
+
+class RemoveCylinder : public EditCylinderBase {
+public:
+ RemoveCylinder(int index, bool currentDiveOnly);
+private:
+ void undo() override;
+ void redo() override;
+};
+
+class EditCylinder : public EditCylinderBase {
+public:
+ EditCylinder(int index, cylinder_t cyl, bool currentDiveOnly); // Clones cylinder
+ ~EditCylinder();
+private:
+ cylinder_t new_cyl;
+ void undo() override;
+ void redo() override;
+};
+
#ifdef SUBSURFACE_MOBILE
// Edit a full dive. This is used on mobile where we don't have per-field granularity.
// It may add or edit a dive site.
@@ -406,5 +445,4 @@ private:
#endif // SUBSURFACE_MOBILE
} // namespace Command
-
#endif