// 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 // 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 dives; std::vector trips; std::vector sites; }; // Dives and sites that have to be removed for a command struct DivesAndSitesToRemove { std::vector dives; std::vector 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 divesToMove; // If dive_trip is null, remove from trip std::vector 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 &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 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 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 sitesToAdd; // For undo std::vector sitesToRemove; std::vector selection; dive * currentDive; }; class DeleteDive : public DiveListBase { public: DeleteDive(const QVector &divesToDelete); private: void undoit() override; void redoit() override; bool workToBeDone() override; // For redo DivesAndSitesToRemove divesToDelete; std::vector tripsToAdd; DivesAndTripsToAdd divesToAdd; }; class ShiftTime : public DiveListBase { public: ShiftTime(const QVector &changedDives, int amount); private: void undoit() override; void redoit() override; bool workToBeDone() override; // For redo and undo QVector diveList; int timeChanged; }; class RenumberDives : public DiveListBase { public: RenumberDives(const QVector> &divesToRenumber); private: void undoit() override; void redoit() override; bool workToBeDone() override; // For redo and undo: pairs of dive-id / new number QVector> 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 &divesToRemove); }; struct RemoveAutogenTrips : public TripBase { RemoveAutogenTrips(); }; struct AddDivesToTrip : public TripBase { AddDivesToTrip(const QVector &divesToAdd, dive_trip *trip); }; struct CreateTrip : public TripBase { CreateTrip(const QVector &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 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 &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> divesToRenumber; }; } // namespace Command #endif // COMMAND_DIVELIST_H