diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-11-09 19:46:39 +0100 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2012-11-09 21:46:56 +0100 |
commit | 7f515eb7e53c5ab6d8dde4d2e6876464ed7fdeae (patch) | |
tree | f92ba6756103c85a431f18d9333c26374ce29ceb /dive.c | |
parent | 51003eaed71ea823dc8ce88e7de0e785a50b24cb (diff) | |
download | subsurface-7f515eb7e53c5ab6d8dde4d2e6876464ed7fdeae.tar.gz |
Fix dive trip merging logic
We used to have very spotty logic for picking the dive trip when
merging two dives. It turns out that that spotty logic almost never
really matters, because in practice you'll never hit the situation of
merging two dives with different dive trips, but it *can* happen.
In particular, it happens when you use multiple dive computers, and
end up loading the dives from one computer on top of the dives of your
other computer. If the clocks of the dive computers was set
sufficiently close to each other, the dive merging logic will kick in
and you may now have slightly different times for the dives that get
merged, and the trip merging logic got *really* confused.
The trip management also depends on the trip dates being updated
correctly when the dives associated with a trip are updated (whether
added or removed), and the trip merging code did none of that.
This fixes it all up. Hopefully correctly.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Diffstat (limited to 'dive.c')
-rw-r--r-- | dive.c | 94 |
1 files changed, 85 insertions, 9 deletions
@@ -713,11 +713,94 @@ static void merge_equipment(struct dive *res, struct dive *a, struct dive *b) } /* + * When merging two dives, this picks the trip from one, and removes it + * from the other. + * + * The 'next' dive is not involved in the dive merging, but is the dive + * that will be the next dive after the merged dive. + */ +static void pick_and_delete_trip(struct dive *res, struct dive *pick, struct dive *remove, struct dive *next) +{ + tripflag_t tripflag = pick->tripflag; + dive_trip_t *trip = pick->divetrip; + + res->tripflag = tripflag; + res->divetrip = trip; + + /* + * We may have to change the trip date if we picked an earlier + * date for the dive that now uses it. + */ + if (res->when < trip->when) + trip->when = res->when; + + /* Was it the same trip as the removed dive? All good*/ + if (trip == remove->divetrip) + return; + + /* Ok, we're dropping a dive. We may need to fix up the date on it */ + trip = remove->divetrip; + if (trip->when != remove->when) + return; + + if (next && next->divetrip == trip) { + trip->when = next->when; + return; + } + + delete_trip(trip); +} + +/* + * Pick a trip for a dive + */ +static void merge_trip(struct dive *res, struct dive *a, struct dive *b, struct dive *next) +{ + /* + * The larger tripflag is more relevant: we prefer + * take manually assigned trips over auto-generated + * ones. + */ + if (a->tripflag > b->tripflag) + goto pick_a; + + if (a->tripflag < b->tripflag) + goto pick_b; + + /* + * Ok, so the divetrips are equally "important". + * Pick the one with the better description. + */ + if (!a->location) + goto pick_b; + if (!b->location) + goto pick_a; + if (!a->notes) + goto pick_b; + if (!b->notes) + goto pick_a; + + /* + * Ok, so both have location and notes. + * Pick the earlier one. + */ + if (a->when < b->when) + goto pick_a; + goto pick_b; + +pick_a: + pick_and_delete_trip(res, a, b, next); + return; +pick_b: + pick_and_delete_trip(res, b, a, next); +} + +/* * This could do a lot more merging. Right now it really only * merges almost exact duplicates - something that happens easily * with overlapping dive downloads. */ -struct dive *try_to_merge(struct dive *a, struct dive *b) +struct dive *try_to_merge(struct dive *a, struct dive *b, struct dive *next) { struct dive *res; @@ -727,14 +810,7 @@ struct dive *try_to_merge(struct dive *a, struct dive *b) res = alloc_dive(); res->when = a->when; - /* the larger tripflag is more relevant */ - if(a->tripflag > b->tripflag) { - res->tripflag = a->tripflag; - res->divetrip = a->divetrip; - } else { - res->tripflag = b->tripflag; - res->divetrip = b->divetrip; - } + merge_trip(res, a, b, next); MERGE_NONZERO(res, a, b, latitude); MERGE_NONZERO(res, a, b, longitude); MERGE_TXT(res, a, b, location); |