summaryrefslogtreecommitdiffstats
path: root/commands
diff options
context:
space:
mode:
authorGravatar Berthold Stoeger <bstoeger@mail.tuwien.ac.at>2020-01-10 08:25:37 +0800
committerGravatar Dirk Hohndel <dirk@hohndel.org>2020-03-10 09:25:57 -0700
commit57b96490b2c5b81023439046dea225b8caf09946 (patch)
tree3c5a811d23fbd80720de18331786ab1b56222407 /commands
parent200932189451d52e277004871004e3b2a0593e58 (diff)
downloadsubsurface-57b96490b2c5b81023439046dea225b8caf09946.tar.gz
mobile/undo: create EditDive command
Command that just swaps two dives. This is rather complex, as for example a dive site might be created. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Diffstat (limited to 'commands')
-rw-r--r--commands/command.cpp7
-rw-r--r--commands/command.h5
-rw-r--r--commands/command_edit.cpp133
-rw-r--r--commands/command_edit.h27
4 files changed, 172 insertions, 0 deletions
diff --git a/commands/command.cpp b/commands/command.cpp
index aa1d18183..47fc45b90 100644
--- a/commands/command.cpp
+++ b/commands/command.cpp
@@ -304,4 +304,11 @@ void editTripNotes(dive_trip *trip, const QString &s)
execute(new EditTripNotes(trip, s));
}
+#ifdef SUBSURFACE_MOBILE
+void editDive(dive *oldDive, dive *newDive, dive_site *createDs, dive_site *changeDs, location_t dsLocation)
+{
+ execute(new EditDive(oldDive, newDive, createDs, changeDs, dsLocation));
+}
+#endif // SUBSURFACE_MOBILE
+
} // namespace Command
diff --git a/commands/command.h b/commands/command.h
index 281c1635c..00de1425a 100644
--- a/commands/command.h
+++ b/commands/command.h
@@ -89,6 +89,11 @@ 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);
+#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!
+void editDive(dive *oldDive, dive *newDive, dive_site *createDs, dive_site *changeDs, location_t dsLocation);
+#endif
// 5) Trip editing commands
diff --git a/commands/command_edit.cpp b/commands/command_edit.cpp
index 1a9684e1f..e08f678e7 100644
--- a/commands/command_edit.cpp
+++ b/commands/command_edit.cpp
@@ -7,6 +7,9 @@
#include "core/subsurface-string.h"
#include "core/tag.h"
#include "qt-models/weightsysteminfomodel.h"
+#ifdef SUBSURFACE_MOBILE
+#include "qt-models/divelocationmodel.h"
+#endif
namespace Command {
@@ -1145,4 +1148,134 @@ void EditWeight::undo()
redo();
}
+#ifdef SUBSURFACE_MOBILE
+
+EditDive::EditDive(dive *oldDiveIn, dive *newDiveIn, dive_site *createDs, dive_site *editDs, location_t dsLocationIn)
+ : oldDive(oldDiveIn)
+ , newDive(newDiveIn)
+ , changedFields(DiveField::NONE)
+ , siteToRemove(nullptr)
+ , siteToAdd(createDs)
+ , siteToEdit(editDs)
+ , dsLocation(dsLocationIn)
+{
+ if (!oldDive || ! newDive)
+ return;
+
+ setText(tr("Edit dive"));
+
+ // Calculate the fields that changed.
+ // Note: Probably not needed, as on mobile we don't have that granularity.
+ // However, for future-proofeness let's just do it.
+ changedFields = DiveField::NONE;
+ if (oldDive->number != newDive->number)
+ changedFields |= DiveField::NR;
+ if (oldDive->when != newDive->when)
+ changedFields |= DiveField::DATETIME;
+ if (oldDive->maxdepth.mm != newDive->maxdepth.mm)
+ changedFields |= DiveField::DEPTH;
+ if (oldDive->duration.seconds != newDive->duration.seconds)
+ changedFields |= DiveField::DURATION;
+ if (oldDive->airtemp.mkelvin != newDive->airtemp.mkelvin)
+ changedFields |= DiveField::AIR_TEMP;
+ if (oldDive->watertemp.mkelvin != newDive->watertemp.mkelvin)
+ changedFields |= DiveField::WATER_TEMP;
+ if (oldDive->surface_pressure.mbar != newDive->surface_pressure.mbar)
+ changedFields |= DiveField::ATM_PRESS;
+ if (oldDive->dive_site != newDive->dive_site)
+ changedFields |= DiveField::DIVESITE;
+ if (!same_string(oldDive->divemaster, newDive->divemaster))
+ changedFields |= DiveField::DIVEMASTER;
+ if (!same_string(oldDive->buddy, newDive->buddy))
+ changedFields |= DiveField::BUDDY;
+ if (oldDive->rating != newDive->rating)
+ changedFields |= DiveField::RATING;
+ if (oldDive->visibility != newDive->visibility)
+ changedFields |= DiveField::VISIBILITY;
+ if (oldDive->wavesize != newDive->wavesize)
+ changedFields |= DiveField::WAVESIZE;
+ if (oldDive->current != newDive->current)
+ changedFields |= DiveField::CURRENT;
+ if (oldDive->surge != newDive->surge)
+ changedFields |= DiveField::SURGE;
+ if (oldDive->chill != newDive->chill)
+ changedFields |= DiveField::CHILL;
+ if (!same_string(oldDive->suit, newDive->suit))
+ changedFields |= DiveField::SUIT;
+ if (get_taglist_string(oldDive->tag_list) != get_taglist_string(newDive->tag_list)) // This is cheating. Do we have a taglist comparison function?
+ changedFields |= DiveField::TAGS;
+ if (oldDive->dc.divemode != newDive->dc.divemode)
+ changedFields |= DiveField::MODE;
+ if (!same_string(oldDive->notes, newDive->notes))
+ changedFields |= DiveField::NOTES;
+ if (oldDive->salinity != newDive->salinity)
+ changedFields |= DiveField::SALINITY;
+}
+
+void EditDive::undo()
+{
+ if (siteToRemove) {
+ int idx = unregister_dive_site(siteToRemove);
+ siteToAdd.reset(siteToRemove);
+ emit diveListNotifier.diveSiteDeleted(siteToRemove, idx); // Inform frontend of removed dive site.
+ }
+
+ exchangeDives();
+ editDs();
+}
+
+void EditDive::redo()
+{
+ if (siteToAdd) {
+ siteToRemove = siteToAdd.get();
+ int idx = register_dive_site(siteToAdd.release()); // Return ownership to backend.
+ emit diveListNotifier.diveSiteAdded(siteToRemove, idx); // Inform frontend of new dive site.
+ }
+
+ exchangeDives();
+ editDs();
+}
+
+void EditDive::exchangeDives()
+{
+ // Bluntly exchange dive data by shallow copy
+ std::swap(*newDive, *oldDive);
+ invalidate_dive_cache(oldDive);
+
+ // Changing times may have unsorted the dive and trip tables
+ QVector<dive *> dives = { oldDive };
+ timestamp_t delta = oldDive->when - newDive->when;
+ if (delta != 0) {
+ sort_dive_table(&dive_table);
+ sort_trip_table(&trip_table);
+ if (newDive->divetrip != oldDive->divetrip)
+ qWarning("Command::EditDive::redo(): This command does not support moving between trips!");
+ if (oldDive->divetrip)
+ sort_dive_table(&newDive->divetrip->dives); // Keep the trip-table in order
+ emit diveListNotifier.divesTimeChanged(delta, dives);
+ }
+
+ // Send signals
+ emit diveListNotifier.divesChanged(dives, changedFields);
+
+ // Select the changed dives
+ setSelection( { oldDive }, oldDive);
+}
+
+void EditDive::editDs()
+{
+ if (siteToEdit) {
+ std::swap(siteToEdit->location, dsLocation);
+ emit diveListNotifier.diveSiteChanged(siteToEdit, LocationInformationModel::LOCATION); // Inform frontend of changed dive site.
+ }
+}
+
+bool EditDive::workToBeDone()
+{
+ // We trust the frontend that an EditDive command is only created if there are changes.
+ return true;
+}
+
+#endif // SUBSURFACE_MOBILE
+
} // namespace Command
diff --git a/commands/command_edit.h b/commands/command_edit.h
index a148550b3..aeecc0bab 100644
--- a/commands/command_edit.h
+++ b/commands/command_edit.h
@@ -375,6 +375,33 @@ private:
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.
+class EditDive : public Base {
+public:
+ EditDive(dive *oldDive, dive *newDive, dive_site *createDs, dive_site *editDs, location_t dsLocation); // Takes ownership of newDive
+private:
+ dive *oldDive; // Dive that is going to be overwritten
+ OwningDivePtr newDive; // New data
+ int changedFields;
+
+ dive_site *siteToRemove;
+ OwningDiveSitePtr siteToAdd;
+
+ dive_site *siteToEdit;
+ location_t dsLocation;
+
+ void undo() override;
+ void redo() override;
+ bool workToBeDone() override;
+
+ void exchangeDives();
+ void editDs();
+};
+
+#endif // SUBSURFACE_MOBILE
+
} // namespace Command
#endif