From 145f70aab59a5ebd1b4ca82432caf38b4821b055 Mon Sep 17 00:00:00 2001 From: Berthold Stoeger Date: Sun, 31 Mar 2019 10:20:13 +0200 Subject: Undo: implement split-out of dive computer Allow splitting out a dive computer into a distinct dive. This is realized by generating a base class from SplitDive. This turned out to be more cumbersome than expected: we don't know a-priori which of the split dives will come first. Since the undo-command saves the indices where the dives will be insert, these have to be calculated. This is an premature optimization, which makes more pain than necessary. Let's remove it and simply determine the insertion index when executing the command. Original code by Linus Torvalds . Signed-off-by: Berthold Stoeger Signed-off-by: Dirk Hohndel --- desktop-widgets/command.cpp | 5 +++ desktop-widgets/command.h | 1 + desktop-widgets/command_divelist.cpp | 86 +++++++++++++++++++++++++++--------- desktop-widgets/command_divelist.h | 19 ++++++-- 4 files changed, 87 insertions(+), 24 deletions(-) (limited to 'desktop-widgets') diff --git a/desktop-widgets/command.cpp b/desktop-widgets/command.cpp index 84f21265d..638be74d1 100644 --- a/desktop-widgets/command.cpp +++ b/desktop-widgets/command.cpp @@ -66,6 +66,11 @@ void splitDives(dive *d, duration_t time) execute(new SplitDives(d, time)); } +void splitDiveComputer(dive *d, int dc_num) +{ + execute(new SplitDiveComputer(d, dc_num)); +} + void mergeDives(const QVector &dives) { execute(new MergeDives(dives)); diff --git a/desktop-widgets/command.h b/desktop-widgets/command.h index d527fff3b..4c6240a93 100644 --- a/desktop-widgets/command.h +++ b/desktop-widgets/command.h @@ -32,6 +32,7 @@ void createTrip(const QVector &divesToAddIn); void autogroupDives(); void mergeTrips(dive_trip *trip1, dive_trip *trip2); void splitDives(dive *d, duration_t time); +void splitDiveComputer(dive *d, int dc_num); void mergeDives(const QVector &dives); } // namespace Command diff --git a/desktop-widgets/command_divelist.cpp b/desktop-widgets/command_divelist.cpp index 845afac75..96c5ead95 100644 --- a/desktop-widgets/command_divelist.cpp +++ b/desktop-widgets/command_divelist.cpp @@ -8,6 +8,8 @@ #include "core/subsurface-qt/DiveListNotifier.h" #include "qt-models/filtermodels.h" +#include + namespace Command { // Generally, signals are sent in batches per trip. To avoid writing the same loop @@ -822,42 +824,51 @@ MergeTrips::MergeTrips(dive_trip *trip1, dive_trip *trip2) divesToMove.divesToMove.push_back( { trip2->dives.dives[i], newTrip } ); } -SplitDives::SplitDives(dive *d, duration_t time) +// std::array is the same as struct *dive[2], with the fundamental +// difference that it can be returned from functions. Thus, this constructor +// can be chained with the result of a function. +SplitDivesBase::SplitDivesBase(dive *d, std::array newDives) { - setText(tr("split dive")); - - // Split the dive - dive *new1, *new2; - int idx = time.seconds < 0 ? - split_dive(d, &new1, &new2) : - split_dive_at_time(d, time, &new1, &new2); - - // If this didn't work, simply return. Empty arrays indicate that nothing is to be done. - if (idx < 0) + // If either of the new dives is null, simply return. Empty arrays indicate that nothing is to be done. + if (!newDives[0] || !newDives[1]) return; // Currently, the core code selects the dive -> this is not what we want, as // we manually manage the selection post-command. // TODO: Reset selection in core. - new1->selected = false; - new2->selected = false; + newDives[0]->selected = false; + newDives[1]->selected = false; + + // Getting the insertion indexes correct is actually not easy, as we don't know + // which of the dives will land first when splitting out dive computers! + // TODO: We really should think about not storing the insertion index in the undo + // command, but calculating it on the fly on execution. + int idx_old = get_divenr(d); + int idx1 = dive_table_get_insertion_index(&dive_table, newDives[0]); + int idx2 = dive_table_get_insertion_index(&dive_table, newDives[1]); + if (idx1 > idx_old) + --idx1; + if (idx2 > idx_old) + --idx2; + if (idx1 == idx2 && dive_less_than(newDives[0], newDives[1])) + ++idx2; diveToSplit.push_back(d); splitDives.dives.resize(2); - splitDives.dives[0].dive.reset(new1); + splitDives.dives[0].dive.reset(newDives[0]); splitDives.dives[0].trip = d->divetrip; - splitDives.dives[0].idx = idx; - splitDives.dives[1].dive.reset(new2); + splitDives.dives[0].idx = idx1; + splitDives.dives[1].dive.reset(newDives[1]); splitDives.dives[1].trip = d->divetrip; - splitDives.dives[1].idx = idx + 1; + splitDives.dives[1].idx = idx2; } -bool SplitDives::workToBeDone() +bool SplitDivesBase::workToBeDone() { return !diveToSplit.empty(); } -void SplitDives::redoit() +void SplitDivesBase::redoit() { divesToUnsplit = addDives(splitDives); unsplitDive = removeDives(diveToSplit); @@ -867,7 +878,7 @@ void SplitDives::redoit() restoreSelection(divesToUnsplit, divesToUnsplit[0]); } -void SplitDives::undoit() +void SplitDivesBase::undoit() { // Note: reverse order with respect to redoit() diveToSplit = addDives(unsplitDive); @@ -878,6 +889,41 @@ void SplitDives::undoit() restoreSelection(diveToSplit, diveToSplit[0] ); } +static std::array doSplitDives(const dive *d, duration_t time) +{ + // Split the dive + dive *new1, *new2; + if (time.seconds < 0) + split_dive(d, &new1, &new2); + else + split_dive_at_time(d, time, &new1, &new2); + + return { new1, new2 }; +} + +SplitDives::SplitDives(dive *d, duration_t time) : SplitDivesBase(d, doSplitDives(d, time)) +{ + setText(tr("split dive")); +} + +static std::array splitDiveComputer(const dive *d, int dc_num) +{ + // Refuse to do anything if the dive has only one dive computer. + // Yes, this should have been checked by the UI, but let's just make sure. + if (!d->dc.next) + return { nullptr, nullptr}; + + dive *new1, *new2; + split_divecomputer(d, dc_num, &new1, &new2); + + return { new1, new2 }; +} + +SplitDiveComputer::SplitDiveComputer(dive *d, int dc_num) : SplitDivesBase(d, splitDiveComputer(d, dc_num)) +{ + setText(tr("split dive computer")); +} + MergeDives::MergeDives(const QVector &dives) { setText(tr("merge dive")); diff --git a/desktop-widgets/command_divelist.h b/desktop-widgets/command_divelist.h index 6cf7f48ab..7742cf729 100644 --- a/desktop-widgets/command_divelist.h +++ b/desktop-widgets/command_divelist.h @@ -185,10 +185,9 @@ struct MergeTrips : public TripBase { MergeTrips(dive_trip *trip1, dive_trip *trip2); }; -class SplitDives : public DiveListBase { -public: - // If time is < 0, split at first surface interval - SplitDives(dive *d, duration_t time); +class SplitDivesBase : public DiveListBase { +protected: + SplitDivesBase(dive *old, std::array newDives); private: void undoit() override; void redoit() override; @@ -209,6 +208,18 @@ private: std::vector divesToUnsplit; }; +class SplitDives : public SplitDivesBase { +public: + // If time is < 0, split at first surface interval + SplitDives(dive *d, duration_t time); +}; + +class SplitDiveComputer : public SplitDivesBase { +public: + // If time is < 0, split at first surface interval + SplitDiveComputer(dive *d, int dc_num); +}; + class MergeDives : public DiveListBase { public: MergeDives(const QVector &dives); -- cgit v1.2.3-70-g09d2