diff options
author | Berthold Stoeger <bstoeger@mail.tuwien.ac.at> | 2019-11-13 15:08:40 +0100 |
---|---|---|
committer | bstoeger <32835590+bstoeger@users.noreply.github.com> | 2019-11-14 21:02:07 +0100 |
commit | 5e29245e689fe9401ee1c33ebb07c601ce25e8c6 (patch) | |
tree | a656bcb0e9357b8cab78c5ad196fc6e5a4da4c31 /commands/command_divelist.h | |
parent | 685b92b9c2ddd6575ae5df7c95b928e60fcd7005 (diff) | |
download | subsurface-5e29245e689fe9401ee1c33ebb07c601ce25e8c6.tar.gz |
Refactoring: move undo commands to top level
In the future we might want to use undo-commands for mobile as
well (even if not implementing undo).
Therefore, move the undo-command source from desktop-widgets
to their own commands top-level folder.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Diffstat (limited to 'commands/command_divelist.h')
-rw-r--r-- | commands/command_divelist.h | 285 |
1 files changed, 285 insertions, 0 deletions
diff --git a/commands/command_divelist.h b/commands/command_divelist.h new file mode 100644 index 000000000..20d031f54 --- /dev/null +++ b/commands/command_divelist.h @@ -0,0 +1,285 @@ +// SPDX-License-Identifier: GPL-2.0 +// Note: this header file is used by the undo-machinery and should not be included elsewhere. + +#ifndef COMMAND_DIVELIST_H +#define COMMAND_DIVELIST_H + +#include "command_base.h" + +#include <QVector> + +// We put everything in a namespace, so that we can shorten names without polluting the global namespace +namespace Command { + +// This helper structure describes a dive that we want to add. +struct DiveToAdd { + OwningDivePtr dive; // Dive to add + dive_trip *trip; // Trip the dive belongs to, may be null + dive_site *site; // Site the dive is associated with, may be null +}; + +// Multiple trips, dives and dive sites that have to be added for a command +struct DivesAndTripsToAdd { + std::vector<DiveToAdd> dives; + std::vector<OwningTripPtr> trips; + std::vector<OwningDiveSitePtr> sites; +}; + +// Dives and sites that have to be removed for a command +struct DivesAndSitesToRemove { + std::vector<dive *> dives; + std::vector<dive_site *> sites; +}; + +// This helper structure describes a dive that should be moved to / removed from +// a trip. If the "trip" member is null, the dive is removed from its trip (if +// it is in a trip, that is) +struct DiveToTrip +{ + struct dive *dive; + dive_trip *trip; +}; + +// This helper structure describes a number of dives to add to / remove from / +// move between trips. +// It has ownership of the trips (if any) that have to be added before hand. +struct DivesToTrip +{ + std::vector<DiveToTrip> divesToMove; // If dive_trip is null, remove from trip + std::vector<OwningTripPtr> tripsToAdd; +}; + +// All divelist commands derive from a common base class. It keeps track +// of dive site counts that may have changed. +// Derived classes implement the virtual methods redoit() and undoit() +// [Yes, the names could be more expressive]. +class DiveListBase : public Base { +protected: + // These are helper functions to add / remove dive from the C-core structures. + DiveToAdd removeDive(struct dive *d, std::vector<OwningTripPtr> &tripsToAdd); + dive *addDive(DiveToAdd &d); + DivesAndTripsToAdd removeDives(DivesAndSitesToRemove &divesAndSitesToDelete); + DivesAndSitesToRemove addDives(DivesAndTripsToAdd &toAdd); + + // Register dive sites where counts changed so that we can signal the frontend later. + void diveSiteCountChanged(struct dive_site *ds); + +private: + // Keep track of dive sites where the number of dives changed + std::vector<dive_site *> sitesCountChanged; + void initWork(); + void finishWork(); // update dive site counts + void undo() override; + void redo() override; + virtual void redoit() = 0; + virtual void undoit() = 0; +}; + +class AddDive : public DiveListBase { +public: + AddDive(dive *dive, bool autogroup, bool newNumber); +private: + void undoit() override; + void redoit() override; + bool workToBeDone() override; + + // For redo + // Note: we a multi-dive structure even though we add only a single dive, so + // that we can reuse the multi-dive functions of the other commands. + DivesAndTripsToAdd divesToAdd; + + // For undo + DivesAndSitesToRemove divesAndSitesToRemove; + std::vector<dive *> selection; + 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, struct dive_site_table *sites, int flags, const QString &source); +private: + void undoit() override; + void redoit() override; + bool workToBeDone() override; + + // For redo and undo + DivesAndTripsToAdd divesToAdd; + DivesAndSitesToRemove divesAndSitesToRemove; + + // For redo + std::vector<OwningDiveSitePtr> sitesToAdd; + + // For undo + std::vector<dive_site *> sitesToRemove; + std::vector<dive *> selection; + dive * currentDive; +}; + +class DeleteDive : public DiveListBase { +public: + DeleteDive(const QVector<dive *> &divesToDelete); +private: + void undoit() override; + void redoit() override; + bool workToBeDone() override; + + // For redo + DivesAndSitesToRemove divesToDelete; + + std::vector<OwningTripPtr> tripsToAdd; + DivesAndTripsToAdd divesToAdd; +}; + +class ShiftTime : public DiveListBase { +public: + ShiftTime(const QVector<dive *> &changedDives, int amount); +private: + void undoit() override; + void redoit() override; + bool workToBeDone() override; + + // For redo and undo + QVector<dive *> diveList; + int timeChanged; +}; + +class RenumberDives : public DiveListBase { +public: + RenumberDives(const QVector<QPair<dive *, int>> &divesToRenumber); +private: + void undoit() override; + void redoit() override; + bool workToBeDone() override; + + // For redo and undo: pairs of dive-id / new number + QVector<QPair<dive *, int>> divesToRenumber; +}; + +// The classes RemoveDivesFromTrip, RemoveAutogenTrips, CreateTrip, AutogroupDives +// and MergeTrips all do the same thing, just the intialization differs. +// Therefore, define a base class with the proper data-structures, redo() +// and undo() functions and derive to specialize the initialization. +class TripBase : public DiveListBase { +protected: + void undoit() override; + void redoit() override; + bool workToBeDone() override; + + // For redo and undo + DivesToTrip divesToMove; +}; +struct RemoveDivesFromTrip : public TripBase { + RemoveDivesFromTrip(const QVector<dive *> &divesToRemove); +}; +struct RemoveAutogenTrips : public TripBase { + RemoveAutogenTrips(); +}; +struct AddDivesToTrip : public TripBase { + AddDivesToTrip(const QVector<dive *> &divesToAdd, dive_trip *trip); +}; +struct CreateTrip : public TripBase { + CreateTrip(const QVector<dive *> &divesToAdd); +}; +struct AutogroupDives : public TripBase { + AutogroupDives(); +}; +struct MergeTrips : public TripBase { + MergeTrips(dive_trip *trip1, dive_trip *trip2); +}; + +class SplitDivesBase : public DiveListBase { +protected: + SplitDivesBase(dive *old, std::array<dive *, 2> newDives); +private: + void undoit() override; + void redoit() override; + bool workToBeDone() override; + + // For redo + // For each dive to split, we remove one from and put two dives into the backend + // Note: we use a vector even though we split only a single dive, so + // that we can reuse the multi-dive functions of the other commands. + DivesAndSitesToRemove diveToSplit; + DivesAndTripsToAdd splitDives; + + // For undo + // For each dive to unsplit, we remove two dives from and add one into the backend + // Note: we use a multi-dive structure even though we unsplit only a single dive, so + // that we can reuse the multi-dive functions of the other commands. + DivesAndTripsToAdd unsplitDive; + DivesAndSitesToRemove divesToUnsplit; +}; + +class SplitDives : public SplitDivesBase { +public: + // If time is < 0, split at first surface interval + SplitDives(dive *d, duration_t time); +}; + +class SplitDiveComputer : public SplitDivesBase { +public: + // If time is < 0, split at first surface interval + SplitDiveComputer(dive *d, int dc_num); +}; + +// When manipulating dive computers (moving, deleting) we go the ineffective, +// but simple and robust way: We keep two full copies of the dive (before and after). +// Removing and readding assures that the dive stays at the correct +// position in the list (the dive computer list is used for sorting dives). +class DiveComputerBase : public DiveListBase { +protected: + // old_dive must be a dive known to the core. + // new_dive must be new dive whose ownership is taken. + DiveComputerBase(dive *old_dive, dive *new_dive, int dc_nr_after); +private: + void undoit() override; + void redoit() override; + bool workToBeDone() override; + +protected: + // For redo and undo + DivesAndTripsToAdd diveToAdd; + DivesAndSitesToRemove diveToRemove; + int dc_nr_before, dc_nr_after; +}; + +class MoveDiveComputerToFront : public DiveComputerBase { +public: + MoveDiveComputerToFront(dive *d, int dc_num); +}; + +class DeleteDiveComputer : public DiveComputerBase { +public: + DeleteDiveComputer(dive *d, int dc_num); +}; + +class MergeDives : public DiveListBase { +public: + MergeDives(const QVector<dive *> &dives); +private: + void undoit() override; + void redoit() override; + bool workToBeDone() override; + + // For redo + // Add one and remove a batch of dives + // Note: we use a multi-dives structure even though we add only a single dive, so + // that we can reuse the multi-dive functions of the other commands. + DivesAndTripsToAdd mergedDive; + DivesAndSitesToRemove divesToMerge; + + // For undo + // Remove one and add a batch of dives + // Note: we use a vector even though we remove only a single dive, so + // that we can reuse the multi-dive functions of the other commands. + DivesAndSitesToRemove diveToUnmerge; + DivesAndTripsToAdd unmergedDives; + + // For undo and redo + QVector<QPair<dive *, int>> divesToRenumber; +}; + +} // namespace Command + +#endif // COMMAND_DIVELIST_H |