diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-30 11:00:37 -0800 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2012-12-30 19:40:15 -0800 |
commit | 96db56f89c76ffc2ede8605f4b0febb0c2261c5a (patch) | |
tree | a778e24dee638e05ea40ef2f460201f2a8ac8d33 /save-xml.c | |
parent | e3ab1c0701fceffa370d56bff187d0c0e90d5d21 (diff) | |
download | subsurface-96db56f89c76ffc2ede8605f4b0febb0c2261c5a.tar.gz |
Allow overlapping (and disjoint) dive trips
We used to have the rule that a dive trip has to have all dives in it in
sequential order, even though our XML file really is much more flexible,
and allows arbitrary nesting of dives within a dive trip.
Put another way, the old model had fairly inflexible rules:
- the dive array is sorted by time
- a dive trip is always a contiguous slice of this sorted array
which makes perfect sense when you think of the dive and trip list as a
physical activity by one person, but leads to various very subtle issues
in the general case when there are no guarantees that the user then uses
subsurface that way.
In particular, if you load the XML files of two divers that have
overlapping dive trips, the end result is incredibly messy, and does not
conform to the above model at all.
There's two ways to enforce such conformance:
- disallow that kind of behavior entirely.
This is actually hard. Our XML files aren't date-based, they are
based on XML nesting rules, and even a single XML file can have
nesting that violates the date ordering. With multiple XML files,
it's trivial to do in practice, and while we could just fail at
loading, the failure would have to be a hard failure that leaves the
user no way to use the data at all.
- try to "fix it up" by sorting, splitting, and combining dive trips
automatically.
Dirk had a patch to do this, but it really does destroy the actual
dive data: if you load both mine and Dirk's dive trips, you ended up
with a result that followed the above two technical rules, but that
didn't actually make any *sense*.
So this patch doesn't try to enforce the rules, and instead just changes
them to be more generic:
- the dive array is still sorted by dive time
- a dive trip is just an arbitrary collection of dives.
The relaxed rules means that mixing dives and dive trips for two people
is trivial, and we can easily handle any XML file. The dive trip is
defined by the XML nesting level, and is totally independent of any
date-based sorting.
It does require a few things:
- when we save our dive data, we have to do it hierarchically by dive
trip, not just by walking the dive array linearly.
- similarly, when we create the dive tree model, we can't just blindly
walk the array of dives one by one, we have to look up the correct
trip (parent)
- when we try to merge two dives that are adjacent (by date sorting),
we can't do it if they are in different trips.
but apart from that, nothing else really changes.
NOTE! Despite the new relaxed model, creating totally disjoing dive
trips is not all that easy (nor is there any *reason* for it to be
easty). Our GUI interfaces still are "add dive to trip above" etc, and
the automatic adding of dives to dive trips is obviously still based on
date.
So this does not really change the expected normal usage, the relaxed
data structure rules just mean that we don't need to worry about the odd
cases as much, because we can just let them be.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Diffstat (limited to 'save-xml.c')
-rw-r--r-- | save-xml.c | 70 |
1 files changed, 46 insertions, 24 deletions
diff --git a/save-xml.c b/save-xml.c index 61469e9ce..0cfc7ccfd 100644 --- a/save-xml.c +++ b/save-xml.c @@ -374,17 +374,6 @@ static void show_date(FILE *f, timestamp_t when) tm.tm_hour, tm.tm_min, tm.tm_sec); } -static void save_trip(FILE *f, dive_trip_t *trip) -{ - fprintf(f, "<trip"); - show_date(f, trip->when); - if (trip->location) - show_utf8(f, trip->location, " location=\'","\'", 1); - fprintf(f, ">\n"); - if (trip->notes) - show_utf8(f, trip->notes, "<notes>","</notes>\n", 0); -} - static void save_samples(FILE *f, int nr, struct sample *s) { static const struct sample empty_sample; @@ -445,6 +434,33 @@ static void save_dive(FILE *f, struct dive *dive) fprintf(f, "</dive>\n"); } +static void save_trip(FILE *f, dive_trip_t *trip) +{ + int i; + struct dive *dive; + + fprintf(f, "<trip"); + show_date(f, trip->when); + if (trip->location) + show_utf8(f, trip->location, " location=\'","\'", 1); + fprintf(f, ">\n"); + if (trip->notes) + show_utf8(f, trip->notes, "<notes>","</notes>\n", 0); + + /* + * Incredibly cheesy: we want to save the dives sorted, and they + * are sorted in the dive array.. So instead of using the dive + * list in the trip, we just traverse the global dive array and + * check the divetrip pointer.. + */ + for_each_dive(i, dive) { + if (dive->divetrip == trip) + save_dive(f, dive); + } + + fprintf(f, "</trip>\n"); +} + static char *add_dc_to_string(char *dc_xml, struct divecomputer *dc) { char *pattern, *tmp; @@ -483,7 +499,7 @@ void save_dives(const char *filename) { int i; struct dive *dive; - dive_trip_t *trip = NULL; + dive_trip_t *trip; char *dc_xml = strdup(""); FILE *f = g_fopen(filename, "w"); @@ -504,22 +520,28 @@ void save_dives(const char *filename) } fprintf(f, dc_xml); fprintf(f, "</settings>\n<dives>\n"); + + for (trip = dive_trip_list; trip != NULL; trip = trip->next) + trip->index = 0; + /* save the dives */ for_each_dive(i, dive) { - dive_trip_t *thistrip = dive->divetrip; - if (trip != thistrip) { - /* Close the old trip? */ - if (trip) - fprintf(f, "</trip>\n"); - /* Open the new one */ - if (thistrip) - save_trip(f, thistrip); - trip = thistrip; + trip = dive->divetrip; + + /* Bare dive without a trip? */ + if (!trip) { + save_dive(f, dive); + continue; } - save_dive(f, get_dive(i)); + + /* Have we already seen this trip (and thus saved this dive?) */ + if (trip->index) + continue; + + /* We haven't seen this trip before - save it and all dives */ + trip->index = 1; + save_trip(f, trip); } - if (trip) - fprintf(f, "</trip>\n"); fprintf(f, "</dives>\n</divelog>\n"); fclose(f); } |