diff options
-rw-r--r-- | desktop-widgets/command.cpp | 5 | ||||
-rw-r--r-- | desktop-widgets/command.h | 1 | ||||
-rw-r--r-- | desktop-widgets/command_edit.cpp | 174 | ||||
-rw-r--r-- | desktop-widgets/command_edit.h | 32 | ||||
-rw-r--r-- | desktop-widgets/mainwindow.cpp | 4 | ||||
-rw-r--r-- | desktop-widgets/tab-widgets/maintab.cpp | 59 | ||||
-rw-r--r-- | desktop-widgets/tab-widgets/maintab.h | 2 |
7 files changed, 215 insertions, 62 deletions
diff --git a/desktop-widgets/command.cpp b/desktop-widgets/command.cpp index 0486b2bce..07c8be61d 100644 --- a/desktop-widgets/command.cpp +++ b/desktop-widgets/command.cpp @@ -200,4 +200,9 @@ void editDiveMaster(const QStringList &newList, bool currentDiveOnly) execute(new EditDiveMaster(newList, currentDiveOnly)); } +void pasteDives(const dive *d, dive_components what) +{ + execute(new PasteDives(d, what)); +} + } // namespace Command diff --git a/desktop-widgets/command.h b/desktop-widgets/command.h index 7667f3482..6cfd7fc4e 100644 --- a/desktop-widgets/command.h +++ b/desktop-widgets/command.h @@ -66,6 +66,7 @@ void editDiveSiteNew(const QString &newName, bool currentDiveOnly); void editTags(const QStringList &newList, bool currentDiveOnly); void editBuddies(const QStringList &newList, bool currentDiveOnly); void editDiveMaster(const QStringList &newList, bool currentDiveOnly); +void pasteDives(const dive *d, dive_components what); } // namespace Command diff --git a/desktop-widgets/command_edit.cpp b/desktop-widgets/command_edit.cpp index f92d045aa..106670978 100644 --- a/desktop-widgets/command_edit.cpp +++ b/desktop-widgets/command_edit.cpp @@ -4,6 +4,7 @@ #include "command_private.h" #include "core/divelist.h" #include "core/qthelper.h" // for copy_qstring +#include "core/subsurface-string.h" #include "desktop-widgets/mapwidget.h" // TODO: Replace desktop-dependency by signal namespace Command { @@ -598,4 +599,177 @@ DiveField EditDiveMaster::fieldId() const return DiveField::DIVEMASTER; } +// Helper function to copy cylinders. This supposes that the destination +// cylinder is uninitialized. I.e. the old description is not freed! +static void copy_cylinder(const cylinder_t &s, cylinder_t &d) +{ + d.type.description = copy_string(s.type.description); + d.type.size = s.type.size; + d.type.workingpressure = s.type.workingpressure; + d.gasmix = s.gasmix; + d.cylinder_use = s.cylinder_use; + d.depth = s.depth; +} + +static void swapCandQString(QString &q, char *&c) +{ + QString tmp(c); + free(c); + c = copy_qstring(q); + q = std::move(tmp); +} + +PasteState::PasteState(dive *dIn, const dive *data, dive_components what) : d(dIn), + tags(nullptr) +{ + memset(&cylinders[0], 0, sizeof(cylinders)); + memset(&weightsystems[0], 0, sizeof(weightsystems)); + if (what.notes) + notes = data->notes; + if (what.divemaster) + divemaster = data->divemaster; + if (what.buddy) + buddy = data->buddy; + if (what.suit) + suit = data->suit; + if (what.rating) + rating = data->rating; + if (what.visibility) + visibility = data->visibility; + if (what.divesite) + divesite = data->dive_site; + if (what.tags) + tags = taglist_copy(data->tag_list); + if (what.cylinders) { + for (int i = 0; i < MAX_CYLINDERS; ++i) + copy_cylinder(data->cylinder[i], cylinders[i]); + } + if (what.weights) { + for (int i = 0; i < MAX_WEIGHTSYSTEMS; ++i) { + weightsystems[i] = data->weightsystem[i]; + weightsystems[i].description = copy_string(data->weightsystem[i].description); + } + } +} + +PasteState::~PasteState() +{ + taglist_free(tags); + for (cylinder_t &c: cylinders) + free((void *)c.type.description); + for (weightsystem_t &w: weightsystems) + free((void *)w.description); +} + +void PasteState::swap(dive_components what) +{ + if (what.notes) + swapCandQString(notes, d->notes); + if (what.divemaster) + swapCandQString(divemaster, d->divemaster); + if (what.buddy) + swapCandQString(buddy, d->buddy); + if (what.suit) + swapCandQString(suit, d->suit); + if (what.rating) + std::swap(rating, d->rating); + if (what.visibility) + std::swap(visibility, d->visibility); + if (what.divesite) + std::swap(divesite, d->dive_site); + if (what.tags) + std::swap(tags, d->tag_list); + if (what.cylinders) + std::swap(cylinders, d->cylinder); + if (what.weights) + std::swap(weightsystems, d->weightsystem); +} + +// ***** Paste ***** +PasteDives::PasteDives(const dive *data, dive_components whatIn) : what(whatIn), + current(current_dive) +{ + std::vector<dive *> selection = getDiveSelection(); + dives.reserve(selection.size()); + for (dive *d: selection) + dives.emplace_back(d, data, what); + + setText(tr("Paste onto %n dive(s)", "", dives.size())); +} + +bool PasteDives::workToBeDone() +{ + return !dives.empty(); +} + +void PasteDives::undo() +{ + bool diveSiteListChanged = false; + + // If we had taken ownership of dive sites, readd them to the system + for (OwningDiveSitePtr &ds: ownedDiveSites) { + register_dive_site(ds.release()); + diveSiteListChanged = true; + } + ownedDiveSites.clear(); + + std::vector<dive *> divesToNotify; // Remember dives so that we can send signals later + divesToNotify.reserve(dives.size()); + for (PasteState &state: dives) { + divesToNotify.push_back(state.d); + state.swap(what); + invalidate_dive_cache(state.d); // Ensure that dive is written in git_save() + } + + // If dive sites were pasted, collect all overwritten dive sites + // and remove those which don't have users anymore from the core. + // But keep an owning pointer. Thus if this undo command is freed, the + // dive-site will be automatically deleted and on redo() it can be + // readded to the system + if (what.divesite) { + std::vector<dive_site *> divesites; + for (const PasteState &d: dives) { + if (std::find(divesites.begin(), divesites.end(), d.divesite) == divesites.end()) + divesites.push_back(d.divesite); + } + for (dive_site *ds: divesites) { + unregister_dive_site(ds); + ownedDiveSites.emplace_back(ds); + diveSiteListChanged = true; + } + } + + // Send signals. + // TODO: We send one signal per changed field. This means that the dive list may + // update the entry numerous times. Perhaps change the field-id into flags? + // There seems to be a number of enums / flags describing dive fields. Perhaps unify them all? + processByTrip(divesToNotify, [&](dive_trip *trip, const QVector<dive *> &divesInTrip) { + if (what.notes) + emit diveListNotifier.divesChanged(trip, divesInTrip, DiveField::NOTES); + if (what.divemaster) + emit diveListNotifier.divesChanged(trip, divesInTrip, DiveField::DIVEMASTER); + if (what.buddy) + emit diveListNotifier.divesChanged(trip, divesInTrip, DiveField::BUDDY); + if (what.suit) + emit diveListNotifier.divesChanged(trip, divesInTrip, DiveField::SUIT); + if (what.rating) + emit diveListNotifier.divesChanged(trip, divesInTrip, DiveField::RATING); + if (what.visibility) + emit diveListNotifier.divesChanged(trip, divesInTrip, DiveField::VISIBILITY); + if (what.divesite) + emit diveListNotifier.divesChanged(trip, divesInTrip, DiveField::DIVESITE); + if (what.tags) + emit diveListNotifier.divesChanged(trip, divesInTrip, DiveField::TAGS); + }); + + if (diveSiteListChanged) + MapWidget::instance()->reload(); +} + +// Redo and undo do the same +void PasteDives::redo() +{ + undo(); +} + } // namespace Command diff --git a/desktop-widgets/command_edit.h b/desktop-widgets/command_edit.h index 9b5923af2..1f627c7ef 100644 --- a/desktop-widgets/command_edit.h +++ b/desktop-widgets/command_edit.h @@ -211,6 +211,38 @@ public: DiveField fieldId() const override; }; +// Fields we have to remember to undo paste +struct PasteState { + dive *d; + dive_site *divesite; + QString notes; + QString divemaster; + QString buddy; + QString suit; + int rating; + int visibility; + tag_entry *tags; + cylinder_t cylinders[MAX_CYLINDERS]; + weightsystem_t weightsystems[MAX_WEIGHTSYSTEMS]; + + PasteState(dive *d, const dive *data, dive_components what); // Read data from dive data for dive d + ~PasteState(); + void swap(dive_components what); // Exchange values here and in dive +}; + +class PasteDives : public Base { + dive_components what; + std::vector<PasteState> dives; + std::vector<OwningDiveSitePtr> ownedDiveSites; + dive *current; +public: + PasteDives(const dive *d, dive_components what); +private: + void undo() override; + void redo() override; + bool workToBeDone() override; +}; + } // namespace Command #endif diff --git a/desktop-widgets/mainwindow.cpp b/desktop-widgets/mainwindow.cpp index a181a8ceb..95b714d00 100644 --- a/desktop-widgets/mainwindow.cpp +++ b/desktop-widgets/mainwindow.cpp @@ -1802,9 +1802,7 @@ void MainWindow::on_copy_triggered() void MainWindow::on_paste_triggered() { - // take the data in our copyPasteDive and apply it to selected dives - selective_copy_dive(©PasteDive, &displayed_dive, what, false); - mainTab->showAndTriggerEditSelective(what); + Command::pasteDives(©PasteDive, what); } void MainWindow::on_actionFilterTags_triggered() diff --git a/desktop-widgets/tab-widgets/maintab.cpp b/desktop-widgets/tab-widgets/maintab.cpp index 84f64e0d0..8b23eb147 100644 --- a/desktop-widgets/tab-widgets/maintab.cpp +++ b/desktop-widgets/tab-widgets/maintab.cpp @@ -47,7 +47,6 @@ MainTab::MainTab(QWidget *parent) : QTabWidget(parent), weightModel(new WeightModel(this)), cylindersModel(new CylindersModel(this)), editMode(NONE), - copyPaste(false), lastSelectedDive(true), lastTabSelectedDive(0), lastTabSelectedDiveTrip(0), @@ -288,7 +287,6 @@ void MainTab::enableEdition(EditMode newEditMode) if (((newEditMode == DIVE || newEditMode == NONE) && current_dive == NULL) || editMode != NONE) return; modified = false; - copyPaste = false; if ((newEditMode == DIVE || newEditMode == NONE) && !isTripEdit && current_dive->dc.model && @@ -700,22 +698,11 @@ void MainTab::reload() mark_divelist_changed(true); \ } while (0) -#define EDIT_TEXT(what) \ - if (same_string(mydive->what, cd->what) || copyPaste) { \ - free(mydive->what); \ - mydive->what = copy_string(displayed_dive.what); \ - } - MainTab::EditMode MainTab::getEditMode() const { return editMode; } -#define EDIT_VALUE(what) \ - if (mydive->what == cd->what || copyPaste) { \ - mydive->what = displayed_dive.what; \ - } - void MainTab::refreshDisplayedDiveSite() { struct dive_site *ds = get_dive_site_for_dive(&displayed_dive); @@ -812,7 +799,7 @@ void MainTab::acceptChanges() MODIFY_DIVES(selectedDives, for (int i = 0; i < MAX_CYLINDERS; i++) { if (mydive != cd) { - if (same_string(mydive->cylinder[i].type.description, cd->cylinder[i].type.description) || copyPaste) { + if (same_string(mydive->cylinder[i].type.description, cd->cylinder[i].type.description)) { // if we started out with the same cylinder description (for multi-edit) or if we do copt & paste // make sure that we have the same cylinder type and copy the gasmix, but DON'T copy the start // and end pressures (those are per dive after all) @@ -855,7 +842,7 @@ void MainTab::acceptChanges() mark_divelist_changed(true); MODIFY_DIVES(selectedDives, for (int i = 0; i < MAX_WEIGHTSYSTEMS; i++) { - if (mydive != cd && (copyPaste || same_string(mydive->weightsystem[i].description, cd->weightsystem[i].description))) { + if (mydive != cd && (same_string(mydive->weightsystem[i].description, cd->weightsystem[i].description))) { mydive->weightsystem[i] = displayed_dive.weightsystem[i]; mydive->weightsystem[i].description = copy_string(displayed_dive.weightsystem[i].description); } @@ -1173,8 +1160,6 @@ void MainTab::on_visibility_valueChanged(int value) } #undef MODIFY_DIVES -#undef EDIT_TEXT -#undef EDIT_VALUE void MainTab::editCylinderWidget(const QModelIndex &index) { @@ -1216,43 +1201,3 @@ void MainTab::clearTabs() { } clearEquipment(); } - -#define SHOW_SELECTIVE(_component) \ - if (what._component) \ - ui._component->setText(displayed_dive._component); - -void MainTab::showAndTriggerEditSelective(struct dive_components what) -{ - // take the data in our copyPasteDive and apply it to selected dives - enableEdition(); - copyPaste = true; - SHOW_SELECTIVE(buddy); - SHOW_SELECTIVE(divemaster); - SHOW_SELECTIVE(suit); - if (what.notes) { - QString tmp(displayed_dive.notes); - if (tmp.contains("<div")) { - tmp.replace(QString("\n"), QString("<br>")); - ui.notes->setHtml(tmp); - } else { - ui.notes->setPlainText(tmp); - } - } - if (what.rating) - ui.rating->setCurrentStars(displayed_dive.rating); - if (what.visibility) - ui.visibility->setCurrentStars(displayed_dive.visibility); - if (what.divesite) - ui.location->setCurrentDiveSite(displayed_dive.dive_site); - if (what.tags) { - ui.tagWidget->setText(get_taglist_string(displayed_dive.tag_list)); - } - if (what.cylinders) { - cylindersModel->updateDive(); - cylindersModel->changed = true; - } - if (what.weights) { - weightModel->updateDive(); - weightModel->changed = true; - } -} diff --git a/desktop-widgets/tab-widgets/maintab.h b/desktop-widgets/tab-widgets/maintab.h index 5d341d287..83a19895a 100644 --- a/desktop-widgets/tab-widgets/maintab.h +++ b/desktop-widgets/tab-widgets/maintab.h @@ -55,7 +55,6 @@ public: void updateCoordinatesText(qreal lat, qreal lon); void refreshDisplayedDiveSite(); void nextInputField(QKeyEvent *event); - void showAndTriggerEditSelective(struct dive_components what); signals: void addDiveFinished(); @@ -113,7 +112,6 @@ private: TagCompletionModel tagModel; Completers completers; bool modified; - bool copyPaste; bool lastSelectedDive; int lastTabSelectedDive; int lastTabSelectedDiveTrip; |