aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Berthold Stoeger <bstoeger@mail.tuwien.ac.at>2018-12-23 23:45:12 +0100
committerGravatar Dirk Hohndel <dirk@hohndel.org>2019-01-09 20:58:04 -0800
commit82c47bdd794c05e51c73afda14b8bfc95f6694e1 (patch)
treee1852b32d8d5370710076da6fe54959b1b6cf4c0
parent0249e125898134d3f6d4a2a8972f3eeb30c02803 (diff)
downloadsubsurface-82c47bdd794c05e51c73afda14b8bfc95f6694e1.tar.gz
Undo: make dive-import undoable
On desktop, replace all add_imported_dives() calls by a new undo-command. This was rather straight forward, as all the preparation work was done in previous commits. By using an undo-command, a full UI-reset can be avoided, making the UI react smoother. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
-rw-r--r--desktop-widgets/command.cpp7
-rw-r--r--desktop-widgets/command.h3
-rw-r--r--desktop-widgets/command_divelist.cpp83
-rw-r--r--desktop-widgets/command_divelist.h20
-rw-r--r--desktop-widgets/divelogimportdialog.cpp5
-rw-r--r--desktop-widgets/downloadfromdivecomputer.cpp19
-rw-r--r--desktop-widgets/mainwindow.cpp5
-rw-r--r--desktop-widgets/subsurfacewebservices.cpp4
-rw-r--r--qt-models/diveimportedmodel.cpp1
9 files changed, 122 insertions, 25 deletions
diff --git a/desktop-widgets/command.cpp b/desktop-widgets/command.cpp
index 2bff1aad0..1fc6fbe1c 100644
--- a/desktop-widgets/command.cpp
+++ b/desktop-widgets/command.cpp
@@ -11,6 +11,13 @@ void addDive(dive *d, bool autogroup, bool newNumber)
execute(new AddDive(d, autogroup, newNumber));
}
+void importDives(struct dive_table *dives, struct trip_table *trips,
+ bool prefer_imported, bool downloaded, bool merge_all_trips,
+ const QString &source)
+{
+ execute(new ImportDives(dives, trips, prefer_imported, downloaded, merge_all_trips, source));
+}
+
void deleteDive(const QVector<struct dive*> &divesToDelete)
{
execute(new DeleteDive(divesToDelete));
diff --git a/desktop-widgets/command.h b/desktop-widgets/command.h
index 71ef2f9da..83bde3b3a 100644
--- a/desktop-widgets/command.h
+++ b/desktop-widgets/command.h
@@ -21,6 +21,9 @@ void addDive(dive *d, bool autogroup, bool newNumber); // If d->dive_trip is nul
// distance are added to a trip. dive d is consumed (the structure is reset)!
// If newNumber is true, the dive is assigned a new number, depending on the
// insertion position.
+void importDives(struct dive_table *dives, struct trip_table *trips,
+ bool prefer_imported, bool downloaded, bool merge_all_trips,
+ const QString &source);
void deleteDive(const QVector<struct dive*> &divesToDelete);
void shiftTime(const QVector<dive *> &changedDives, int amount);
void renumberDives(const QVector<QPair<dive *, int>> &divesToRenumber);
diff --git a/desktop-widgets/command_divelist.cpp b/desktop-widgets/command_divelist.cpp
index c8ec5d082..6d2eafc6d 100644
--- a/desktop-widgets/command_divelist.cpp
+++ b/desktop-widgets/command_divelist.cpp
@@ -43,7 +43,7 @@ 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
+// It is crucial that dives are added in reverse order of deletion, so that the indices are correctly
// set and that the trips are added before they are used!
DiveToAdd DiveListBase::removeDive(struct dive *d, std::vector<OwningTripPtr> &tripsToAdd)
{
@@ -558,6 +558,87 @@ void AddDive::undoit()
MainWindow::instance()->refreshDisplay(false);
}
+ImportDives::ImportDives(struct dive_table *dives, struct trip_table *trips,
+ bool prefer_imported, bool downloaded, bool merge_all_trips,
+ const QString &source)
+{
+ setText(tr("import %n dive(s) from %1", "", dives->nr).arg(source));
+
+ struct dive_table dives_to_add = { 0 };
+ struct dive_table dives_to_remove = { 0 };
+ struct trip_table trips_to_add = { 0 };
+ process_imported_dives(dives, trips, prefer_imported, downloaded, merge_all_trips,
+ &dives_to_add, &dives_to_remove, &trips_to_add);
+
+ // Add trips to the divesToAdd.trips structure
+ divesToAdd.trips.reserve(trips_to_add.nr);
+ for (int i = 0; i < trips_to_add.nr; ++i)
+ divesToAdd.trips.emplace_back(trips_to_add.trips[i]);
+
+ // Add dives to the divesToAdd.dives structure
+ divesToAdd.dives.reserve(dives_to_add.nr);
+ for (int i = 0; i < dives_to_add.nr; ++i) {
+ OwningDivePtr divePtr(dives_to_add.dives[i]);
+ divePtr->selected = false; // See above in AddDive::AddDive()
+ dive_trip *trip = divePtr->divetrip;
+ divePtr->divetrip = nullptr; // See above in AddDive::AddDive()
+ int idx = dive_table_get_insertion_index(&dive_table, divePtr.get());
+
+ // Note: The dives are added in reverse order of the divesToAdd array.
+ // This, and the fact that we populate the array in chronological order
+ // means that wo do *not* have to manipulated the indices.
+ // Yes, that's all horribly subtle.
+ divesToAdd.dives.push_back({ std::move(divePtr), trip, idx });
+ }
+
+ // Add dive to be deleted to the divesToRemove structure
+ divesToRemove.reserve(dives_to_remove.nr);
+ for (int i = 0; i < dives_to_remove.nr; ++i)
+ divesToRemove.push_back(dives_to_remove.dives[i]);
+}
+
+bool ImportDives::workToBeDone()
+{
+ return !divesToAdd.dives.empty();
+}
+
+void ImportDives::redoit()
+{
+ // Remember selection so that we can undo it
+ currentDive = current_dive;
+
+ // Add new dives
+ std::vector<dive *> divesToRemoveNew = addDives(divesToAdd);
+
+ // Remove old dives
+ divesToAdd = removeDives(divesToRemove);
+
+ // Select the newly added dives
+ restoreSelection(divesToRemoveNew, divesToRemoveNew.back());
+
+ // Remember dives to remove
+ divesToRemove = std::move(divesToRemoveNew);
+
+ mark_divelist_changed(true);
+}
+
+void ImportDives::undoit()
+{
+ // Add new dives
+ std::vector<dive *> divesToRemoveNew = addDives(divesToAdd);
+
+ // Remove old dives
+ divesToAdd = removeDives(divesToRemove);
+
+ // Remember dives to remove
+ divesToRemove = std::move(divesToRemoveNew);
+
+ // ...and restore the selection
+ restoreSelection(selection, currentDive);
+
+ mark_divelist_changed(true);
+}
+
DeleteDive::DeleteDive(const QVector<struct dive*> &divesToDeleteIn) : divesToDelete(divesToDeleteIn.toStdVector())
{
setText(tr("delete %n dive(s)", "", divesToDelete.size()));
diff --git a/desktop-widgets/command_divelist.h b/desktop-widgets/command_divelist.h
index 77116c302..8cf8986e3 100644
--- a/desktop-widgets/command_divelist.h
+++ b/desktop-widgets/command_divelist.h
@@ -104,6 +104,26 @@ private:
dive * currentDive;
};
+class ImportDives : public DiveListBase {
+public:
+ // Note: dives and trips are consumed - after the call they will be empty.
+ ImportDives(struct dive_table *dives, struct trip_table *trips,
+ bool prefer_imported, bool downloaded, bool merge_all_trips,
+ const QString &source);
+private:
+ void undoit() override;
+ void redoit() override;
+ bool workToBeDone() override;
+
+ // For redo and undo
+ DivesAndTripsToAdd divesToAdd;
+ std::vector<dive *> divesToRemove;
+
+ // For undo
+ std::vector<dive *> selection;
+ dive * currentDive;
+};
+
class DeleteDive : public DiveListBase {
public:
DeleteDive(const QVector<dive *> &divesToDelete);
diff --git a/desktop-widgets/divelogimportdialog.cpp b/desktop-widgets/divelogimportdialog.cpp
index f8e44067d..638cf6094 100644
--- a/desktop-widgets/divelogimportdialog.cpp
+++ b/desktop-widgets/divelogimportdialog.cpp
@@ -1011,9 +1011,8 @@ void DiveLogImportDialog::on_buttonBox_accepted()
}
}
- add_imported_dives(&table, &trips, false, false, true);
- Command::clear();
- MainWindow::instance()->refreshDisplay();
+ QString source = fileNames.size() == 1 ? fileNames[0] : tr("multiple files");
+ Command::importDives(&table, &trips, false, false, true, source);
}
TagDragDelegate::TagDragDelegate(QObject *parent) : QStyledItemDelegate(parent)
diff --git a/desktop-widgets/downloadfromdivecomputer.cpp b/desktop-widgets/downloadfromdivecomputer.cpp
index 547c740c8..ff703d98e 100644
--- a/desktop-widgets/downloadfromdivecomputer.cpp
+++ b/desktop-widgets/downloadfromdivecomputer.cpp
@@ -521,25 +521,12 @@ void DownloadFromDCWidget::on_ok_clicked()
}
if (table->nr > 0) {
- MainWindow::instance()->diveList->unselectDives();
- // remember the last downloaded dive (on most dive computers this will be the chronologically
- // first new dive) and select it again after processing all the dives
- int uniqId = table->dives[table->nr - 1]->id;
- add_imported_dives(table, trips, preferDownloaded(), true, false);
- Command::clear();
- // after add_imported_dives does any merging or resorting needed, we need
- // to recreate the model for the dive list so we can select the newest dive
- MainWindow::instance()->recreateDiveList();
- int idx = get_idx_by_uniq_id(uniqId);
- // this shouldn't be necessary - but there are reports that somehow existing dives stay selected
- // (but not visible as selected)
- MainWindow::instance()->diveList->unselectDives();
- MainWindow::instance()->diveList->selectDive(idx, true);
+ auto data = thread.data();
+ Command::importDives(table, trips, preferDownloaded(), true, false, data->devName());
}
- if (ostcFirmwareCheck && currentState == DONE) {
+ if (ostcFirmwareCheck && currentState == DONE)
ostcFirmwareCheck->checkLatest(this, thread.data()->internalData());
- }
accept();
}
diff --git a/desktop-widgets/mainwindow.cpp b/desktop-widgets/mainwindow.cpp
index 474ce0f55..2e4342511 100644
--- a/desktop-widgets/mainwindow.cpp
+++ b/desktop-widgets/mainwindow.cpp
@@ -1714,9 +1714,8 @@ void MainWindow::importFiles(const QStringList fileNames)
fileNamePtr = QFile::encodeName(fileNames.at(i));
parse_file(fileNamePtr.data(), &table, &trips);
}
- add_imported_dives(&table, &trips, false, false, true);
- Command::clear();
- refreshDisplay();
+ QString source = fileNames.size() == 1 ? fileNames[0] : tr("multiple files");
+ Command::importDives(&table, &trips, false, false, true, source);
}
void MainWindow::loadFiles(const QStringList fileNames)
diff --git a/desktop-widgets/subsurfacewebservices.cpp b/desktop-widgets/subsurfacewebservices.cpp
index 58806a75b..e6ef6668e 100644
--- a/desktop-widgets/subsurfacewebservices.cpp
+++ b/desktop-widgets/subsurfacewebservices.cpp
@@ -4,6 +4,7 @@
#include "core/webservice.h"
#include "core/settings/qPrefCloudStorage.h"
#include "desktop-widgets/mainwindow.h"
+#include "desktop-widgets/command.h"
#include "desktop-widgets/usersurvey.h"
#include "core/divelist.h"
#include "desktop-widgets/mapwidget.h"
@@ -771,8 +772,7 @@ void DivelogsDeWebServices::buttonClicked(QAbstractButton *button)
struct dive_table table = { 0 };
struct trip_table trips = { 0 };
parse_file(QFile::encodeName(zipFile.fileName()), &table, &trips);
- add_imported_dives(&table, &trips, false, false, true);
- MainWindow::instance()->refreshDisplay();
+ Command::importDives(&table, &trips, false, false, true, QStringLiteral("divelogs.de"));
/* store last entered user/pass in config */
QSettings s;
diff --git a/qt-models/diveimportedmodel.cpp b/qt-models/diveimportedmodel.cpp
index ac7e26c26..566bda173 100644
--- a/qt-models/diveimportedmodel.cpp
+++ b/qt-models/diveimportedmodel.cpp
@@ -141,6 +141,7 @@ void DiveImportedModel::repopulate(dive_table_t *table, trip_table_t *trips)
endResetModel();
}
+// Note: this function is only used from mobile - perhaps move it there or unify.
void DiveImportedModel::recordDives()
{
if (diveTable->nr == 0)