Dive site: add dive site ref-counting

Instead of setting dive->dive_site directly, call the
add_dive_to_dive_site() and unregister_dive_from_dive_site()
functions. In the parser this turned out to be a bit tricky.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2019-03-05 22:58:47 +01:00 committed by Dirk Hohndel
parent c22fd9f4fd
commit e2df38d868
19 changed files with 121 additions and 75 deletions

View file

@ -195,9 +195,9 @@ static unsigned char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive
*/ */
snprintf(buffer, sizeof(buffer), "%s, %s", locality, dive_point); snprintf(buffer, sizeof(buffer), "%s, %s", locality, dive_point);
ds = get_dive_site_by_name(buffer, sites); ds = get_dive_site_by_name(buffer, sites);
dt_dive->dive_site = ds; if (!ds)
if (!dt_dive->dive_site) ds = create_dive_site(buffer, sites);
dt_dive->dive_site = create_dive_site(buffer, sites); add_dive_to_dive_site(dt_dive, ds);
free(locality); free(locality);
locality = NULL; locality = NULL;
free(dive_point); free(dive_point);

View file

@ -662,8 +662,10 @@ void selective_copy_dive(const struct dive *s, struct dive *d, struct dive_compo
d->rating = s->rating; d->rating = s->rating;
if (what.visibility) if (what.visibility)
d->visibility = s->visibility; d->visibility = s->visibility;
if (what.divesite) if (what.divesite) {
d->dive_site = s->dive_site; unregister_dive_from_dive_site(d);
add_dive_to_dive_site(d, s->dive_site);
}
if (what.tags) if (what.tags)
STRUCTURED_LIST_COPY(struct tag_entry, s->tag_list, d->tag_list, copy_tl); STRUCTURED_LIST_COPY(struct tag_entry, s->tag_list, d->tag_list, copy_tl);
if (what.cylinders) if (what.cylinders)
@ -2988,12 +2990,21 @@ static int likely_same_dive(const struct dive *a, const struct dive *b)
* be the old dive and dive b is supposed to be the newly imported * be the old dive and dive b is supposed to be the newly imported
* dive. If the flag "prefer_downloaded" is set, data of the latter * dive. If the flag "prefer_downloaded" is set, data of the latter
* will take priority over the former. * will take priority over the former.
*
* Attn: The dive_site parameter of the dive will be set, but the caller
* still has to register the dive in the dive site!
*/ */
struct dive *try_to_merge(struct dive *a, struct dive *b, bool prefer_downloaded) struct dive *try_to_merge(struct dive *a, struct dive *b, bool prefer_downloaded)
{ {
if (likely_same_dive(a, b)) struct dive *res;
return merge_dives(a, b, 0, prefer_downloaded, NULL); struct dive_site *site;
return NULL;
if (!likely_same_dive(a, b))
return NULL;
res = merge_dives(a, b, 0, prefer_downloaded, NULL, &site);
res->dive_site = site; /* Caller has to call add_dive_to_dive_site()! */
return res;
} }
void free_events(struct event *ev) void free_events(struct event *ev)
@ -3440,10 +3451,12 @@ bool has_planned(const struct dive *dive, bool planned) {
* will take priority over the former. * will take priority over the former.
* *
* The trip the new dive should be associated with (if any) is returned * The trip the new dive should be associated with (if any) is returned
* in the "trip" output paramater. If "trip" is NULL, then the dive will * in the "trip" output parameter.
* instead be added to this trip. *
* The dive site the new dive should be added to (if any) is returned
* in the "dive_site" output parameter.
*/ */
struct dive *merge_dives(const struct dive *a, const struct dive *b, int offset, bool prefer_downloaded, struct dive_trip **trip) struct dive *merge_dives(const struct dive *a, const struct dive *b, int offset, bool prefer_downloaded, struct dive_trip **trip, struct dive_site **site)
{ {
struct dive *res = alloc_dive(); struct dive *res = alloc_dive();
int cylinders_map_a[MAX_CYLINDERS], cylinders_map_b[MAX_CYLINDERS]; int cylinders_map_a[MAX_CYLINDERS], cylinders_map_b[MAX_CYLINDERS];
@ -3490,10 +3503,7 @@ struct dive *merge_dives(const struct dive *a, const struct dive *b, int offset,
join_dive_computers(res, &res->dc, &a->dc, &b->dc, cylinders_map_a, cylinders_map_b, 0); join_dive_computers(res, &res->dc, &a->dc, &b->dc, cylinders_map_a, cylinders_map_b, 0);
/* we take the first dive site, unless it's empty */ /* we take the first dive site, unless it's empty */
if (a->dive_site && !dive_site_is_empty(a->dive_site)) *site = a->dive_site && !dive_site_is_empty(a->dive_site) ? a->dive_site : b->dive_site;
res->dive_site = a->dive_site;
else
res->dive_site = b->dive_site;
fixup_dive(res); fixup_dive(res);
return res; return res;
} }
@ -4034,7 +4044,8 @@ static void dive_set_geodata_from_picture(struct dive *dive, struct picture *pic
if (ds) { if (ds) {
ds->location = picture->location; ds->location = picture->location;
} else { } else {
dive->dive_site = create_dive_site_with_gps("", &picture->location, table); ds = create_dive_site_with_gps("", &picture->location, table);
add_dive_to_dive_site(dive, ds);
invalidate_dive_cache(dive); invalidate_dive_cache(dive);
} }
} }

View file

@ -538,7 +538,7 @@ extern unsigned int dc_airtemp(const struct divecomputer *dc);
extern unsigned int dc_watertemp(const struct divecomputer *dc); extern unsigned int dc_watertemp(const struct divecomputer *dc);
extern int split_dive(const struct dive *dive, struct dive **new1, struct dive **new2); extern int split_dive(const struct dive *dive, struct dive **new1, struct dive **new2);
extern int split_dive_at_time(const struct dive *dive, duration_t time, struct dive **new1, struct dive **new2); extern int split_dive_at_time(const struct dive *dive, duration_t time, struct dive **new1, struct dive **new2);
extern struct dive *merge_dives(const struct dive *a, const struct dive *b, int offset, bool prefer_downloaded, struct dive_trip **trip); extern struct dive *merge_dives(const struct dive *a, const struct dive *b, int offset, bool prefer_downloaded, struct dive_trip **trip, struct dive_site **site);
extern struct dive *try_to_merge(struct dive *a, struct dive *b, bool prefer_downloaded); extern struct dive *try_to_merge(struct dive *a, struct dive *b, bool prefer_downloaded);
extern struct event *clone_event(const struct event *src_ev); extern struct event *clone_event(const struct event *src_ev);
extern void copy_events(const struct divecomputer *s, struct divecomputer *d); extern void copy_events(const struct divecomputer *s, struct divecomputer *d);

View file

@ -1169,6 +1169,7 @@ void delete_single_dive(int idx)
if (dive->selected) if (dive->selected)
deselect_dive(dive); deselect_dive(dive);
remove_dive_from_trip(dive, &trip_table); remove_dive_from_trip(dive, &trip_table);
unregister_dive_from_dive_site(dive);
delete_dive_from_table(&dive_table, idx); delete_dive_from_table(&dive_table, idx);
} }
@ -1337,6 +1338,7 @@ static void merge_imported_dives(struct dive_table *table)
struct dive *prev = table->dives[i - 1]; struct dive *prev = table->dives[i - 1];
struct dive *dive = table->dives[i]; struct dive *dive = table->dives[i];
struct dive *merged; struct dive *merged;
struct dive_site *ds;
/* only try to merge overlapping dives - or if one of the dives has /* only try to merge overlapping dives - or if one of the dives has
* zero duration (that might be a gps marker from the webservice) */ * zero duration (that might be a gps marker from the webservice) */
@ -1348,6 +1350,13 @@ static void merge_imported_dives(struct dive_table *table)
if (!merged) if (!merged)
continue; continue;
/* Add dive to dive site; try_to_merge() does not do that! */
ds = merged->dive_site;
if (ds) {
merged->dive_site = NULL;
add_dive_to_dive_site(merged, ds);
}
/* Overwrite the first of the two dives and remove the second */ /* Overwrite the first of the two dives and remove the second */
free_dive(prev); free_dive(prev);
table->dives[i - 1] = merged; table->dives[i - 1] = merged;
@ -1531,15 +1540,15 @@ void add_imported_dives(struct dive_table *import_table, struct trip_table *impo
process_imported_dives(import_table, import_trip_table, import_sites_table, flags, process_imported_dives(import_table, import_trip_table, import_sites_table, flags,
&dives_to_add, &dives_to_remove, &trips_to_add, &dive_sites_to_add); &dives_to_add, &dives_to_remove, &trips_to_add, &dive_sites_to_add);
/* Add new dives to trip, so that trips don't get deleted /* Add new dives to trip and site to get reference count correct. */
* on deletion of old dives */
for (i = 0; i < dives_to_add.nr; i++) { for (i = 0; i < dives_to_add.nr; i++) {
struct dive *d = dives_to_add.dives[i]; struct dive *d = dives_to_add.dives[i];
struct dive_trip *trip = d->divetrip; struct dive_trip *trip = d->divetrip;
if (!trip) struct dive_site *site = d->dive_site;
continue;
d->divetrip = NULL; d->divetrip = NULL;
d->dive_site = NULL;
add_dive_to_trip(d, trip); add_dive_to_trip(d, trip);
add_dive_to_dive_site(d, site);
} }
/* Remove old dives */ /* Remove old dives */
@ -1716,6 +1725,7 @@ void process_imported_dives(struct dive_table *import_table, struct trip_table *
if (!old_ds) { if (!old_ds) {
/* Dive site doesn't exist. Add it to list of dive sites to be added. */ /* Dive site doesn't exist. Add it to list of dive sites to be added. */
new_ds->dives.nr = 0; /* Caller is responsible for adding dives to site */
add_dive_site_to_table(new_ds, sites_to_add); add_dive_site_to_table(new_ds, sites_to_add);
continue; continue;
} }

View file

@ -339,7 +339,8 @@ void merge_dive_sites(struct dive_site *ref, struct dive_site *dive_sites[], int
for_each_dive(curr_dive, d) { for_each_dive(curr_dive, d) {
if (d->dive_site != dive_sites[i] ) if (d->dive_site != dive_sites[i] )
continue; continue;
d->dive_site = ref; unregister_dive_from_dive_site(d);
add_dive_to_dive_site(d, ref);
invalidate_dive_cache(d); invalidate_dive_cache(d);
} }
} }
@ -377,7 +378,7 @@ void purge_empty_dive_sites(struct dive_site_table *ds_table)
continue; continue;
for_each_dive(j, d) { for_each_dive(j, d) {
if (d->dive_site == ds) if (d->dive_site == ds)
d->dive_site = NULL; unregister_dive_from_dive_site(d);
} }
} }
} }
@ -387,8 +388,10 @@ void add_dive_to_dive_site(struct dive *d, struct dive_site *ds)
int idx; int idx;
if (d->dive_site == ds) if (d->dive_site == ds)
return; return;
if (d->dive_site) if (d->dive_site) {
fprintf(stderr, "Warning: adding dive that already belongs to a dive site to a different site\n"); fprintf(stderr, "Warning: adding dive that already belongs to a dive site to a different site\n");
unregister_dive_from_dive_site(d);
}
idx = dive_table_get_insertion_index(&ds->dives, d); idx = dive_table_get_insertion_index(&ds->dives, d);
add_to_dive_table(&ds->dives, idx, d); add_to_dive_table(&ds->dives, idx, d);
d->dive_site = ds; d->dive_site = ds;

View file

@ -213,7 +213,7 @@ static void copy_gps_location(struct gpsTracker &gps, struct dive *d)
struct dive_site *ds = d->dive_site; struct dive_site *ds = d->dive_site;
if (!ds) { if (!ds) {
ds = create_dive_site(qPrintable(gps.name), &dive_site_table); ds = create_dive_site(qPrintable(gps.name), &dive_site_table);
d->dive_site = ds; add_dive_to_dive_site(d, ds);
} }
ds->location = gps.location; ds->location = gps.location;
} }

View file

@ -197,7 +197,7 @@ static int cobalt_dive(void *param, int columns, char **data, char **column)
return 1; return 1;
} }
sprintf(tmp, "%s / %s", location, location_site); sprintf(tmp, "%s / %s", location, location_site);
state->cur_dive->dive_site = find_or_create_dive_site_with_name(tmp, state->sites); add_dive_to_dive_site(state->cur_dive, find_or_create_dive_site_with_name(tmp, state->sites));
free(tmp); free(tmp);
} }
free(location); free(location);

View file

@ -287,7 +287,7 @@ static int divinglog_dive(void *param, int columns, char **data, char **column)
state->cur_dive->when = (time_t)(atol(data[1])); state->cur_dive->when = (time_t)(atol(data[1]));
if (data[2]) if (data[2])
state->cur_dive->dive_site = find_or_create_dive_site_with_name(data[2], state->sites); add_dive_to_dive_site(state->cur_dive, find_or_create_dive_site_with_name(data[2], state->sites));
if (data[3]) if (data[3])
utf8_string(data[3], &state->cur_dive->buddy); utf8_string(data[3], &state->cur_dive->buddy);

View file

@ -596,8 +596,10 @@ static void parse_string_field(device_data_t *devdata, struct dive *dive, dc_fie
parse_location(line, &location); parse_location(line, &location);
if (location.lat.udeg && location.lon.udeg) if (location.lat.udeg && location.lon.udeg) {
dive->dive_site = create_dive_site_with_gps(str->value, &location, devdata->sites); unregister_dive_from_dive_site(dive);
add_dive_to_dive_site(dive, create_dive_site_with_gps(str->value, &location, devdata->sites));
}
} }
} }
#endif #endif

View file

@ -191,7 +191,7 @@ static void parse_dives(int log_version, const unsigned char *buf, unsigned int
/* Store the location only if we have one */ /* Store the location only if we have one */
if (len || place_len) { if (len || place_len) {
dive->dive_site = find_or_create_dive_site_with_name(location, sites); add_dive_to_dive_site(dive, find_or_create_dive_site_with_name(location, sites));
free(location); free(location);
} }

View file

@ -159,9 +159,8 @@ static void parse_dive_gps(char *line, struct membuffer *str, void *_dive)
if (!ds) { if (!ds) {
ds = get_dive_site_by_gps(&location, &dive_site_table); ds = get_dive_site_by_gps(&location, &dive_site_table);
if (!ds) if (!ds)
dive->dive_site = create_dive_site_with_gps("", &location, &dive_site_table); ds = create_dive_site_with_gps("", &location, &dive_site_table);
else add_dive_to_dive_site(dive, ds);
dive->dive_site = ds;
} else { } else {
if (dive_site_has_gps_location(ds) && !same_location(&ds->location, &location)) { if (dive_site_has_gps_location(ds) && !same_location(&ds->location, &location)) {
char *coords = printGPSCoordsC(&location); char *coords = printGPSCoordsC(&location);
@ -183,9 +182,8 @@ static void parse_dive_location(char *line, struct membuffer *str, void *_dive)
if (!ds) { if (!ds) {
ds = get_dive_site_by_name(name, &dive_site_table); ds = get_dive_site_by_name(name, &dive_site_table);
if (!ds) if (!ds)
dive->dive_site = create_dive_site(name, &dive_site_table); ds = create_dive_site(name, &dive_site_table);
else add_dive_to_dive_site(dive, ds);
dive->dive_site = ds;
} else { } else {
// we already had a dive site linked to the dive // we already had a dive site linked to the dive
if (empty_string(ds->name)) { if (empty_string(ds->name)) {
@ -212,7 +210,7 @@ static void parse_dive_notes(char *line, struct membuffer *str, void *_dive)
{ UNUSED(line); struct dive *dive = _dive; dive->notes = get_utf8(str); } { UNUSED(line); struct dive *dive = _dive; dive->notes = get_utf8(str); }
static void parse_dive_divesiteid(char *line, struct membuffer *str, void *_dive) static void parse_dive_divesiteid(char *line, struct membuffer *str, void *_dive)
{ UNUSED(str); struct dive *dive = _dive; dive->dive_site = get_dive_site_by_uuid(get_hex(line), &dive_site_table); } { UNUSED(str); struct dive *dive = _dive; add_dive_to_dive_site(dive, get_dive_site_by_uuid(get_hex(line), &dive_site_table)); }
/* /*
* We can have multiple tags in the membuffer. They are separated by * We can have multiple tags in the membuffer. They are separated by

View file

@ -558,11 +558,11 @@ static void hex_value(char *buffer, uint32_t *i)
*i = strtoul(buffer, NULL, 16); *i = strtoul(buffer, NULL, 16);
} }
static void dive_site(char *buffer, struct dive_site **ds, struct parser_state *state) static void dive_site(char *buffer, struct dive *d, struct parser_state *state)
{ {
uint32_t uuid; uint32_t uuid;
hex_value(buffer, &uuid); hex_value(buffer, &uuid);
*ds = get_dive_site_by_uuid(uuid, state->sites); add_dive_to_dive_site(d, get_dive_site_by_uuid(uuid, state->sites));
} }
static void get_notrip(char *buffer, bool *notrip) static void get_notrip(char *buffer, bool *notrip)
@ -972,9 +972,10 @@ static void try_to_fill_sample(struct sample *sample, const char *name, char *bu
nonmatch("sample", name, buf); nonmatch("sample", name, buf);
} }
static void divinglog_place(char *place, struct dive_site **ds, struct parser_state *state) static void divinglog_place(char *place, struct dive *d, struct parser_state *state)
{ {
char buffer[1024]; char buffer[1024];
struct dive_site *ds;
snprintf(buffer, sizeof(buffer), snprintf(buffer, sizeof(buffer),
"%s%s%s%s%s", "%s%s%s%s%s",
@ -983,9 +984,10 @@ static void divinglog_place(char *place, struct dive_site **ds, struct parser_st
state->city ? state->city : "", state->city ? state->city : "",
state->country ? ", " : "", state->country ? ", " : "",
state->country ? state->country : ""); state->country ? state->country : "");
*ds = get_dive_site_by_name(buffer, state->sites); ds = get_dive_site_by_name(buffer, state->sites);
if (!*ds) if (!ds)
*ds = create_dive_site(buffer, state->sites); ds = create_dive_site(buffer, state->sites);
add_dive_to_dive_site(d, ds);
// TODO: capture the country / city info in the taxonomy instead // TODO: capture the country / city info in the taxonomy instead
free(state->city); free(state->city);
@ -1010,7 +1012,7 @@ static int divinglog_dive_match(struct dive *dive, const char *name, char *buf,
MATCH("names.buddy", utf8_string, &dive->buddy) || MATCH("names.buddy", utf8_string, &dive->buddy) ||
MATCH("name.country", utf8_string, &state->country) || MATCH("name.country", utf8_string, &state->country) ||
MATCH("name.city", utf8_string, &state->city) || MATCH("name.city", utf8_string, &state->city) ||
MATCH_STATE("name.place", divinglog_place, &dive->dive_site) || MATCH_STATE("name.place", divinglog_place, dive) ||
0; 0;
} }
@ -1137,7 +1139,7 @@ static void gps_lat(char *buffer, struct dive *dive, struct parser_state *state)
location.lat = parse_degrees(buffer, &end); location.lat = parse_degrees(buffer, &end);
if (!ds) { if (!ds) {
dive->dive_site = create_dive_site_with_gps(NULL, &location, state->sites); add_dive_to_dive_site(dive, create_dive_site_with_gps(NULL, &location, state->sites));
} else { } else {
if (ds->location.lat.udeg && ds->location.lat.udeg != location.lat.udeg) if (ds->location.lat.udeg && ds->location.lat.udeg != location.lat.udeg)
fprintf(stderr, "Oops, changing the latitude of existing dive site id %8x name %s; not good\n", ds->uuid, ds->name ?: "(unknown)"); fprintf(stderr, "Oops, changing the latitude of existing dive site id %8x name %s; not good\n", ds->uuid, ds->name ?: "(unknown)");
@ -1153,7 +1155,7 @@ static void gps_long(char *buffer, struct dive *dive, struct parser_state *state
location.lon = parse_degrees(buffer, &end); location.lon = parse_degrees(buffer, &end);
if (!ds) { if (!ds) {
dive->dive_site = create_dive_site_with_gps(NULL, &location, state->sites); add_dive_to_dive_site(dive, create_dive_site_with_gps(NULL, &location, state->sites));
} else { } else {
if (ds->location.lon.udeg && ds->location.lon.udeg != location.lon.udeg) if (ds->location.lon.udeg && ds->location.lon.udeg != location.lon.udeg)
fprintf(stderr, "Oops, changing the longitude of existing dive site id %8x name %s; not good\n", ds->uuid, ds->name ?: "(unknown)"); fprintf(stderr, "Oops, changing the longitude of existing dive site id %8x name %s; not good\n", ds->uuid, ds->name ?: "(unknown)");
@ -1189,10 +1191,10 @@ static void gps_in_dive(char *buffer, struct dive *dive, struct parser_state *st
// found a site nearby; in case it turns out this one had a different name let's // found a site nearby; in case it turns out this one had a different name let's
// remember the original coordinates so we can create the correct dive site later // remember the original coordinates so we can create the correct dive site later
state->cur_location = location; state->cur_location = location;
dive->dive_site = ds;
} else { } else {
dive->dive_site = create_dive_site_with_gps("", &location, state->sites); ds = create_dive_site_with_gps("", &location, state->sites);
} }
add_dive_to_dive_site(dive, ds);
} else { } else {
if (dive_site_has_gps_location(ds) && if (dive_site_has_gps_location(ds) &&
has_location(&location) && !same_location(&ds->location, &location)) { has_location(&location) && !same_location(&ds->location, &location)) {
@ -1234,7 +1236,7 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf, str
default: default:
break; break;
} }
if (MATCH_STATE("divesiteid", dive_site, &dive->dive_site)) if (MATCH_STATE("divesiteid", dive_site, dive))
return; return;
if (MATCH("number", get_index, &dive->number)) if (MATCH("number", get_index, &dive->number))
return; return;
@ -2122,7 +2124,7 @@ int parse_dlf_buffer(unsigned char *buffer, size_t size, struct dive_table *tabl
/* Measure GPS */ /* Measure GPS */
state.cur_location.lat.udeg = (int)((ptr[7] << 24) + (ptr[6] << 16) + (ptr[5] << 8) + (ptr[4] << 0)); state.cur_location.lat.udeg = (int)((ptr[7] << 24) + (ptr[6] << 16) + (ptr[5] << 8) + (ptr[4] << 0));
state.cur_location.lon.udeg = (int)((ptr[11] << 24) + (ptr[10] << 16) + (ptr[9] << 8) + (ptr[8] << 0)); state.cur_location.lon.udeg = (int)((ptr[11] << 24) + (ptr[10] << 16) + (ptr[9] << 8) + (ptr[8] << 0));
state.cur_dive->dive_site = create_dive_site_with_gps("DLF imported", &state.cur_location, state.sites); add_dive_to_dive_site(state.cur_dive, create_dive_site_with_gps("DLF imported", &state.cur_location, state.sites));
break; break;
default: default:
break; break;

View file

@ -415,14 +415,14 @@ void add_dive_site(char *ds_name, struct dive *dive, struct parser_state *state)
char *buffer = ds_name; char *buffer = ds_name;
char *to_free = NULL; char *to_free = NULL;
int size = trimspace(buffer); int size = trimspace(buffer);
if(size) { if (size) {
struct dive_site *ds = dive->dive_site; struct dive_site *ds = dive->dive_site;
if (!ds) { if (!ds) {
// if the dive doesn't have a uuid, check if there's already a dive site by this name // if the dive doesn't have a dive site, check if there's already a dive site by this name
ds = get_dive_site_by_name(buffer, state->sites); ds = get_dive_site_by_name(buffer, state->sites);
} }
if (ds) { if (ds) {
// we have a uuid, let's hope there isn't a different name // we have a dive site, let's hope there isn't a different name
if (empty_string(ds->name)) { if (empty_string(ds->name)) {
ds->name = copy_string(buffer); ds->name = copy_string(buffer);
} else if (!same_string(ds->name, buffer)) { } else if (!same_string(ds->name, buffer)) {
@ -432,10 +432,12 @@ void add_dive_site(char *ds_name, struct dive *dive, struct parser_state *state)
// way around // way around
struct dive_site *exact_match = get_dive_site_by_gps_and_name(buffer, &ds->location, state->sites); struct dive_site *exact_match = get_dive_site_by_gps_and_name(buffer, &ds->location, state->sites);
if (exact_match) { if (exact_match) {
dive->dive_site = exact_match; unregister_dive_from_dive_site(dive);
add_dive_to_dive_site(dive, exact_match);
} else { } else {
struct dive_site *newds = create_dive_site(buffer, state->sites); struct dive_site *newds = create_dive_site(buffer, state->sites);
dive->dive_site = newds; unregister_dive_from_dive_site(dive);
add_dive_to_dive_site(dive, newds);
if (has_location(&state->cur_location)) { if (has_location(&state->cur_location)) {
// we started this uuid with GPS data, so lets use those // we started this uuid with GPS data, so lets use those
newds->location = state->cur_location; newds->location = state->cur_location;
@ -444,12 +446,13 @@ void add_dive_site(char *ds_name, struct dive *dive, struct parser_state *state)
} }
newds->notes = add_to_string(newds->notes, translate("gettextFromC", "additional name for site: %s\n"), ds->name); newds->notes = add_to_string(newds->notes, translate("gettextFromC", "additional name for site: %s\n"), ds->name);
} }
} else { } else if (dive->dive_site != ds) {
// add the existing dive site to the current dive // add the existing dive site to the current dive
dive->dive_site = ds; unregister_dive_from_dive_site(dive);
add_dive_to_dive_site(dive, ds);
} }
} else { } else {
dive->dive_site = create_dive_site(buffer, state->sites); add_dive_to_dive_site(dive, create_dive_site(buffer, state->sites));
} }
} }
free(to_free); free(to_free);

View file

@ -996,7 +996,8 @@ static bool process_raw_buffer(device_data_t *devdata, uint32_t deviceid, char *
int divespot_id = atoi(val); int divespot_id = atoi(val);
if (divespot_id != -1) { if (divespot_id != -1) {
struct dive_site *ds = create_dive_site("from Uemis", devdata->sites); struct dive_site *ds = create_dive_site("from Uemis", devdata->sites);
dive->dive_site = ds; unregister_dive_from_dive_site(dive);
add_dive_to_dive_site(dive, ds);
uemis_mark_divelocation(dive->dc.diveid, divespot_id, ds); uemis_mark_divelocation(dive->dc.diveid, divespot_id, ds);
} }
#if UEMIS_DEBUG & 2 #if UEMIS_DEBUG & 2
@ -1182,7 +1183,8 @@ static void get_uemis_divespot(device_data_t *devdata, const char *mountpath, in
if (is_divespot_mappable(divespot_id)) { if (is_divespot_mappable(divespot_id)) {
struct dive_site *ds = get_dive_site_by_divespot_id(divespot_id); struct dive_site *ds = get_dive_site_by_divespot_id(divespot_id);
dive->dive_site = ds; unregister_dive_from_dive_site(dive);
add_dive_to_dive_site(dive, ds);
} else if (nds && nds->name && strstr(nds->name,"from Uemis")) { } else if (nds && nds->name && strstr(nds->name,"from Uemis")) {
if (load_uemis_divespot(mountpath, divespot_id)) { if (load_uemis_divespot(mountpath, divespot_id)) {
/* get the divesite based on the diveid, this should give us /* get the divesite based on the diveid, this should give us
@ -1198,7 +1200,8 @@ static void get_uemis_divespot(device_data_t *devdata, const char *mountpath, in
/* if the uuid's are the same, the new site is a duplicate and can be deleted */ /* if the uuid's are the same, the new site is a duplicate and can be deleted */
if (nds->uuid != ods->uuid) { if (nds->uuid != ods->uuid) {
delete_dive_site(nds, devdata->sites); delete_dive_site(nds, devdata->sites);
dive->dive_site = ods; unregister_dive_from_dive_site(dive);
add_dive_to_dive_site(dive, ods);
} }
} }
add_to_divespot_mapping(divespot_id, dive->dive_site); add_to_divespot_mapping(divespot_id, dive->dive_site);

View file

@ -66,9 +66,10 @@ DiveToAdd DiveListBase::removeDive(struct dive *d, std::vector<OwningTripPtr> &t
if (res.idx < 0) if (res.idx < 0)
qWarning() << "Deletion of unknown dive!"; qWarning() << "Deletion of unknown dive!";
// remove dive from trip - if this is the last dive in the trip // remove dive from trip and site - if this is the last dive in the trip
// remove the whole trip. // remove the whole trip.
res.trip = unregister_dive_from_trip(d); res.trip = unregister_dive_from_trip(d);
res.site = unregister_dive_from_dive_site(d);
if (res.trip && res.trip->dives.nr == 0) { if (res.trip && res.trip->dives.nr == 0) {
unregister_trip(res.trip, &trip_table); // Remove trip from backend unregister_trip(res.trip, &trip_table); // Remove trip from backend
tripsToAdd.emplace_back(res.trip); // Take ownership of trip tripsToAdd.emplace_back(res.trip); // Take ownership of trip
@ -86,6 +87,8 @@ dive *DiveListBase::addDive(DiveToAdd &d)
{ {
if (d.trip) if (d.trip)
add_dive_to_trip(d.dive.get(), d.trip); add_dive_to_trip(d.dive.get(), d.trip);
if (d.site)
add_dive_to_dive_site(d.dive.get(), d.site);
dive *res = d.dive.release(); // Give up ownership of dive dive *res = d.dive.release(); // Give up ownership of dive
// Set the filter flag according to current filter settings // Set the filter flag according to current filter settings
@ -516,9 +519,11 @@ AddDive::AddDive(dive *d, const QString &newDS, bool autogroup, bool newNumber)
// If we alloc a new-trip for autogrouping, get an owning pointer to it. // If we alloc a new-trip for autogrouping, get an owning pointer to it.
OwningTripPtr allocTrip; OwningTripPtr allocTrip;
dive_trip *trip = divePtr->divetrip; dive_trip *trip = divePtr->divetrip;
// We have to delete the pointer-to-trip, because this would prevent the core from adding to the trip dive_site *site = divePtr->dive_site;
// and we would get the count-of-dives in the trip wrong. Yes, that's all horribly subtle! // We have to delete the pointers to trip and site, because this would prevent the core from adding to the
// trip or site and we would get the count-of-dives in the trip or site wrong. Yes, that's all horribly subtle!
divePtr->divetrip = nullptr; divePtr->divetrip = nullptr;
divePtr->dive_site = nullptr;
if (!trip && autogroup) { if (!trip && autogroup) {
bool alloc; bool alloc;
trip = get_trip_for_new_dive(divePtr.get(), &alloc); trip = get_trip_for_new_dive(divePtr.get(), &alloc);
@ -530,7 +535,7 @@ AddDive::AddDive(dive *d, const QString &newDS, bool autogroup, bool newNumber)
if (newNumber) if (newNumber)
divePtr->number = get_dive_nr_at_idx(idx); divePtr->number = get_dive_nr_at_idx(idx);
divesToAdd.dives.push_back({ std::move(divePtr), trip, idx }); divesToAdd.dives.push_back({ std::move(divePtr), trip, site, idx });
if (allocTrip) if (allocTrip)
divesToAdd.trips.push_back(std::move(allocTrip)); divesToAdd.trips.push_back(std::move(allocTrip));
} }
@ -599,13 +604,15 @@ ImportDives::ImportDives(struct dive_table *dives, struct trip_table *trips, str
divePtr->selected = false; // See above in AddDive::AddDive() divePtr->selected = false; // See above in AddDive::AddDive()
dive_trip *trip = divePtr->divetrip; dive_trip *trip = divePtr->divetrip;
divePtr->divetrip = nullptr; // See above in AddDive::AddDive() divePtr->divetrip = nullptr; // See above in AddDive::AddDive()
dive_site *site = divePtr->dive_site;
divePtr->dive_site = nullptr; // See above in AddDive::AddDive()
int idx = dive_table_get_insertion_index(&dive_table, divePtr.get()); int idx = dive_table_get_insertion_index(&dive_table, divePtr.get());
// Note: The dives are added in reverse order of the divesToAdd array. // Note: The dives are added in reverse order of the divesToAdd array.
// This, and the fact that we populate the array in chronological order // This, and the fact that we populate the array in chronological order
// means that wo do *not* have to manipulated the indices. // means that wo do *not* have to manipulated the indices.
// Yes, that's all horribly subtle. // Yes, that's all horribly subtle.
divesToAdd.dives.push_back({ std::move(divePtr), trip, idx }); divesToAdd.dives.push_back({ std::move(divePtr), trip, site, idx });
} }
// Add dive to be deleted to the divesToRemove structure // Add dive to be deleted to the divesToRemove structure
@ -969,7 +976,8 @@ MergeDives::MergeDives(const QVector <dive *> &dives)
} }
dive_trip *preferred_trip; dive_trip *preferred_trip;
OwningDivePtr d(merge_dives(dives[0], dives[1], dives[1]->when - dives[0]->when, false, &preferred_trip)); dive_site *preferred_site;
OwningDivePtr d(merge_dives(dives[0], dives[1], dives[1]->when - dives[0]->when, false, &preferred_trip, &preferred_site));
// Currently, the core code selects the dive -> this is not what we want, as // Currently, the core code selects the dive -> this is not what we want, as
// we manually manage the selection post-command. // we manually manage the selection post-command.
@ -979,13 +987,15 @@ MergeDives::MergeDives(const QVector <dive *> &dives)
// Set the preferred dive trip, so that for subsequent merges the better trip can be selected // Set the preferred dive trip, so that for subsequent merges the better trip can be selected
d->divetrip = preferred_trip; d->divetrip = preferred_trip;
for (int i = 2; i < dives.count(); ++i) { for (int i = 2; i < dives.count(); ++i) {
d.reset(merge_dives(d.get(), dives[i], dives[i]->when - d->when, false, &preferred_trip)); d.reset(merge_dives(d.get(), dives[i], dives[i]->when - d->when, false, &preferred_trip, &preferred_site));
// Set the preferred dive trip, so that for subsequent merges the better trip can be selected // Set the preferred dive trip and site, so that for subsequent merges the better trip and site can be selected
d->divetrip = preferred_trip; d->divetrip = preferred_trip;
d->dive_site = preferred_site;
} }
// We got our preferred trip, so now the reference can be deleted from the newly generated dive // We got our preferred trip and site, so now the references can be deleted from the newly generated dive
d->divetrip = nullptr; d->divetrip = nullptr;
d->dive_site = nullptr;
// The merged dive gets the number of the first dive // The merged dive gets the number of the first dive
d->number = dives[0]->number; d->number = dives[0]->number;

View file

@ -12,10 +12,10 @@
namespace Command { namespace Command {
// This helper structure describes a dive that we want to add. // This helper structure describes a dive that we want to add.
// Potentially it also adds a trip (if deletion of the dive resulted in deletion of the trip)
struct DiveToAdd { struct DiveToAdd {
OwningDivePtr dive; // Dive to add OwningDivePtr dive; // Dive to add
dive_trip *trip; // Trip the dive belongs to, may be null dive_trip *trip; // Trip the dive belongs to, may be null
dive_site *site; // Site the dive is associated with, may be null
int idx; // Position in divelist int idx; // Position in divelist
}; };

View file

@ -47,7 +47,8 @@ static void copy_gps_location(struct dive *from, struct dive *to)
struct dive_site *gds = get_dive_site_for_dive(from); struct dive_site *gds = get_dive_site_for_dive(from);
if (!ds) { if (!ds) {
// simply link to the one created for the fake dive // simply link to the one created for the fake dive
to->dive_site = gds; unregister_dive_from_dive_site(to);
add_dive_to_dive_site(to, gds);
} else { } else {
ds->latitude = gds->latitude; ds->latitude = gds->latitude;
ds->longitude = gds->longitude; ds->longitude = gds->longitude;

View file

@ -674,7 +674,8 @@ struct dive_site *MainTab::updateDiveSite(struct dive_site *pickedDs, dive *d)
} }
} }
d->dive_site = pickedDs; unregister_dive_from_dive_site(d);
add_dive_to_dive_site(d, pickedDs);
qDebug() << "Setting the dive site id on the dive:" << pickedDs->uuid; qDebug() << "Setting the dive site id on the dive:" << pickedDs->uuid;
return pickedDs; return pickedDs;
} }

View file

@ -775,7 +775,8 @@ static void setupDivesite(struct dive *d, struct dive_site *ds, double lat, doub
if (ds) { if (ds) {
ds->location = location; ds->location = location;
} else { } else {
d->dive_site = create_dive_site_with_gps(locationtext, &location, &dive_site_table); unregister_dive_from_dive_site(d);
add_dive_to_dive_site(d, create_dive_site_with_gps(locationtext, &location, &dive_site_table));
} }
} }
@ -894,7 +895,8 @@ bool QMLManager::checkLocation(DiveObjectHelper *myDive, struct dive *d, QString
ds = get_dive_site_by_name(qPrintable(location), &dive_site_table); ds = get_dive_site_by_name(qPrintable(location), &dive_site_table);
if (!ds && !location.isEmpty()) if (!ds && !location.isEmpty())
ds = create_dive_site(qPrintable(location), &dive_site_table); ds = create_dive_site(qPrintable(location), &dive_site_table);
d->dive_site = ds; unregister_dive_from_dive_site(d);
add_dive_to_dive_site(d, ds);
} }
// now make sure that the GPS coordinates match - if the user changed the name but not // now make sure that the GPS coordinates match - if the user changed the name but not
// the GPS coordinates, this still does the right thing as the now new dive site will // the GPS coordinates, this still does the right thing as the now new dive site will