diff options
author | Berthold Stoeger <bstoeger@mail.tuwien.ac.at> | 2019-03-31 10:20:13 +0200 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2019-04-04 09:38:12 -0700 |
commit | 145f70aab59a5ebd1b4ca82432caf38b4821b055 (patch) | |
tree | 2527f595c552559ffe74e6cce39f3c52283762d9 /desktop-widgets | |
parent | 8c9e5becb20d2d8c8aa1f7108775cc520b08fae1 (diff) | |
download | subsurface-145f70aab59a5ebd1b4ca82432caf38b4821b055.tar.gz |
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 <torvalds@linux-foundation.org>.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Diffstat (limited to 'desktop-widgets')
-rw-r--r-- | desktop-widgets/command.cpp | 5 | ||||
-rw-r--r-- | desktop-widgets/command.h | 1 | ||||
-rw-r--r-- | desktop-widgets/command_divelist.cpp | 86 | ||||
-rw-r--r-- | desktop-widgets/command_divelist.h | 19 |
4 files changed, 87 insertions, 24 deletions
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 <dive *> &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<dive *> &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 <dive *> &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 <array> + 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<dive *, 2> 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<dive *, 2> 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<dive *, 2> 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<dive *, 2> 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 <dive *> &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<dive *, 2> newDives); private: void undoit() override; void redoit() override; @@ -209,6 +208,18 @@ private: std::vector<dive *> 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<dive *> &dives); |