aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Berthold Stoeger <bstoeger@mail.tuwien.ac.at>2019-05-17 22:22:55 +0200
committerGravatar Dirk Hohndel <dirk@hohndel.org>2019-05-20 21:23:16 -0700
commiteba6e76b963115a77b5f8607bc6c3ea1040a466f (patch)
treee926eb7112a902561c1b66f4d6a342ec2a7134b5
parentf0307abf50397da79671ce79707eb4ce1f78acd0 (diff)
downloadsubsurface-eba6e76b963115a77b5f8607bc6c3ea1040a466f.tar.gz
Undo: make "move dive computer to front" undoable
Instead of the elegant solution that just modifies the dive, keep two copies and add either the old or the new copy. This is primitive, but it trivially keeps the dives in the right order. The order might change on renumbering the dive computers. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
-rw-r--r--core/dive.c43
-rw-r--r--core/dive.h2
-rw-r--r--desktop-widgets/command.cpp5
-rw-r--r--desktop-widgets/command.h1
-rw-r--r--desktop-widgets/command_divelist.cpp52
-rw-r--r--desktop-widgets/command_divelist.h17
-rw-r--r--profile-widget/profilewidget2.cpp9
7 files changed, 106 insertions, 23 deletions
diff --git a/core/dive.c b/core/dive.c
index ed0c5a757..e6b27e0bb 100644
--- a/core/dive.c
+++ b/core/dive.c
@@ -4151,27 +4151,42 @@ bool dive_remove_picture(struct dive *d, const char *filename)
return false;
}
-/* this always acts on the current divecomputer of the current dive */
-void make_first_dc()
+/* clones a dive and moves given dive computer to front */
+struct dive *make_first_dc(const struct dive *d, int dc_number)
{
- struct divecomputer *dc = &current_dive->dc;
- struct divecomputer *newdc = malloc(sizeof(*newdc));
- struct divecomputer *cur_dc = current_dc; /* needs to be in a local variable so the macro isn't re-executed */
+ struct dive *res;
+ struct divecomputer *dc, *newdc, *old_dc;
+
+ /* copy the dive */
+ res = alloc_dive();
+ copy_dive(d, res);
+
+ /* make a new unique id, since we still can't handle two equal ids */
+ res->id = dive_getUniqID();
+ invalidate_dive_cache(res);
+
+ if (dc_number == 0)
+ return res;
+
+ dc = &res->dc;
+ newdc = malloc(sizeof(*newdc));
+ old_dc = get_dive_dc(res, dc_number);
/* skip the current DC in the linked list */
- while (dc && dc->next != cur_dc)
- dc = dc->next;
+ for (dc = &res->dc; dc && dc->next != old_dc; dc = dc->next)
+ ;
if (!dc) {
free(newdc);
fprintf(stderr, "data inconsistent: can't find the current DC");
- return;
+ return res;
}
- dc->next = cur_dc->next;
- *newdc = current_dive->dc;
- current_dive->dc = *cur_dc;
- current_dive->dc.next = newdc;
- free(cur_dc);
- invalidate_dive_cache(current_dive);
+ dc->next = old_dc->next;
+ *newdc = res->dc;
+ res->dc = *old_dc;
+ res->dc.next = newdc;
+ free(old_dc);
+
+ return res;
}
/* always acts on the current dive */
diff --git a/core/dive.h b/core/dive.h
index 7aea050b6..ebc127bd7 100644
--- a/core/dive.h
+++ b/core/dive.h
@@ -434,7 +434,7 @@ extern unsigned int number_of_computers(const struct dive *dive);
extern struct divecomputer *get_dive_dc(struct dive *dive, int nr);
extern timestamp_t dive_endtime(const struct dive *dive);
-extern void make_first_dc(void);
+extern struct dive *make_first_dc(const struct dive *d, int dc_number);
extern unsigned int count_divecomputers(void);
extern void delete_current_divecomputer(void);
void split_divecomputer(const struct dive *src, int num, struct dive **out1, struct dive **out2);
diff --git a/desktop-widgets/command.cpp b/desktop-widgets/command.cpp
index e5244e92a..b6283ec8d 100644
--- a/desktop-widgets/command.cpp
+++ b/desktop-widgets/command.cpp
@@ -74,6 +74,11 @@ void splitDiveComputer(dive *d, int dc_num)
execute(new SplitDiveComputer(d, dc_num));
}
+void moveDiveComputerToFront(dive *d, int dc_num)
+{
+ execute(new MoveDiveComputerToFront(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 2686255ee..543e3bcae 100644
--- a/desktop-widgets/command.h
+++ b/desktop-widgets/command.h
@@ -36,6 +36,7 @@ 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 moveDiveComputerToFront(dive *d, int dc_num);
void mergeDives(const QVector <dive *> &dives);
// 3) Dive-site related commands
diff --git a/desktop-widgets/command_divelist.cpp b/desktop-widgets/command_divelist.cpp
index c49159f5a..4c4a7e7d3 100644
--- a/desktop-widgets/command_divelist.cpp
+++ b/desktop-widgets/command_divelist.cpp
@@ -9,6 +9,7 @@
#include "core/qthelper.h"
#include "core/subsurface-qt/DiveListNotifier.h"
#include "qt-models/filtermodels.h"
+#include "../profile-widget/profilewidget2.h"
#include <array>
@@ -802,6 +803,57 @@ SplitDiveComputer::SplitDiveComputer(dive *d, int dc_num) : SplitDivesBase(d, sp
setText(tr("split dive computer"));
}
+MoveDiveComputerToFront::MoveDiveComputerToFront(dive *d, int dc_num)
+{
+ setText(tr("move dive computer to front"));
+
+ dive *new_dive = make_first_dc(d, dc_num);
+ if (!new_dive)
+ return;
+
+ diveToRemove.dives.push_back(d);
+
+ // 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.
+ new_dive->selected = false;
+
+ // Reset references to trip and site in the new dive, as the undo command
+ // will add the dive to the trip and site.
+ new_dive->divetrip = nullptr;
+ new_dive->dive_site = nullptr;
+
+ diveToAdd.dives.resize(1);
+ diveToAdd.dives[0].dive.reset(new_dive);
+ diveToAdd.dives[0].trip = d->divetrip;
+ diveToAdd.dives[0].site = d->dive_site;
+}
+
+bool MoveDiveComputerToFront::workToBeDone()
+{
+ return !diveToRemove.dives.empty() || !diveToAdd.dives.empty();
+}
+
+void MoveDiveComputerToFront::redoit()
+{
+ DivesAndSitesToRemove addedDive = addDives(diveToAdd);
+ diveToAdd = removeDives(diveToRemove);
+ diveToRemove = std::move(addedDive);
+
+ // Select added dive and make it current
+ restoreSelection(diveToRemove.dives, diveToRemove.dives[0]);
+
+ // Update the profile to show the first dive computer
+ dc_number = 0;
+ MainWindow::instance()->graphics->replot(current_dive);
+}
+
+void MoveDiveComputerToFront::undoit()
+{
+ // Undo and redo do the same
+ redoit();
+}
+
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 2d3ee8db1..d46697454 100644
--- a/desktop-widgets/command_divelist.h
+++ b/desktop-widgets/command_divelist.h
@@ -236,6 +236,23 @@ public:
SplitDiveComputer(dive *d, int dc_num);
};
+// When moving the dive computer to the front, we go the ineffective,
+// but easy way: We keep two full copies of the dive (before and after).
+// Removing and readding assures that the dive stays at the correct
+// position in the list (the dive computer list is used for sorting dives).
+class MoveDiveComputerToFront : public DiveListBase {
+public:
+ MoveDiveComputerToFront(dive *d, int dc_num);
+private:
+ void undoit() override;
+ void redoit() override;
+ bool workToBeDone() override;
+
+ // For redo and undo
+ DivesAndTripsToAdd diveToAdd;
+ DivesAndSitesToRemove diveToRemove;
+};
+
class MergeDives : public DiveListBase {
public:
MergeDives(const QVector<dive *> &dives);
diff --git a/profile-widget/profilewidget2.cpp b/profile-widget/profilewidget2.cpp
index f9655127e..46a1eb1a0 100644
--- a/profile-widget/profilewidget2.cpp
+++ b/profile-widget/profilewidget2.cpp
@@ -1590,14 +1590,7 @@ void ProfileWidget2::splitCurrentDC()
void ProfileWidget2::makeFirstDC()
{
- make_first_dc();
- mark_divelist_changed(true);
- // this is now the first DC, so we need to redraw the profile and refresh the dive list
- // (and no, it's not just enough to rewrite the text - the first DC is special so values in the
- // dive list may change).
- // As a side benefit, this returns focus to the dive list.
- dc_number = 0;
- emit refreshDisplay(true);
+ Command::moveDiveComputerToFront(current_dive, dc_number);
}
void ProfileWidget2::hideEvents()