summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--desktop-widgets/command.cpp5
-rw-r--r--desktop-widgets/command.h1
-rw-r--r--desktop-widgets/command_edit.cpp174
-rw-r--r--desktop-widgets/command_edit.h32
-rw-r--r--desktop-widgets/mainwindow.cpp4
-rw-r--r--desktop-widgets/tab-widgets/maintab.cpp59
-rw-r--r--desktop-widgets/tab-widgets/maintab.h2
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(&copyPasteDive, &displayed_dive, what, false);
- mainTab->showAndTriggerEditSelective(what);
+ Command::pasteDives(&copyPasteDive, 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;