diff options
Diffstat (limited to 'desktop-widgets/undocommands.cpp')
-rw-r--r-- | desktop-widgets/undocommands.cpp | 155 |
1 files changed, 126 insertions, 29 deletions
diff --git a/desktop-widgets/undocommands.cpp b/desktop-widgets/undocommands.cpp index 16f87fa23..8470e4f2d 100644 --- a/desktop-widgets/undocommands.cpp +++ b/desktop-widgets/undocommands.cpp @@ -88,6 +88,60 @@ static void renumberDives(QVector<QPair<int, int>> &divesToRenumber) } } +// This helper function moves a dive to a trip. The old trip is recorded in the +// passed-in structure. This means that calling the function twice on the same +// object is a no-op concerning the dive. If the old trip was deleted from the +// core, an owning pointer to the removed trip is returned, otherwise a null pointer. +static OwningTripPtr moveDiveToTrip(DiveToTrip &diveToTrip) +{ + // Firstly, check if we move to the same trip and bail if this is a no-op. + if (diveToTrip.trip == diveToTrip.dive->divetrip) + return {}; + + // Remove from old trip + OwningTripPtr res; + + // Remove dive from trip - if this is the last dive in the trip, remove the whole trip. + dive_trip *trip = unregister_dive_from_trip(diveToTrip.dive, false); + if (trip && trip->nrdives == 0) { + unregister_trip(trip); // Remove trip from backend + res.reset(trip); + } + + // Store old trip and get new trip we should associate this dive with + std::swap(trip, diveToTrip.trip); + add_dive_to_trip(diveToTrip.dive, trip); + return res; +} + +// This helper function moves a set of dives between trips using the +// moveDiveToTrip function. Before doing so, it adds the necessary trips to +// the core. Trips that are removed from the core because they are empty +// are recorded in the passed in struct. The vectors of trips and dives +// are reversed. Thus, calling the function twice on the same object is +// a no-op. +static void moveDivesBetweenTrips(DivesToTrip &dives) +{ + // first bring back the trip(s) + for (OwningTripPtr &trip: dives.tripsToAdd) { + dive_trip *t = trip.release(); // Give up ownership + insert_trip(&t); // Return ownership to backend + } + dives.tripsToAdd.clear(); + + for (DiveToTrip &dive: dives.divesToMove) { + OwningTripPtr tripToAdd = moveDiveToTrip(dive); + // register trips that we'll have to readd + if (tripToAdd) + dives.tripsToAdd.push_back(std::move(tripToAdd)); + } + + // Reverse the tripsToAdd and the divesToAdd, so that on undo/redo the operations + // will be performed in reverse order. + std::reverse(dives.tripsToAdd.begin(), dives.tripsToAdd.end()); + std::reverse(dives.divesToMove.begin(), dives.divesToMove.end()); +} + UndoAddDive::UndoAddDive(dive *d) { setText(gettextFromC::tr("add dive")); @@ -196,47 +250,90 @@ void UndoRenumberDives::redo() undo(); } -UndoRemoveDivesFromTrip::UndoRemoveDivesFromTrip(const QVector<dive *> &divesToRemoveIn) : divesToRemove(divesToRemoveIn) +void UndoTripBase::redo() { - setText(tr("remove %n dive(s) from trip", "", divesToRemove.size())); + moveDivesBetweenTrips(divesToMove); + + mark_divelist_changed(true); + + // Finally, do the UI stuff: + MainWindow::instance()->refreshDisplay(); } -void UndoRemoveDivesFromTrip::undo() +void UndoTripBase::undo() { - // first bring back the trip(s) - for (auto &trip: tripsToAdd) { - dive_trip *t = trip.release(); // Give up ownership - insert_trip(&t); // Return ownership to backend + // Redo and undo do the same thing! + redo(); +} + +UndoRemoveDivesFromTrip::UndoRemoveDivesFromTrip(const QVector<dive *> &divesToRemove) +{ + setText(divesToRemove.size() == 1 ? gettextFromC::tr("remove dive from trip") + : gettextFromC::tr("remove %1 dives from trip").arg(divesToRemove.size())); + divesToMove.divesToMove.reserve(divesToRemove.size()); + for (dive *d: divesToRemove) + divesToMove.divesToMove.push_back( {d, nullptr} ); +} + +UndoRemoveAutogenTrips::UndoRemoveAutogenTrips() +{ + setText(gettextFromC::tr("remove autogenerated trips")); + // TODO: don't touch core-innards directly + int i; + struct dive *dive; + for_each_dive(i, dive) { + if (dive->divetrip && dive->divetrip->autogen) + divesToMove.divesToMove.push_back( {dive, nullptr} ); } - tripsToAdd.clear(); +} - for (auto &pair: divesToAdd) - add_dive_to_trip(pair.first, pair.second); - divesToAdd.clear(); - mark_divelist_changed(true); +UndoAddDivesToTrip::UndoAddDivesToTrip(const QVector<dive *> &divesToAddIn, dive_trip *trip) +{ + setText(divesToAddIn.size() == 1 ? gettextFromC::tr("add dives to trip") + : gettextFromC::tr("add %1 dives to trip").arg(divesToAddIn.size())); + for (dive *d: divesToAddIn) + divesToMove.divesToMove.push_back( {d, trip} ); +} - // Finally, do the UI stuff: - MainWindow::instance()->refreshDisplay(); +UndoCreateTrip::UndoCreateTrip(const QVector<dive *> &divesToAddIn) +{ + setText(gettextFromC::tr("create trip")); + + if (divesToAddIn.isEmpty()) + return; + + dive_trip *trip = create_trip_from_dive(divesToAddIn[0]); + divesToMove.tripsToAdd.emplace_back(trip); + for (dive *d: divesToAddIn) + divesToMove.divesToMove.push_back( {d, trip} ); } -void UndoRemoveDivesFromTrip::redo() +UndoAutogroupDives::UndoAutogroupDives() { - for (dive *d: divesToRemove) { - // remove dive from trip - if this is the last dive in the trip - // remove the whole trip. - dive_trip *trip = unregister_dive_from_trip(d, false); - if (!trip) - continue; // This was not part of a trip - if (trip->nrdives == 0) { - unregister_trip(trip); // Remove trip from backend - tripsToAdd.emplace_back(trip); // Take ownership of trip - } - divesToAdd.emplace_back(d, trip); + setText(gettextFromC::tr("autogroup dives")); + + dive_trip *trip; + bool alloc; + int from, to; + for(int i = 0; (trip = get_dives_to_autogroup(i, &from, &to, &alloc)) != NULL; i = to) { + // If this is an allocated trip, take ownership + if (alloc) + divesToMove.tripsToAdd.emplace_back(trip); + for (int j = from; j < to; ++j) + divesToMove.divesToMove.push_back( { get_dive(j), trip } ); } - mark_divelist_changed(true); +} - // Finally, do the UI stuff: - MainWindow::instance()->refreshDisplay(); +UndoMergeTrips::UndoMergeTrips(dive_trip *trip1, dive_trip *trip2) +{ + if (trip1 == trip2) + return; + dive_trip *newTrip = combine_trips_create(trip1, trip2); + divesToMove.tripsToAdd.emplace_back(newTrip); + for (dive *d = trip1->dives; d; d = d->next) + divesToMove.divesToMove.push_back( { d, newTrip } ); + for (dive *d = trip2->dives; d; d = d->next) + divesToMove.divesToMove.push_back( { d, newTrip } ); } UndoSplitDives::UndoSplitDives(dive *d, duration_t time) |