From ea0c0307702f06998e87077dc038bff90a579abe Mon Sep 17 00:00:00 2001 From: Berthold Stoeger Date: Sun, 13 Feb 2022 19:32:19 +0100 Subject: [PATCH] undo: split replanDive and editProfile commands These two actions were using the same command with a flag controlling the name of the command, which is shown in the undo menu. However, the replanDive does much more (such as changing the notes) and in the future we may want to be more fine-grained with respect to profile editing. Therefore, split these commands into two separate ones. Moreover, make the editProfile command more flexible. Pass an enum describing the action instead and also a counter indicating how many points have been moved or removed. Finally, don't consume the input dive in the editProfile command, because we will want to keep the original dive while editing the profile. Signed-off-by: Berthold Stoeger --- commands/command.cpp | 6 +- commands/command.h | 9 ++- commands/command_edit.cpp | 75 ++++++++++++++++++++++++- commands/command_edit.h | 20 ++++++- desktop-widgets/tab-widgets/maintab.cpp | 2 +- 5 files changed, 102 insertions(+), 10 deletions(-) diff --git a/commands/command.cpp b/commands/command.cpp index b466f1156..1772f9063 100644 --- a/commands/command.cpp +++ b/commands/command.cpp @@ -276,12 +276,12 @@ void pasteDives(const dive *d, dive_components what) void replanDive(dive *d) { - execute(new ReplanDive(d, false)); + execute(new ReplanDive(d)); } -void editProfile(dive *d) +void editProfile(const dive *d, EditProfileType type, int count) { - execute(new ReplanDive(d, true)); + execute(new EditProfile(d, type, count)); } int addWeight(bool currentDiveOnly) diff --git a/commands/command.h b/commands/command.h index 39af8e7fb..d5e22b135 100644 --- a/commands/command.h +++ b/commands/command.h @@ -93,8 +93,13 @@ int editTags(const QStringList &newList, bool currentDiveOnly); int editBuddies(const QStringList &newList, bool currentDiveOnly); int editDiveGuide(const QStringList &newList, bool currentDiveOnly); void pasteDives(const dive *d, dive_components what); -void replanDive(dive *d); // dive computer(s) and cylinder(s) will be reset! -void editProfile(dive *d); // dive computer(s) and cylinder(s) will be reset! +enum class EditProfileType { + ADD, + REMOVE, + MOVE, +}; +void replanDive(dive *d); // dive computer(s) and cylinder(s) of first argument will be consumed! +void editProfile(const dive *d, EditProfileType type, int count); int addWeight(bool currentDiveOnly); int removeWeight(int index, bool currentDiveOnly); int editWeight(int index, weightsystem_t ws, bool currentDiveOnly); diff --git a/commands/command_edit.cpp b/commands/command_edit.cpp index 5b89f24d3..5d835a8ee 100644 --- a/commands/command_edit.cpp +++ b/commands/command_edit.cpp @@ -794,7 +794,7 @@ void PasteDives::redo() } // ***** ReplanDive ***** -ReplanDive::ReplanDive(dive *source, bool edit_profile) : d(current_dive), +ReplanDive::ReplanDive(dive *source) : d(current_dive), when(0), maxdepth({0}), meandepth({0}), @@ -824,7 +824,7 @@ ReplanDive::ReplanDive(dive *source, bool edit_profile) : d(current_dive), std::swap(source->cylinders, cylinders); std::swap(source->dc, dc); - setText((edit_profile ? Command::Base::tr("Replan dive") : Command::Base::tr("Edit profile")) + diveNumberOrDate(d)); + setText(Command::Base::tr("Replan dive")); } ReplanDive::~ReplanDive() @@ -867,6 +867,77 @@ void ReplanDive::redo() undo(); } +// ***** EditProfile ***** +QString editProfileTypeToString(EditProfileType type, int count) +{ + switch (type) { + default: + case EditProfileType::ADD: return Command::Base::tr("Add stop"); + case EditProfileType::REMOVE: return Command::Base::tr("Remove %n stop(s)", "", count); + case EditProfileType::MOVE: return Command::Base::tr("Move %n stop(s)", "", count); + } +} + +EditProfile::EditProfile(const dive *source, EditProfileType type, int count) : d(current_dive), + dcNr(dc_number), + maxdepth({0}), + meandepth({0}), + dcmaxdepth({0}), + duration({0}), + dc({ 0 }) +{ + const struct divecomputer *sdc = get_dive_dc_const(source, dcNr); + if (!sdc) + d = nullptr; // Signal that we refuse to do anything. + if (!d) + return; + + maxdepth = source->maxdepth; + dcmaxdepth = sdc->maxdepth; + meandepth = source->meandepth; + duration = source->duration; + + copy_samples(sdc, &dc); + copy_events(sdc, &dc); + + setText(editProfileTypeToString(type, count) + diveNumberOrDate(d)); +} + +EditProfile::~EditProfile() +{ + free_dive_dcs(&dc); +} + +bool EditProfile::workToBeDone() +{ + return !!d; +} + +void EditProfile::undo() +{ + struct divecomputer *sdc = get_dive_dc(d, dcNr); + if (!sdc) + return; + std::swap(sdc->samples, dc.samples); + std::swap(sdc->alloc_samples, dc.alloc_samples); + std::swap(sdc->sample, dc.sample); + std::swap(sdc->maxdepth, dc.maxdepth); + std::swap(d->maxdepth, maxdepth); + std::swap(d->meandepth, meandepth); + std::swap(d->duration, duration); + fixup_dive(d); + invalidate_dive_cache(d); // Ensure that dive is written in git_save() + + QVector divesToNotify = { d }; + emit diveListNotifier.divesChanged(divesToNotify, DiveField::DURATION | DiveField::DEPTH); +} + +// Redo and undo do the same +void EditProfile::redo() +{ + undo(); +} + // ***** Add Weight ***** AddWeight::AddWeight(bool currentDiveOnly) : EditDivesBase(currentDiveOnly) diff --git a/commands/command_edit.h b/commands/command_edit.h index 0772f8d56..d2a2cb7db 100644 --- a/commands/command_edit.h +++ b/commands/command_edit.h @@ -334,8 +334,7 @@ class ReplanDive : public Base { int salinity; public: // Dive computer(s) and cylinders(s) of the source dive will be reset! - // If edit_profile is true, the text will be changed from "replan dive" to "edit profile". - ReplanDive(dive *source, bool edit_profile); + ReplanDive(dive *source); ~ReplanDive(); private: void undo() override; @@ -343,6 +342,23 @@ private: bool workToBeDone() override; }; +class EditProfile : public Base { + dive *d; + int dcNr; + + depth_t maxdepth, meandepth, dcmaxdepth; + duration_t duration; + struct divecomputer dc; +public: + // Note: source must be clean (i.e. fixup_dive must have been called on it). + EditProfile(const dive *source, EditProfileType type, int count); + ~EditProfile(); +private: + void undo() override; + void redo() override; + bool workToBeDone() override; +}; + class AddWeight : public EditDivesBase { public: AddWeight(bool currentDiveOnly); diff --git a/desktop-widgets/tab-widgets/maintab.cpp b/desktop-widgets/tab-widgets/maintab.cpp index fe3c93eb0..bf9deae26 100644 --- a/desktop-widgets/tab-widgets/maintab.cpp +++ b/desktop-widgets/tab-widgets/maintab.cpp @@ -498,7 +498,7 @@ void MainTab::acceptChanges() MainWindow::instance()->showProfile(); DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::NOTHING); - Command::editProfile(&displayed_dive); + Command::editProfile(&displayed_dive, Command::EditProfileType::MOVE, 0); int scrolledBy = MainWindow::instance()->diveList->verticalScrollBar()->sliderPosition(); MainWindow::instance()->diveList->reload();