summaryrefslogtreecommitdiffstats
path: root/desktop-widgets
diff options
context:
space:
mode:
authorGravatar Berthold Stoeger <bstoeger@mail.tuwien.ac.at>2018-11-26 22:06:17 +0100
committerGravatar Dirk Hohndel <dirk@hohndel.org>2019-01-09 20:58:04 -0800
commit7df8d8c888cb8e1cdb12a171a4715c8f5af7c80d (patch)
tree1a397c5d9c448a8b6c0c3d5771fd7d981bc0b763 /desktop-widgets
parent517fb7a462c207e32cc7c5ed50e1e9b1f359dbd8 (diff)
downloadsubsurface-7df8d8c888cb8e1cdb12a171a4715c8f5af7c80d.tar.gz
Undo commands: refactor dive-trip handling
Trips were added to the core with the first dive of that trip. With the recent changes that keep trips ordered by first dive, this became counter-productive. Keeping a consistent state at all times would mean resorting the trip table for every dive that is added. Instead, add all dives to a trip and *then* add the trip to the core. Change the data-structures to not register trips-to-be-added with individual dives, but keep them in a separate vector for each undo command. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Diffstat (limited to 'desktop-widgets')
-rw-r--r--desktop-widgets/command_divelist.cpp93
-rw-r--r--desktop-widgets/command_divelist.h33
2 files changed, 67 insertions, 59 deletions
diff --git a/desktop-widgets/command_divelist.cpp b/desktop-widgets/command_divelist.cpp
index b3c4f24e3..c00935912 100644
--- a/desktop-widgets/command_divelist.cpp
+++ b/desktop-widgets/command_divelist.cpp
@@ -42,9 +42,10 @@ void processByTrip(std::vector<std::pair<dive_trip *, dive *>> &dives, Function
// This helper function removes a dive, takes ownership of the dive and adds it to a DiveToAdd structure.
+// If the trip the dive belongs to becomes empty, it is removed and added to the tripsToAdd vector.
// It is crucial that dives are added in reverse order of deletion, so the the indices are correctly
// set and that the trips are added before they are used!
-DiveToAdd DiveListBase::removeDive(struct dive *d)
+DiveToAdd DiveListBase::removeDive(struct dive *d, std::vector<OwningTripPtr> &tripsToAdd)
{
// If the dive to be removed is selected, we will inform the frontend
// later via a signal that the dive changed.
@@ -68,7 +69,7 @@ DiveToAdd DiveListBase::removeDive(struct dive *d)
res.trip = unregister_dive_from_trip(d);
if (res.trip && res.trip->dives.nr == 0) {
unregister_trip(res.trip); // Remove trip from backend
- res.tripToAdd.reset(res.trip); // Take ownership of trip
+ tripsToAdd.emplace_back(res.trip); // Take ownership of trip
}
res.dive.reset(unregister_dive(res.idx)); // Remove dive from backend
@@ -83,8 +84,6 @@ dive *DiveListBase::addDive(DiveToAdd &d)
{
if (d.trip)
add_dive_to_trip(d.dive.get(), d.trip);
- if (d.tripToAdd)
- insert_trip(d.tripToAdd.release()); // Return ownership to backend
dive *res = d.dive.release(); // Give up ownership of dive
// Set the filter flag according to current filter settings
@@ -104,67 +103,70 @@ dive *DiveListBase::addDive(DiveToAdd &d)
// This helper function calls removeDive() on a list of dives to be removed and
// returns a vector of corresponding DiveToAdd objects, which can later be readded.
+// Moreover, a vector of deleted trips is returned, if trips became empty.
// The passed in vector is cleared.
-std::vector<DiveToAdd> DiveListBase::removeDives(std::vector<dive *> &divesToDelete)
+DivesAndTripsToAdd DiveListBase::removeDives(std::vector<dive *> &divesToDelete)
{
- std::vector<DiveToAdd> res;
- res.reserve(divesToDelete.size());
+ std::vector<DiveToAdd> divesToAdd;
+ std::vector<OwningTripPtr> tripsToAdd;
+ divesToAdd.reserve(divesToDelete.size());
for (dive *d: divesToDelete)
- res.push_back(removeDive(d));
+ divesToAdd.push_back(removeDive(d, tripsToAdd));
divesToDelete.clear();
// We send one dives-deleted signal per trip (see comments in DiveListNotifier.h).
// Therefore, collect all dives in an array and sort by trip.
std::vector<std::pair<dive_trip *, dive *>> dives;
- dives.reserve(res.size());
- for (const DiveToAdd &entry: res)
+ dives.reserve(divesToAdd.size());
+ for (const DiveToAdd &entry: divesToAdd)
dives.push_back({ entry.trip, entry.dive.get() });
// Send signals.
processByTrip(dives, [&](dive_trip *trip, const QVector<dive *> &divesInTrip) {
- // Now, let's check if this trip is supposed to be deleted, by checking if it was marked
- // as "add it". We could be smarter here, but let's just check the whole array for brevity.
+ // Check if this trip is supposed to be deleted, by checking if it was marked as "add it".
bool deleteTrip = trip &&
- std::find_if(res.begin(), res.end(), [trip](const DiveToAdd &entry)
- { return entry.tripToAdd.get() == trip; }) != res.end();
+ std::find_if(tripsToAdd.begin(), tripsToAdd.end(), [trip](const OwningTripPtr &ptr)
+ { return ptr.get() == trip; }) != tripsToAdd.end();
emit diveListNotifier.divesDeleted(trip, deleteTrip, divesInTrip);
});
- return res;
+ return { std::move(divesToAdd), std::move(tripsToAdd) };
}
// This helper function is the counterpart fo removeDives(): it calls addDive() on a list
// of dives to be (re)added and returns a vector of the added dives. It does this in reverse
// order, so that trips are created appropriately and indexing is correct.
// The passed in vector is cleared.
-std::vector<dive *> DiveListBase::addDives(std::vector<DiveToAdd> &divesToAdd)
+std::vector<dive *> DiveListBase::addDives(DivesAndTripsToAdd &toAdd)
{
std::vector<dive *> res;
- res.resize(divesToAdd.size());
+ res.resize(toAdd.dives.size());
// First, tell the filters that new dives are added. We do this here
// instead of later by signals, so that the filter can set the
// checkboxes of the new rows to its liking. The added dives will
// then appear in the correct shown/hidden state.
QVector<dive *> divesForFilter;
- for (const DiveToAdd &entry: divesToAdd)
+ for (const DiveToAdd &entry: toAdd.dives)
divesForFilter.push_back(entry.dive.get());
- // At the end of the function, to send the proper dives-added signals,
- // we the the list of added trips. Create this list now.
- std::vector<dive_trip *> addedTrips;
- for (const DiveToAdd &entry: divesToAdd) {
- if (entry.tripToAdd)
- addedTrips.push_back(entry.tripToAdd.get());
- }
-
// Now, add the dives
// Note: the idiomatic STL-way would be std::transform, but let's use a loop since
// that is closer to classical C-style.
auto it2 = res.rbegin();
- for (auto it = divesToAdd.rbegin(); it != divesToAdd.rend(); ++it, ++it2)
+ for (auto it = toAdd.dives.rbegin(); it != toAdd.dives.rend(); ++it, ++it2)
*it2 = addDive(*it);
- divesToAdd.clear();
+ toAdd.dives.clear();
+
+ // If the dives belong to new trips, add these as well.
+ // Remember the pointers so that we can later check if a trip was newly added
+ std::vector<dive_trip *> addedTrips;
+ addedTrips.reserve(toAdd.trips.size());
+ for (OwningTripPtr &trip: toAdd.trips) {
+ addedTrips.push_back(trip.get());
+ insert_trip(trip.release()); // Return ownership to backend
+ }
+ toAdd.trips.clear();
// We send one dives-deleted signal per trip (see comments in DiveListNotifier.h).
// Therefore, collect all dives in a array and sort by trip.
@@ -175,8 +177,7 @@ std::vector<dive *> DiveListBase::addDives(std::vector<DiveToAdd> &divesToAdd)
// Send signals.
processByTrip(dives, [&](dive_trip *trip, const QVector<dive *> &divesInTrip) {
- // Now, let's check if this trip is supposed to be created, by checking if it was marked
- // as "add it". We could be smarter here, but let's just check the whole array for brevity.
+ // Now, let's check if this trip is supposed to be created, by checking if it was marked as "add it".
bool createTrip = trip && std::find(addedTrips.begin(), addedTrips.end(), trip) != addedTrips.end();
// Finally, emit the signal
emit diveListNotifier.divesAdded(trip, createTrip, divesInTrip);
@@ -515,7 +516,9 @@ AddDive::AddDive(dive *d, bool autogroup, bool newNumber)
if (newNumber)
divePtr->number = get_dive_nr_at_idx(idx);
- divesToAdd.push_back({ std::move(divePtr), std::move(allocTrip), trip, idx });
+ divesToAdd.dives.push_back({ std::move(divePtr), trip, idx });
+ if (allocTrip)
+ divesToAdd.trips.push_back(std::move(allocTrip));
}
bool AddDive::workToBeDone()
@@ -584,8 +587,8 @@ void DeleteDive::redoit()
// Deselect all dives and select dive that was close to the first deleted dive
dive *newCurrent = nullptr;
- if (!divesToAdd.empty()) {
- timestamp_t when = divesToAdd[0].dive->when;
+ if (!divesToAdd.dives.empty()) {
+ timestamp_t when = divesToAdd.dives[0].dive->when;
newCurrent = find_next_visible_dive(when);
}
if (newCurrent)
@@ -772,13 +775,13 @@ SplitDives::SplitDives(dive *d, duration_t time)
new2->selected = false;
diveToSplit.push_back(d);
- splitDives.resize(2);
- splitDives[0].dive.reset(new1);
- splitDives[0].trip = d->divetrip;
- splitDives[0].idx = idx;
- splitDives[1].dive.reset(new2);
- splitDives[1].trip = d->divetrip;
- splitDives[1].idx = idx + 1;
+ splitDives.dives.resize(2);
+ splitDives.dives[0].dive.reset(new1);
+ splitDives.dives[0].trip = d->divetrip;
+ splitDives.dives[0].idx = idx;
+ splitDives.dives[1].dive.reset(new2);
+ splitDives.dives[1].trip = d->divetrip;
+ splitDives.dives[1].idx = idx + 1;
}
bool SplitDives::workToBeDone()
@@ -882,16 +885,16 @@ MergeDives::MergeDives(const QVector <dive *> &dives)
}
}
- mergedDive.resize(1);
- mergedDive[0].dive = std::move(d);
- mergedDive[0].idx = get_divenr(dives[0]);
- mergedDive[0].trip = preferred_trip;
+ mergedDive.dives.resize(1);
+ mergedDive.dives[0].dive = std::move(d);
+ mergedDive.dives[0].idx = get_divenr(dives[0]);
+ mergedDive.dives[0].trip = preferred_trip;
divesToMerge = dives.toStdVector();
}
bool MergeDives::workToBeDone()
{
- return !mergedDive.empty();
+ return !mergedDive.dives.empty();
}
void MergeDives::redoit()
diff --git a/desktop-widgets/command_divelist.h b/desktop-widgets/command_divelist.h
index 29c9c6e7b..77116c302 100644
--- a/desktop-widgets/command_divelist.h
+++ b/desktop-widgets/command_divelist.h
@@ -15,11 +15,16 @@ namespace Command {
// Potentially it also adds a trip (if deletion of the dive resulted in deletion of the trip)
struct DiveToAdd {
OwningDivePtr dive; // Dive to add
- OwningTripPtr tripToAdd; // Not-null if we also have to add a dive
dive_trip *trip; // Trip the dive belongs to, may be null
int idx; // Position in divelist
};
+// Multiple trips and dives that have to be added for a command
+struct DivesAndTripsToAdd {
+ std::vector<DiveToAdd> dives;
+ std::vector<OwningTripPtr> trips;
+};
+
// This helper structure describes a dive that should be moved to / removed from
// a trip. If the "trip" member is null, the dive is removed from its trip (if
// it is in a trip, that is)
@@ -29,7 +34,7 @@ struct DiveToTrip
dive_trip *trip;
};
-// This helper structure describes a number of dives to add to /remove from /
+// This helper structure describes a number of dives to add to / remove from /
// move between trips.
// It has ownership of the trips (if any) that have to be added before hand.
struct DivesToTrip
@@ -51,10 +56,10 @@ protected:
// These are helper functions to add / remove dive from the C-core structures,
// which set the selectionChanged flag if the added / removed dive was selected.
- DiveToAdd removeDive(struct dive *d);
+ DiveToAdd removeDive(struct dive *d, std::vector<OwningTripPtr> &tripsToAdd);
dive *addDive(DiveToAdd &d);
- std::vector<DiveToAdd> removeDives(std::vector<dive *> &divesToDelete);
- std::vector<dive *> addDives(std::vector<DiveToAdd> &divesToAdd);
+ DivesAndTripsToAdd removeDives(std::vector<dive *> &divesToDelete);
+ std::vector<dive *> addDives(DivesAndTripsToAdd &toAdd);
// Set the selection to a given state. Set the selectionChanged flag if anything changed.
void restoreSelection(const std::vector<dive *> &selection, dive *currentDive);
@@ -89,9 +94,9 @@ private:
bool workToBeDone() override;
// For redo
- // Note: we use a vector even though we add only a single dive, so
+ // Note: we a multi-dive structure even though we add only a single dive, so
// that we can reuse the multi-dive functions of the other commands.
- std::vector<DiveToAdd> divesToAdd;
+ DivesAndTripsToAdd divesToAdd;
// For undo
std::vector<dive *> divesToRemove;
@@ -111,7 +116,7 @@ private:
std::vector<struct dive*> divesToDelete;
std::vector<OwningTripPtr> tripsToAdd;
- std::vector<DiveToAdd> divesToAdd;
+ DivesAndTripsToAdd divesToAdd;
};
class ShiftTime : public DiveListBase {
@@ -185,13 +190,13 @@ private:
// Note: we use a vector even though we split only a single dive, so
// that we can reuse the multi-dive functions of the other commands.
std::vector<dive *> diveToSplit;
- std::vector<DiveToAdd> splitDives;
+ DivesAndTripsToAdd splitDives;
// For undo
// For each dive to unsplit, we remove two dives from and add one into the backend
- // Note: we use a vector even though we unsplit only a single dive, so
+ // Note: we use a multi-dive structure even though we unsplit only a single dive, so
// that we can reuse the multi-dive functions of the other commands.
- std::vector<DiveToAdd> unsplitDive;
+ DivesAndTripsToAdd unsplitDive;
std::vector<dive *> divesToUnsplit;
};
@@ -205,9 +210,9 @@ private:
// For redo
// Add one and remove a batch of dives
- // Note: we use a vector even though we add only a single dive, so
+ // Note: we use a multi-dives structure even though we add only a single dive, so
// that we can reuse the multi-dive functions of the other commands.
- std::vector<DiveToAdd> mergedDive;
+ DivesAndTripsToAdd mergedDive;
std::vector<dive *> divesToMerge;
// For undo
@@ -215,7 +220,7 @@ private:
// Note: we use a vector even though we remove only a single dive, so
// that we can reuse the multi-dive functions of the other commands.
std::vector<dive *> diveToUnmerge;
- std::vector<DiveToAdd> unmergedDives;
+ DivesAndTripsToAdd unmergedDives;
// For undo and redo
QVector<QPair<dive *, int>> divesToRenumber;