mirror of
https://github.com/subsurface/subsurface.git
synced 2024-11-30 22:20:21 +00:00
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>
This commit is contained in:
parent
0249e12589
commit
82c47bdd79
9 changed files with 122 additions and 25 deletions
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue