diff options
author | Berthold Stoeger <bstoeger@mail.tuwien.ac.at> | 2018-09-23 21:22:48 +0200 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2018-10-11 16:22:27 -0700 |
commit | f427226b3b605523bc8285dbdaaa7f6993af6e6a (patch) | |
tree | e025722f92883fbac72b3584d6b4fb301bb8a40d /core/divelist.c | |
parent | 4fbb8ef399a356e0b1a7393311c22ca68c50a14d (diff) | |
download | subsurface-f427226b3b605523bc8285dbdaaa7f6993af6e6a.tar.gz |
Undo: make diverse trip-related operations undo-able
AddDivesToTrip, CreateTrip, AutogroupDives, RemoveAutogenTrips
and MergeTrips basically all did the same thing as RemoveDivesFromTrip,
which was already implemented. Thus, factor our the common functionality
and hook it up to make all these functions undo-able.
Don't do the autogroup-call everytime the dive-list is rebuilt
(that would create innumberable undo-actions), but only on dive-load /
import or if expressly asked by the user [by switching the autogroup
flag].
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Diffstat (limited to 'core/divelist.c')
-rw-r--r-- | core/divelist.c | 109 |
1 files changed, 94 insertions, 15 deletions
diff --git a/core/divelist.c b/core/divelist.c index 63bb7aa07..f6453e04c 100644 --- a/core/divelist.c +++ b/core/divelist.c @@ -22,7 +22,10 @@ * void remove_dive_from_trip(struct dive *dive, bool was_autogen) * void add_dive_to_trip(struct dive *dive, dive_trip_t *trip) * dive_trip_t *create_and_hookup_trip_from_dive(struct dive *dive) + * dive_trip_t *get_dives_to_autogroup(int start, int *from, int *to, bool *allocated) * void autogroup_dives(void) + * void combine_trips(struct dive_trip *trip_a, struct dive_trip *trip_b) + * dive_trip_t *combine_trips_create(struct dive_trip *trip_a, struct dive_trip *trip_b) * struct dive *unregister_dive(int idx) * void delete_single_dive(int idx) * void add_single_dive(int idx, struct dive *dive) @@ -877,12 +880,27 @@ void add_dive_to_trip(struct dive *dive, dive_trip_t *trip) trip->when = dive->when; } +dive_trip_t *alloc_trip(void) +{ + return calloc(1, sizeof(dive_trip_t)); +} + +dive_trip_t *create_trip_from_dive(struct dive *dive) +{ + dive_trip_t *trip; + + trip = alloc_trip(); + trip->when = dive->when; + trip->location = copy_string(get_dive_location(dive)); + + return trip; +} + dive_trip_t *create_and_hookup_trip_from_dive(struct dive *dive) { - dive_trip_t *dive_trip = calloc(1, sizeof(dive_trip_t)); + dive_trip_t *dive_trip = alloc_trip(); - dive_trip->when = dive->when; - dive_trip->location = copy_string(get_dive_location(dive)); + dive_trip = create_trip_from_dive(dive); insert_trip(&dive_trip); dive->tripflag = IN_TRIP; @@ -891,14 +909,23 @@ dive_trip_t *create_and_hookup_trip_from_dive(struct dive *dive) } /* - * Walk the dives from the oldest dive, and see if we can autogroup them + * Collect dives for auto-grouping. Pass in first dive which should be checked. + * Returns range of dives that should be autogrouped and trip it should be + * associated to. If the returned trip was newly allocated, the last bool + * is set to true. Caller still has to register it in the system. Note + * whereas this looks complicated - it is needed by the undo-system, which + * manually injects the new trips. If there are no dives to be autogrouped, + * return NULL. */ -void autogroup_dives(void) +dive_trip_t *get_dives_to_autogroup(int start, int *from, int *to, bool *allocated) { int i; struct dive *dive, *lastdive = NULL; - for_each_dive(i, dive) { + /* Find first dive that should be merged and remember any previous + * dive that could be merged into. + */ + for (i = start; (dive = get_dive(i)) != NULL; i++) { dive_trip_t *trip; if (dive->divetrip) { @@ -911,21 +938,53 @@ void autogroup_dives(void) continue; } - /* Do we have a trip we can combine this into? */ - if (lastdive && dive->when < lastdive->when + TRIP_THRESHOLD) { - dive_trip_t *trip = lastdive->divetrip; - add_dive_to_trip(dive, trip); + /* We found a dive, let's see if we have to allocate a new trip */ + if (!lastdive || dive->when >= lastdive->when + TRIP_THRESHOLD) { + /* allocate new trip */ + trip = create_trip_from_dive(dive); + trip->autogen = true; + *allocated = true; + } else { + /* use trip of previous dive */ + trip = lastdive->divetrip; + *allocated = false; + } + + // Now, find all dives that will be added to this trip + lastdive = dive; + *from = i; + for (*to = *from + 1; (dive = get_dive(*to)) != NULL; (*to)++) { + if (dive->divetrip || !DIVE_NEEDS_TRIP(dive) || + dive->when >= lastdive->when + TRIP_THRESHOLD) + break; if (get_dive_location(dive) && !trip->location) trip->location = copy_string(get_dive_location(dive)); lastdive = dive; - continue; } - - lastdive = dive; - trip = create_and_hookup_trip_from_dive(dive); - trip->autogen = 1; + return trip; } + /* Did not find anyhting - mark as end */ + return NULL; +} + +/* + * Walk the dives from the oldest dive, and see if we can autogroup them + */ +void autogroup_dives(void) +{ + int from, to; + dive_trip_t *trip; + int i, j; + bool alloc; + + for(i = 0; (trip = get_dives_to_autogroup(i, &from, &to, &alloc)) != NULL; i = to) { + /* If this was newly allocated, add trip to list */ + if (alloc) + insert_trip(&trip); + for (j = from; j < to; ++j) + add_dive_to_trip(get_dive(j), trip); + } #ifdef DEBUG_TRIP dump_trip_list(); #endif @@ -1209,6 +1268,26 @@ void combine_trips(struct dive_trip *trip_a, struct dive_trip *trip_b) add_dive_to_trip(trip_b->dives, trip_a); } +/* Out of two strings, copy the string that is not empty (if any). */ +static char *copy_non_empty_string(const char *a, const char *b) +{ + return copy_string(empty_string(b) ? a : b); +} + +/* Combine trips new. This combines two trips, generating a + * new trip. To support undo, we have to preserve the old trips. */ +dive_trip_t *combine_trips_create(struct dive_trip *trip_a, struct dive_trip *trip_b) +{ + dive_trip_t *trip; + + trip = alloc_trip(); + trip->when = trip_a->when; + trip->location = copy_non_empty_string(trip_a->location, trip_b->location); + trip->notes = copy_non_empty_string(trip_a->notes, trip_b->notes); + + return trip; +} + void mark_divelist_changed(bool changed) { if (dive_list_changed == changed) |