diff options
-rw-r--r-- | core/dive.c | 76 | ||||
-rw-r--r-- | core/dive.h | 4 | ||||
-rw-r--r-- | desktop-widgets/divelistview.cpp | 10 | ||||
-rw-r--r-- | desktop-widgets/undocommands.cpp | 56 | ||||
-rw-r--r-- | desktop-widgets/undocommands.h | 19 | ||||
-rw-r--r-- | profile-widget/profilewidget2.cpp | 16 |
6 files changed, 145 insertions, 36 deletions
diff --git a/core/dive.c b/core/dive.c index d7a2f11a8..1e8f23623 100644 --- a/core/dive.c +++ b/core/dive.c @@ -3388,7 +3388,7 @@ struct dive *merge_dives(struct dive *a, struct dive *b, int offset, bool prefer } // copy_dive(), but retaining the new ID for the copied dive -static struct dive *create_new_copy(struct dive *from) +static struct dive *create_new_copy(const struct dive *from) { struct dive *to = alloc_dive(); int id; @@ -3450,9 +3450,11 @@ static void force_fixup_dive(struct dive *d) /* * Split a dive that has a surface interval from samples 'a' to 'b' - * into two dives. + * into two dives, but don't add them to the log yet. + * Returns the nr of the old dive or <0 on failure. + * On success, the newly allocated dives are returned in out1 and out2. */ -static int split_dive_at(struct dive *dive, int a, int b) +static int split_dive_at(const struct dive *dive, int a, int b, struct dive **out1, struct dive **out2) { int i, nr; uint32_t t; @@ -3462,15 +3464,16 @@ static int split_dive_at(struct dive *dive, int a, int b) /* if we can't find the dive in the dive list, don't bother */ if ((nr = get_divenr(dive)) < 0) - return 0; + return -1; /* Splitting should leave at least 3 samples per dive */ if (a < 3 || b > dive->dc.samples - 4) - return 0; + return -1; /* We're not trying to be efficient here.. */ d1 = create_new_copy(dive); d2 = create_new_copy(dive); + d1->divetrip = d2->divetrip = 0; /* now unselect the first first segment so we don't keep all * dives selected by mistake. But do keep the second one selected @@ -3544,15 +3547,6 @@ static int split_dive_at(struct dive *dive, int a, int b) force_fixup_dive(d1); force_fixup_dive(d2); - if (dive->divetrip) { - d1->divetrip = d2->divetrip = 0; - add_dive_to_trip(d1, dive->divetrip); - add_dive_to_trip(d2, dive->divetrip); - } - - delete_single_dive(nr); - add_single_dive(nr, d1); - /* * Was the dive numbered? If it was the last dive, then we'll * increment the dive number for the tail part that we split off. @@ -3564,16 +3558,28 @@ static int split_dive_at(struct dive *dive, int a, int b) else d2->number = 0; } - add_single_dive(nr + 1, d2); mark_divelist_changed(true); - return 1; + *out1 = d1; + *out2 = d2; + return nr; +} + +static void finish_split(int nr, struct dive *old, struct dive *d1, struct dive *d2) +{ + if (old->divetrip) { + add_dive_to_trip(d1, old->divetrip); + add_dive_to_trip(d2, old->divetrip); + } + delete_single_dive(nr); + add_single_dive(nr, d1); + add_single_dive(nr + 1, d2); } /* in freedive mode we split for as little as 10 seconds on the surface, * otherwise we use a minute */ -static bool should_split(struct divecomputer *dc, int t1, int t2) +static bool should_split(const struct divecomputer *dc, int t1, int t2) { int threshold = dc->divemode == FREEDIVE ? 10 : 60; @@ -3590,14 +3596,14 @@ static bool should_split(struct divecomputer *dc, int t1, int t2) * * In other words, this is a (simplified) reversal of the dive merging. */ -int split_dive(struct dive *dive) +int split_dive_dont_insert(const struct dive *dive, struct dive **new1, struct dive **new2) { int i; int at_surface, surface_start; - struct divecomputer *dc; + const struct divecomputer *dc; if (!dive) - return 0; + return -1; dc = &dive->dc; surface_start = 0; @@ -3627,25 +3633,43 @@ int split_dive(struct dive *dive) if (!should_split(dc, dc->sample[surface_start].time.seconds, sample[-1].time.seconds)) continue; - return split_dive_at(dive, surface_start, i-1); + return split_dive_at(dive, surface_start, i-1, new1, new2); } - return 0; + return -1; } -void split_dive_at_time(struct dive *dive, duration_t time) +void split_dive(struct dive *dive) +{ + int nr; + struct dive *new1, *new2; + + if ((nr = split_dive_dont_insert(dive, &new1, &new2)) >= 0) + finish_split(nr, dive, new1, new2); +} + +int split_dive_at_time_dont_insert(const struct dive *dive, duration_t time, struct dive **new1, struct dive **new2) { int i = 0; struct sample *sample = dive->dc.sample; if (!dive) - return; + return -1; while(sample->time.seconds < time.seconds) { ++sample; ++i; if (dive->dc.samples == i) - return; + return -1; } - split_dive_at(dive, i, i - 1); + return split_dive_at(dive, i, i - 1, new1, new2); +} + +void split_dive_at_time(struct dive *dive, duration_t time) +{ + int nr; + struct dive *new1, *new2; + + if ((nr = split_dive_at_time_dont_insert(dive, time, &new1, &new2)) >= 0) + finish_split(nr, dive, new1, new2); } /* diff --git a/core/dive.h b/core/dive.h index 2d3edbc5c..340bc7ec8 100644 --- a/core/dive.h +++ b/core/dive.h @@ -569,7 +569,9 @@ extern void fixup_dc_duration(struct divecomputer *dc); extern int dive_getUniqID(); extern unsigned int dc_airtemp(const struct divecomputer *dc); extern unsigned int dc_watertemp(const struct divecomputer *dc); -extern int split_dive(struct dive *); +extern int split_dive_dont_insert(const struct dive *dive, struct dive **new1, struct dive **new2); +extern void split_dive(struct dive *); +extern int split_dive_at_time_dont_insert(const struct dive *dive, duration_t time, struct dive **new1, struct dive **new2); extern void split_dive_at_time(struct dive *dive, duration_t time); extern struct dive *merge_dives(struct dive *a, struct dive *b, int offset, bool prefer_downloaded); extern struct dive *try_to_merge(struct dive *a, struct dive *b, bool prefer_downloaded); diff --git a/desktop-widgets/divelistview.cpp b/desktop-widgets/divelistview.cpp index 945a7381e..938a4e3e5 100644 --- a/desktop-widgets/divelistview.cpp +++ b/desktop-widgets/divelistview.cpp @@ -633,12 +633,16 @@ void DiveListView::splitDives() int i; struct dive *dive; + // Let's collect the dives to be split first, so that we don't catch newly inserted dives! + QVector<struct dive *> dives; for_each_dive (i, dive) { if (dive->selected) - split_dive(dive); + dives.append(dive); + } + for (struct dive *d: dives) { + UndoSplitDives *undoCommand = new UndoSplitDives(d, duration_t{-1}); + MainWindow::instance()->undoStack->push(undoCommand); } - MainWindow::instance()->refreshProfile(); - MainWindow::instance()->refreshDisplay(); } void DiveListView::renumberDives() diff --git a/desktop-widgets/undocommands.cpp b/desktop-widgets/undocommands.cpp index 668a84f9e..45c796af8 100644 --- a/desktop-widgets/undocommands.cpp +++ b/desktop-widgets/undocommands.cpp @@ -180,6 +180,7 @@ void UndoRemoveDivesFromTrip::undo() for (auto &pair: divesToAdd) add_dive_to_trip(pair.first, pair.second); divesToAdd.clear(); + mark_divelist_changed(true); // Finally, do the UI stuff: MainWindow::instance()->refreshDisplay(); @@ -204,3 +205,58 @@ void UndoRemoveDivesFromTrip::redo() // Finally, do the UI stuff: MainWindow::instance()->refreshDisplay(); } + +UndoSplitDives::UndoSplitDives(dive *d, duration_t time) +{ + setText(gettextFromC::tr("split dive")); + + // Split the dive + dive *new1, *new2; + int idx = time.seconds < 0 ? + split_dive_dont_insert(d, &new1, &new2) : + split_dive_at_time_dont_insert(d, time, &new1, &new2); + + // If this didn't work, reset pointers so that redo() and undo() do nothing + if (idx < 0) { + diveToSplit = nullptr; + divesToUnsplit[0] = divesToUnsplit[1]; + return; + } + + diveToSplit = d; + 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; +} + +void UndoSplitDives::redo() +{ + if (!diveToSplit) + return; + divesToUnsplit[0] = addDive(splitDives[0]); + divesToUnsplit[1] = addDive(splitDives[1]); + unsplitDive = removeDive(diveToSplit); + mark_divelist_changed(true); + + // Finally, do the UI stuff: + MainWindow::instance()->refreshDisplay(); + MainWindow::instance()->refreshProfile(); +} + +void UndoSplitDives::undo() +{ + if (!unsplitDive.dive) + return; + // Note: reverse order with respect to redo() + diveToSplit = addDive(unsplitDive); + splitDives[1] = removeDive(divesToUnsplit[1]); + splitDives[0] = removeDive(divesToUnsplit[0]); + mark_divelist_changed(true); + + // Finally, do the UI stuff: + MainWindow::instance()->refreshDisplay(); + MainWindow::instance()->refreshProfile(); +} diff --git a/desktop-widgets/undocommands.h b/desktop-widgets/undocommands.h index 4c4073454..c30ae5fae 100644 --- a/desktop-widgets/undocommands.h +++ b/desktop-widgets/undocommands.h @@ -227,4 +227,23 @@ private: std::vector<OwningTripPtr> tripsToAdd; }; +class UndoSplitDives : public QUndoCommand { +public: + // If time is < 0, split at first surface interval + UndoSplitDives(dive *d, duration_t time); +private: + void undo() override; + void redo() override; + + // For redo + // For each dive to split, we remove one from and put two dives into the backend + dive *diveToSplit; + DiveToAdd splitDives[2]; + + // For undo + // For each dive to unsplit, we remove two dives from and add one into the backend + DiveToAdd unsplitDive; + dive *divesToUnsplit[2]; +}; + #endif // UNDOCOMMANDS_H diff --git a/profile-widget/profilewidget2.cpp b/profile-widget/profilewidget2.cpp index 793c6d950..79b70d719 100644 --- a/profile-widget/profilewidget2.cpp +++ b/profile-widget/profilewidget2.cpp @@ -23,6 +23,7 @@ #include "desktop-widgets/diveplanner.h" #include "desktop-widgets/simplewidgets.h" #include "desktop-widgets/divepicturewidget.h" +#include "desktop-widgets/undocommands.h" #include "desktop-widgets/mainwindow.h" #include "core/qthelper.h" #include "core/gettextfromc.h" @@ -1675,16 +1676,19 @@ void ProfileWidget2::addSetpointChange() void ProfileWidget2::splitDive() { +#ifndef SUBSURFACE_MOBILE + // Make sure that this is an actual dive and we're not in add mode + dive *d = get_dive_by_uniq_id(displayed_dive.id); + if (!d) + return; QAction *action = qobject_cast<QAction *>(sender()); QPointF scenePos = mapToScene(mapFromGlobal(action->data().toPoint())); duration_t time; - time.seconds = lrint(timeAxis->valueAt((scenePos))); - split_dive_at_time(&displayed_dive, time); + time.seconds = lrint(timeAxis->valueAt(scenePos)); + UndoSplitDives *undoCommand = new UndoSplitDives(d, time); + MainWindow::instance()->undoStack->push(undoCommand); emit updateDiveInfo(false); - mark_divelist_changed(true); - replot(); - MainWindow::instance()->refreshProfile(); - MainWindow::instance()->refreshDisplay(); +#endif } void ProfileWidget2::changeGas() |