diff options
author | Dirk Hohndel <dirk@hohndel.org> | 2015-02-13 23:52:41 -0800 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2015-02-13 23:52:41 -0800 |
commit | 56de6b73f67d5ddeec74153303a27866e39279c7 (patch) | |
tree | 45040e1fb23c26e12b3002e9381f13717a9eb78d | |
parent | 2843dc38c9e64e87ac1ee84e2cb0147f630ab117 (diff) | |
parent | f81e2c111d9c563a78e62c3bae64bec07c052ec0 (diff) | |
download | subsurface-56de6b73f67d5ddeec74153303a27866e39279c7.tar.gz |
Merge branch 'divesites'
This brings in the dive site infrastructure and initial UI work
-rw-r--r-- | dive.c | 24 | ||||
-rw-r--r-- | dive.h | 58 | ||||
-rw-r--r-- | divelist.c | 9 | ||||
-rw-r--r-- | divesite.c | 118 | ||||
-rw-r--r-- | divesite.h | 61 | ||||
-rw-r--r-- | liquivision.c | 17 | ||||
-rw-r--r-- | load-git.c | 102 | ||||
-rw-r--r-- | parse-xml.c | 217 | ||||
-rw-r--r-- | qt-ui/completionmodels.cpp | 14 | ||||
-rw-r--r-- | qt-ui/divecomponentselection.ui | 57 | ||||
-rw-r--r-- | qt-ui/filtermodels.cpp | 4 | ||||
-rw-r--r-- | qt-ui/globe.cpp | 51 | ||||
-rw-r--r-- | qt-ui/locationInformation.ui | 75 | ||||
-rw-r--r-- | qt-ui/maintab.cpp | 100 | ||||
-rw-r--r-- | qt-ui/maintab.h | 7 | ||||
-rw-r--r-- | qt-ui/maintab.ui | 130 | ||||
-rw-r--r-- | qt-ui/mainwindow.cpp | 26 | ||||
-rw-r--r-- | qt-ui/mainwindow.h | 5 | ||||
-rw-r--r-- | qt-ui/models.cpp | 6 | ||||
-rw-r--r-- | qt-ui/printlayout.cpp | 2 | ||||
-rw-r--r-- | qt-ui/simplewidgets.cpp | 97 | ||||
-rw-r--r-- | qt-ui/simplewidgets.h | 25 | ||||
-rw-r--r-- | qt-ui/socialnetworks.cpp | 2 | ||||
-rw-r--r-- | qt-ui/subsurfacewebservices.cpp | 51 | ||||
-rw-r--r-- | qthelper.cpp | 2 | ||||
-rw-r--r-- | save-git.c | 41 | ||||
-rw-r--r-- | save-html.c | 9 | ||||
-rw-r--r-- | save-xml.c | 75 | ||||
-rw-r--r-- | subsurface.pro | 5 | ||||
-rw-r--r-- | uemis-downloader.c | 7 | ||||
-rw-r--r-- | uemis.c | 23 | ||||
-rw-r--r-- | uemis.h | 2 | ||||
-rw-r--r-- | worldmap-save.c | 10 |
33 files changed, 1063 insertions, 369 deletions
@@ -13,6 +13,7 @@ * it's used in the UI, but it seems to make the most sense to have it * here */ struct dive displayed_dive; +struct dive_site displayed_dive_site; struct tag_entry *g_tag_list = NULL; @@ -437,7 +438,6 @@ void clear_dive(struct dive *d) /* free the strings */ free(d->buddy); free(d->divemaster); - free(d->location); free(d->notes); free(d->suit); /* free tags, additional dive computers, and pictures */ @@ -463,7 +463,6 @@ void copy_dive(struct dive *s, struct dive *d) *d = *s; d->buddy = copy_string(s->buddy); d->divemaster = copy_string(s->divemaster); - d->location = copy_string(s->location); d->notes = copy_string(s->notes); d->suit = copy_string(s->suit); for (int i = 0; i < MAX_CYLINDERS; i++) @@ -500,7 +499,6 @@ void selective_copy_dive(struct dive *s, struct dive *d, struct dive_components { if (clear) clear_dive(d); - CONDITIONAL_COPY_STRING(location); CONDITIONAL_COPY_STRING(notes); CONDITIONAL_COPY_STRING(divemaster); CONDITIONAL_COPY_STRING(buddy); @@ -509,10 +507,8 @@ void selective_copy_dive(struct dive *s, struct dive *d, struct dive_components d->rating = s->rating; if (what.visibility) d->visibility = s->visibility; - if (what.gps) { - d->longitude = s->longitude; - d->latitude = s->latitude; - } + if (what.divesite) + d->dive_site_uuid = s->dive_site_uuid; if (what.tags) STRUCTURED_LIST_COPY(struct tag_entry, s->tag_list, d->tag_list, copy_tl); if (what.cylinders) @@ -2699,7 +2695,7 @@ int count_dives_with_location(const char *location) struct dive *d; for_each_dive (i, d) { - if (same_string(d->location, location)) + if (same_string(get_dive_location(d), location)) counter++; } return counter; @@ -2744,9 +2740,6 @@ struct dive *merge_dives(struct dive *a, struct dive *b, int offset, bool prefer res->when = dl ? dl->when : a->when; res->selected = a->selected || b->selected; merge_trip(res, a, b); - MERGE_NONZERO(res, a, b, latitude.udeg); - MERGE_NONZERO(res, a, b, longitude.udeg); - MERGE_TXT(res, a, b, location); MERGE_TXT(res, a, b, notes); MERGE_TXT(res, a, b, buddy); MERGE_TXT(res, a, b, divemaster); @@ -2766,7 +2759,7 @@ struct dive *merge_dives(struct dive *a, struct dive *b, int offset, bool prefer interleave_dive_computers(&res->dc, &a->dc, &b->dc, offset); else join_dive_computers(&res->dc, &a->dc, &b->dc, 0); - + res->dive_site_uuid = a->dive_site_uuid ?: b->dive_site_uuid; fixup_dive(res); return res; } @@ -2931,9 +2924,10 @@ unsigned int dive_get_picture_count(struct dive *d) void dive_set_geodata_from_picture(struct dive *d, struct picture *pic) { - if (!d->latitude.udeg && pic->latitude.udeg) { - d->latitude = pic->latitude; - d->longitude = pic->longitude; + struct dive_site *ds = get_dive_site_by_uuid(d->dive_site_uuid); + if (!dive_site_has_gps_location(ds) && (pic->latitude.udeg || pic->longitude.udeg)) { + ds->latitude = pic->latitude; + ds->longitude = pic->longitude; } } @@ -8,6 +8,7 @@ #include <zip.h> #include <sqlite3.h> #include <string.h> +#include "divesite.h" /* Windows has no MIN/MAX macros - so let's just roll our own */ #define MIN(x, y) ({ \ @@ -47,6 +48,8 @@ extern "C" { #include <stdbool.h> #endif +extern int last_xml_version; + enum dive_comp_type {OC, CCR, PSCR, FREEDIVE, NUM_DC_TYPE}; // Flags (Open-circuit and Closed-circuit-rebreather) for setting dive computer type enum cylinderuse {OC_GAS, DILUENT, OXYGEN, NUM_GAS_USE}; // The different uses for cylinders @@ -318,11 +321,10 @@ struct dive { bool hidden_by_filter; bool downloaded; timestamp_t when; - char *location; + uint32_t dive_site_uuid; char *notes; char *divemaster, *buddy; int rating; - degrees_t latitude, longitude; int visibility; /* 0 - 5 star rating */ cylinder_t cylinder[MAX_CYLINDERS]; weightsystem_t weightsystem[MAX_WEIGHTSYSTEMS]; @@ -347,14 +349,13 @@ extern int get_cylinder_idx_by_use(struct dive *dive, enum cylinderuse cylinder_ /* when selectively copying dive information, which parts should be copied? */ struct dive_components { - unsigned int location : 1; + unsigned int divesite : 1; unsigned int notes : 1; unsigned int divemaster : 1; unsigned int buddy : 1; unsigned int suit : 1; unsigned int rating : 1; unsigned int visibility : 1; - unsigned int gps : 1; unsigned int tags : 1; unsigned int cylinders : 1; unsigned int weights : 1; @@ -386,22 +387,6 @@ extern void dive_set_geodata_from_picture(struct dive *d, struct picture *pic); extern int explicit_first_cylinder(struct dive *dive, struct divecomputer *dc); -static inline int dive_has_gps_location(struct dive *dive) -{ - return dive->latitude.udeg || dive->longitude.udeg; -} - -static inline void copy_gps_location(struct dive *from, struct dive *to) -{ - if (from && to) { - to->latitude.udeg = from->latitude.udeg; - to->longitude.udeg = from->longitude.udeg; - if (!to->location) { - to->location = strdup(from->location); - } - } -} - static inline int get_surface_pressure_in_mbar(const struct dive *dive, bool non_null) { int mbar = dive->surface_pressure.mbar; @@ -489,18 +474,12 @@ struct dive_table { extern struct dive_table dive_table; extern struct dive displayed_dive; +extern struct dive_site displayed_dive_site; extern int selected_dive; extern unsigned int dc_number; #define current_dive (get_dive(selected_dive)) #define current_dc (get_dive_dc(current_dive, dc_number)) -static inline struct dive *get_gps_location(int nr, struct dive_table *table) -{ - if (nr >= table->nr || nr < 0) - return NULL; - return table->dives[nr]; -} - static inline struct dive *get_dive(int nr) { if (nr >= dive_table.nr || nr < 0) @@ -515,6 +494,21 @@ static inline struct dive *get_dive_from_table(int nr, struct dive_table *dt) return dt->dives[nr]; } +static inline struct dive_site *get_dive_site_for_dive(struct dive *dive) +{ + if (dive) + return get_dive_site_by_uuid(dive->dive_site_uuid); + return NULL; +} + +static inline char *get_dive_location(struct dive *dive) +{ + struct dive_site *ds = get_dive_site_by_uuid(dive->dive_site_uuid); + if (ds && ds->name) + return ds->name; + return NULL; +} + static inline unsigned int number_of_computers(struct dive *dive) { unsigned int total_number = 0; @@ -613,6 +607,16 @@ static inline int get_idx_by_uniq_id(int id) return i; } +static inline bool dive_site_has_gps_location(struct dive_site *ds) +{ + return ds && (ds->latitude.udeg || ds->longitude.udeg); +} + +static inline int dive_has_gps_location(struct dive *dive) +{ + return dive_site_has_gps_location(get_dive_site_by_uuid(dive->dive_site_uuid)); +} + #ifdef __cplusplus extern "C" { #endif diff --git a/divelist.c b/divelist.c index f1dd7006c..d57188a68 100644 --- a/divelist.c +++ b/divelist.c @@ -678,9 +678,9 @@ 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 *dive_trip = calloc(1, sizeof(dive_trip_t)); + dive_trip->when = dive->when; - if (dive->location) - dive_trip->location = strdup(dive->location); + dive_trip->location = copy_string(get_dive_location(dive)); insert_trip(&dive_trip); dive->tripflag = IN_TRIP; @@ -713,8 +713,8 @@ void autogroup_dives(void) if (lastdive && dive->when < lastdive->when + TRIP_THRESHOLD) { dive_trip_t *trip = lastdive->divetrip; add_dive_to_trip(dive, trip); - if (dive->location && !trip->location) - trip->location = strdup(dive->location); + if (get_dive_location(dive) && !trip->location) + trip->location = copy_string(get_dive_location(dive)); lastdive = dive; continue; } @@ -745,7 +745,6 @@ void delete_single_dive(int idx) dive_table.dives[--dive_table.nr] = NULL; /* free all allocations */ free(dive->dc.sample); - free((void *)dive->location); free((void *)dive->notes); free((void *)dive->divemaster); free((void *)dive->buddy); diff --git a/divesite.c b/divesite.c new file mode 100644 index 000000000..4f236017f --- /dev/null +++ b/divesite.c @@ -0,0 +1,118 @@ +/* divesite.c */ +#include "divesite.h" +#include "dive.h" + +struct dive_site_table dive_site_table; + +/* there could be multiple sites of the same name - return the first one */ +uint32_t get_dive_site_uuid_by_name(const char *name, struct dive_site **dsp) +{ + int i; + struct dive_site *ds; + for_each_dive_site (i, ds) { + if (same_string(ds->name, name)) { + if (dsp) + *dsp = ds; + return ds->uuid; + } + } + return 0; +} + +/* there could be multiple sites at the same GPS fix - return the first one */ +uint32_t get_dive_site_uuid_by_gps(degrees_t latitude, degrees_t longitude, struct dive_site **dsp) +{ + int i; + struct dive_site *ds; + for_each_dive_site (i, ds) { + if (ds->latitude.udeg == latitude.udeg && ds->longitude.udeg == longitude.udeg) { + if (dsp) + *dsp = ds; + return ds->uuid; + } + } + return 0; +} + +/* try to create a uniqe ID - fingers crossed */ +static uint32_t dive_site_getUniqId() +{ + uint32_t id = 0; + + while (id == 0 || get_dive_site_by_uuid(id)) + id = random() + random(); + + return id; +} + +struct dive_site *alloc_dive_site() +{ + int nr = dive_site_table.nr, allocated = dive_site_table.allocated; + struct dive_site **sites = dive_site_table.dive_sites; + + if (nr >= allocated) { + allocated = (nr + 32) * 3 / 2; + sites = realloc(sites, allocated * sizeof(struct dive_site *)); + if (!sites) + exit(1); + dive_site_table.dive_sites = sites; + dive_site_table.allocated = allocated; + } + struct dive_site *ds = calloc(1, sizeof(*ds)); + if (!ds) + exit(1); + sites[nr] = ds; + dive_site_table.nr = nr + 1; + ds->uuid = dive_site_getUniqId(); + return ds; +} + +void delete_dive_site(uint32_t id) +{ + int nr = dive_site_table.nr; + for (int i = 0; i < nr; i++) { + struct dive_site *ds = get_dive_site(i); + if (ds->uuid == id) { + free(ds->name); + free(ds->notes); + free(ds); + if (nr - 1 > i) + memmove(&dive_site_table.dive_sites[i], + &dive_site_table.dive_sites[i+1], + (nr - 1 - i) * sizeof(dive_site_table.dive_sites[0])); + dive_site_table.nr = nr - 1; + break; + } + } +} + +/* allocate a new site and add it to the table */ +uint32_t create_dive_site(const char *name) +{ + struct dive_site *ds = alloc_dive_site(); + ds->name = copy_string(name); + + return ds->uuid; +} + +/* same as before, but with GPS data */ +uint32_t create_dive_site_with_gps(const char *name, degrees_t latitude, degrees_t longitude) +{ + struct dive_site *ds = alloc_dive_site(); + ds->uuid = dive_site_getUniqId(); + ds->name = copy_string(name); + ds->latitude = latitude; + ds->longitude = longitude; + + return ds->uuid; +} + +/* a uuid is always present - but if all the other fields are empty, the dive site is pointless */ +bool dive_site_is_empty(struct dive_site *ds) +{ + return same_string(ds->name, "") && + same_string(ds->description, "") && + same_string(ds->notes, "") && + ds->latitude.udeg == 0 && + ds->longitude.udeg == 0; +} diff --git a/divesite.h b/divesite.h new file mode 100644 index 000000000..ca650259a --- /dev/null +++ b/divesite.h @@ -0,0 +1,61 @@ +#ifndef DIVESITE_H +#define DIVESITE_H + +#include "units.h" +#include <stdlib.h> + +#ifdef __cplusplus +extern "C" { +#else +#include <stdbool.h> +#endif + +struct dive_site +{ + uint32_t uuid; + char *name; + degrees_t latitude, longitude; + char *description; + char *notes; +}; + +struct dive_site_table { + int nr, allocated; + struct dive_site **dive_sites; +}; + +extern struct dive_site_table dive_site_table; + +static inline struct dive_site *get_dive_site(int nr) +{ + if (nr >= dive_site_table.nr || nr < 0) + return NULL; + return dive_site_table.dive_sites[nr]; +} + +/* iterate over each dive site */ +#define for_each_dive_site(_i, _x) \ + for ((_i) = 0; ((_x) = get_dive_site(_i)) != NULL; (_i)++) + +static inline struct dive_site *get_dive_site_by_uuid(uint32_t uuid) +{ + int i; + struct dive_site *ds; + for_each_dive_site (i, ds) + if (ds->uuid == uuid) + return get_dive_site(i); + return NULL; +} + +struct dive_site *alloc_dive_site(); +void delete_dive_site(uint32_t id); +uint32_t create_dive_site(const char *name); +uint32_t create_dive_site_with_gps(const char *name, degrees_t latitude, degrees_t longitude); +uint32_t get_dive_site_uuid_by_name(const char *name, struct dive_site **dsp); +uint32_t get_dive_site_uuid_by_gps(degrees_t latitude, degrees_t longitude, struct dive_site **dsp); +bool dive_site_is_empty(struct dive_site *ds); + +#ifdef __cplusplus +} +#endif +#endif // DIVESITE_H diff --git a/liquivision.c b/liquivision.c index a42c35aab..7126c9b79 100644 --- a/liquivision.c +++ b/liquivision.c @@ -121,21 +121,24 @@ static void parse_dives (int log_version, const unsigned char *buf, unsigned int // Dive location, assemble Location and Place unsigned int len, place_len; + char *location; len = array_uint32_le(buf + ptr); ptr += 4; place_len = array_uint32_le(buf + ptr + len); if (len && place_len) { - dive->location = malloc(len + place_len + 4); - memset(dive->location, 0, len + place_len + 4); - memcpy(dive->location, buf + ptr, len); - memcpy(dive->location + len, ", ", 2); - memcpy(dive->location + len + 2, buf + ptr + len + 4, place_len); + location = malloc(len + place_len + 4); + memset(location, 0, len + place_len + 4); + memcpy(location, buf + ptr, len); + memcpy(location + len, ", ", 2); + memcpy(location + len + 2, buf + ptr + len + 4, place_len); } else if (len) { - dive->location = strndup(buf + ptr, len); + location = strndup(buf + ptr, len); } else if (place_len) { - dive->location = strndup(buf + ptr + len + 4, place_len); + location = strndup(buf + ptr + len + 4, place_len); } + dive->dive_site_uuid = create_dive_site(location); + free(location); ptr += len + 4 + place_len; diff --git a/load-git.c b/load-git.c index 1cdb44cff..7cebb038a 100644 --- a/load-git.c +++ b/load-git.c @@ -23,13 +23,6 @@ struct keyword_action { #define ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0])) extern degrees_t parse_degrees(char *buf, char **end); -static void parse_dive_gps(char *line, struct membuffer *str, void *_dive) -{ - struct dive *dive = _dive; - - dive->latitude = parse_degrees(line, &line); - dive->longitude = parse_degrees(line, &line); -} static char *get_utf8(struct membuffer *b) { @@ -145,8 +138,43 @@ static int get_index(const char *line) static int get_hex(const char *line) { return strtoul(line, NULL, 16); } +static void parse_dive_gps(char *line, struct membuffer *str, void *_dive) +{ + uint32_t uuid; + degrees_t latitude = parse_degrees(line, &line); + degrees_t longitude = parse_degrees(line, &line); + struct dive *dive = _dive; + struct dive_site *ds = get_dive_site_for_dive(dive); + if (!ds) { + uuid = get_dive_site_uuid_by_gps(latitude, longitude, NULL); + if (!uuid) + uuid = create_dive_site_with_gps("", latitude, longitude); + dive->dive_site_uuid = uuid; + } else { + ds->latitude = latitude; + ds->longitude = longitude; + } + +} + static void parse_dive_location(char *line, struct membuffer *str, void *_dive) -{ struct dive *dive = _dive; dive->location = get_utf8(str); } +{ + uint32_t uuid; + char *name = get_utf8(str); + struct dive *dive = _dive; + struct dive_site *ds = get_dive_site_for_dive(dive); + fprintf(stderr, "looking for a site named {%s} ", name); + if (!ds) { + uuid = get_dive_site_uuid_by_name(name, NULL); + if (!uuid) { fprintf(stderr, "found none, creating\n"); + uuid = create_dive_site(name); + } else { fprintf(stderr, "found one with uuid %8x\n", uuid); } + dive->dive_site_uuid = uuid; + } else { + fprintf(stderr, "dive had site with uuid %8x and name {%s}\n", ds->uuid, ds->name); + ds->name = name; + } +} static void parse_dive_divemaster(char *line, struct membuffer *str, void *_dive) { struct dive *dive = _dive; dive->divemaster = get_utf8(str); } @@ -160,6 +188,9 @@ static void parse_dive_suit(char *line, struct membuffer *str, void *_dive) static void parse_dive_notes(char *line, struct membuffer *str, void *_dive) { struct dive *dive = _dive; dive->notes = get_utf8(str); } +static void parse_dive_divesiteid(char *line, struct membuffer *str, void *_dive) +{ struct dive *dive = _dive; dive->dive_site_uuid = get_hex(line); } + /* * We can have multiple tags in the membuffer. They are separated by * NUL bytes. @@ -205,6 +236,24 @@ static void parse_dive_visibility(char *line, struct membuffer *str, void *_dive static void parse_dive_notrip(char *line, struct membuffer *str, void *_dive) { struct dive *dive = _dive; dive->tripflag = NO_TRIP; } +static void parse_site_description(char *line, struct membuffer *str, void *_ds) +{ struct dive_site *ds = _ds; ds->description = strdup(mb_cstring(str)); } + +static void parse_site_name(char *line, struct membuffer *str, void *_ds) +{ struct dive_site *ds = _ds; ds->name = strdup(mb_cstring(str)); } + +static void parse_site_notes(char *line, struct membuffer *str, void *_ds) +{ struct dive_site *ds = _ds; ds->notes = strdup(mb_cstring(str)); } + +extern degrees_t parse_degrees(char *buf, char **end); +static void parse_site_gps(char *line, struct membuffer *str, void *_ds) +{ + struct dive_site *ds = _ds; + + ds->latitude = parse_degrees(line, &line); + ds->longitude = parse_degrees(line, &line); +} + /* Parse key=val parts of samples and cylinders etc */ static char *parse_keyvalue_entry(void (*fn)(void *, const char *, const char *), void *fndata, char *line) { @@ -672,7 +721,7 @@ static void parse_settings_userid(char *line, struct membuffer *str, void *_unus * *can* do some day. And if we do change the version, this warning will show if * you read with a version of subsurface that doesn't know about it. */ -#define VERSION 2 +#define VERSION 3 static void parse_settings_version(char *line, struct membuffer *str, void *_unused) { int version = atoi(line); @@ -783,7 +832,7 @@ static void divecomputer_parser(char *line, struct membuffer *str, void *_dc) struct keyword_action dive_action[] = { #undef D #define D(x) { #x, parse_dive_ ## x } - D(airtemp), D(buddy), D(cylinder), D(divemaster), D(duration), + D(airtemp), D(buddy), D(cylinder), D(divemaster), D(divesiteid), D(duration), D(gps), D(location), D(notes), D(notrip), D(rating), D(suit), D(tags), D(visibility), D(watertemp), D(weightsystem) }; @@ -794,6 +843,18 @@ static void dive_parser(char *line, struct membuffer *str, void *_dive) } /* These need to be sorted! */ +struct keyword_action site_action[] = { +#undef D +#define D(x) { #x, parse_site_ ## x } + D(description), D(gps), D(name), D(notes) +}; + +static void site_parser(char *line, struct membuffer *str, void *_ds) +{ + match_action(line, str, _ds, site_action, ARRAY_SIZE(site_action)); +} + +/* These need to be sorted! */ struct keyword_action trip_action[] = { #undef D #define D(x) { #x, parse_trip_ ## x } @@ -1190,6 +1251,9 @@ static int walk_tree_directory(const char *root, const git_tree_entry *entry) if (!strcmp(name, "Pictures")) return picture_directory(root, name); + if (!strcmp(name, "01-Divesites")) + return GIT_WALK_OK; + while (isdigit(c = name[digits])) digits++; @@ -1284,6 +1348,20 @@ static int parse_dive_entry(git_repository *repo, const git_tree_entry *entry, c return 0; } +static int parse_site_entry(git_repository *repo, const git_tree_entry *entry, const char *suffix) +{ + if (*suffix == '\0') + return report_error("Dive site without uuid"); + struct dive_site *ds = alloc_dive_site(); + ds->uuid = strtol(suffix, NULL, 16); + git_blob *blob = git_tree_entry_blob(repo, entry); + if (!blob) + return report_error("Unable to read dive site file"); + for_each_line(blob, site_parser, ds); + git_blob_free(blob); + return 0; +} + static int parse_trip_entry(git_repository *repo, const git_tree_entry *entry) { git_blob *blob = git_tree_entry_blob(repo, entry); @@ -1343,7 +1421,6 @@ static int walk_tree_file(const char *root, const git_tree_entry *entry, git_rep struct dive *dive = active_dive; dive_trip_t *trip = active_trip; const char *name = git_tree_entry_name(entry); - switch (*name) { /* Picture file? They are saved as time offsets in the dive */ case '-': case '+': @@ -1356,6 +1433,9 @@ static int walk_tree_file(const char *root, const git_tree_entry *entry, git_rep if (dive && !strncmp(name, "Dive", 4)) return parse_dive_entry(repo, entry, name+4); break; + case 'S': + if (!strncmp(name, "Site", 4)) + return parse_site_entry(repo, entry, name + 5); case '0': if (trip && !strcmp(name, "00-Trip")) return parse_trip_entry(repo, entry); diff --git a/parse-xml.c b/parse-xml.c index 5baa40394..cfe3459ed 100644 --- a/parse-xml.c +++ b/parse-xml.c @@ -21,6 +21,7 @@ int verbose, quit; int metric = 1; +int last_xml_version = -1; static xmlDoc *test_xslt_transforms(xmlDoc *doc, const char **params); @@ -128,6 +129,7 @@ const struct units IMPERIAL_units = IMPERIAL_UNITS; #define MAX_EVENT_NAME 128 static struct divecomputer *cur_dc; static struct dive *cur_dive; +static struct dive_site *cur_dive_site; static dive_trip_t *cur_trip = NULL; static struct sample *cur_sample; static struct picture *cur_picture; @@ -933,10 +935,8 @@ static void try_to_fill_sample(struct sample *sample, const char *name, char *bu return; if (MATCH("sensor3.sample", double_to_o2pressure, &sample->o2sensor[2])) // up to 3 CCR sensors return; - if (MATCH("po2.sample", double_to_o2pressure, &sample->setpoint)) { - cur_dive->dc.divemode = CCR; + if (MATCH("po2.sample", double_to_o2pressure, &sample->setpoint)) return; - } if (MATCH("heartbeat", get_uint8, &sample->heartbeat)) return; if (MATCH("bearing", get_bearing, &sample->bearing)) @@ -968,22 +968,21 @@ void try_to_fill_userid(const char *name, char *buf) static const char *country, *city; -static void divinglog_place(char *place, char **location) +static void divinglog_place(char *place, uint32_t *uuid) { char buffer[1024], *p; int len; - len = snprintf(buffer, sizeof(buffer), - "%s%s%s%s%s", - place, - city ? ", " : "", - city ? city : "", - country ? ", " : "", - country ? country : ""); - - p = malloc(len + 1); - memcpy(p, buffer, len + 1); - *location = p; + snprintf(buffer, sizeof(buffer), + "%s%s%s%s%s", + place, + city ? ", " : "", + city ? city : "", + country ? ", " : "", + country ? country : ""); + *uuid = get_dive_site_uuid_by_name(buffer, NULL); + if (*uuid == 0) + *uuid = create_dive_site(buffer); city = NULL; country = NULL; @@ -1005,7 +1004,7 @@ static int divinglog_dive_match(struct dive *dive, const char *name, char *buf) MATCH("names.buddy", utf8_string, &dive->buddy) || MATCH("name.country", utf8_string, &country) || MATCH("name.city", utf8_string, &city) || - MATCH("name.place", divinglog_place, &dive->location) || + MATCH("name.place", divinglog_place, &dive->dive_site_uuid) || 0; } @@ -1127,23 +1126,112 @@ degrees_t parse_degrees(char *buf, char **end) static void gps_lat(char *buffer, struct dive *dive) { char *end; - - dive->latitude = parse_degrees(buffer, &end); + degrees_t latitude = parse_degrees(buffer, &end); + struct dive_site *ds = get_dive_site_for_dive(dive); + if (!ds) { + dive->dive_site_uuid = create_dive_site_with_gps(NULL, latitude, (degrees_t){0}); + } else { + if (ds->latitude.udeg && ds->latitude.udeg != latitude.udeg) + fprintf(stderr, "Oops, changing the latitude of existing dive site id %8x name %s; not good\n", ds->uuid, ds->name ?: "(unknown)"); + ds->latitude = latitude; + } } static void gps_long(char *buffer, struct dive *dive) { char *end; + degrees_t longitude = parse_degrees(buffer, &end); + struct dive_site *ds = get_dive_site_for_dive(dive); + if (!ds) { + dive->dive_site_uuid = create_dive_site_with_gps(NULL, (degrees_t){0}, longitude); + } else { + if (ds->longitude.udeg && ds->longitude.udeg != longitude.udeg) + fprintf(stderr, "Oops, changing the longitude of existing dive site id %8x name %s; not good\n", ds->uuid, ds->name ?: "(unknown)"); + ds->longitude = longitude; + } - dive->longitude = parse_degrees(buffer, &end); } -static void gps_location(char *buffer, struct dive *dive) +static void gps_location(char *buffer, struct dive_site *ds) { char *end; - dive->latitude = parse_degrees(buffer, &end); - dive->longitude = parse_degrees(end, &end); + ds->latitude = parse_degrees(buffer, &end); + ds->longitude = parse_degrees(end, &end); +} + +static void gps_in_dive(char *buffer, struct dive *dive) +{ + char *end; + struct dive_site *ds = NULL; + degrees_t latitude = parse_degrees(buffer, &end); + degrees_t longitude = parse_degrees(end, &end); + fprintf(stderr, "got lat %f lon %f\n", latitude.udeg / 1000000.0, longitude.udeg / 1000000.0); + uint32_t uuid = dive->dive_site_uuid; + if (uuid == 0) { + uuid = get_dive_site_uuid_by_gps(latitude, longitude, &ds); + if (ds) { + fprintf(stderr, "found dive site {%s} with these coordinates\n", ds->name); + dive->dive_site_uuid = uuid; + } else { + fprintf(stderr, "found no uuid in dive, no existing dive site with these coordinates, creating a new divesite without name and above GPS\n"); + dive->dive_site_uuid = create_dive_site_with_gps("", latitude, longitude); + } + } else { + fprintf(stderr, "found uuid in dive, checking to see if we should add GPS\n"); + struct dive_site *ds = get_dive_site_by_uuid(uuid); + if (dive_site_has_gps_location(ds) && + (latitude.udeg != 0 || longitude.udeg != 0) && + (ds->latitude.udeg != latitude.udeg || ds->longitude.udeg != longitude.udeg)) { + // Houston, we have a problem + fprintf(stderr, "dive site uuid in dive, but gps location (%10.6f/%10.6f) different from dive location (%10.6f/%10.6f)\n", + ds->latitude.udeg / 1000000.0, ds->longitude.udeg / 1000000.0, + latitude.udeg / 1000000.0, longitude.udeg / 1000000.0); + int len = ds->notes ? strlen(ds->notes) : 0; + len += sizeof("\nalternative coordinates") + 24; + char *notes = malloc(len); + snprintf(notes, len, "%s\nalternative coordinates %11.6f/%11.6f", + ds->notes ?: "", latitude.udeg / 1000000.0, longitude.udeg / 1000000.0); + free(ds->notes); + ds->notes = notes; + } else { + fprintf(stderr, "let's add the gps coordinates to divesite with uuid %8x and name %s\n", ds->uuid, ds->name ?: "(none)"); + ds->latitude = latitude; + ds->longitude = longitude; + } + } +} + +static void add_dive_site(char *buffer, struct dive *dive) +{ + fprintf(stderr, "add_dive_site with name %s\n", buffer); + int size = trimspace(buffer); + if(size) { + uint32_t uuid = dive->dive_site_uuid; + struct dive_site *ds = get_dive_site_by_uuid(uuid); + if (uuid && !ds) { + // that's strange - we have a uuid but it doesn't exist - let's just ignore it + fprintf(stderr, "dive contains a non-existing dive site uuid %x\n", dive->dive_site_uuid); + uuid = 0; + } + if (!uuid) + // if the dive doesn't have a uuid, check if there's already a dive site by this name + uuid = get_dive_site_uuid_by_name(buffer, &ds); + if (ds) { + // we have a uuid, let's hope there isn't a different name + fprintf(stderr, "have existing site with name {%s} gps %f/%f ", ds->name, ds->latitude.udeg / 1000000.0, ds->longitude.udeg / 1000000.0); + if (same_string(ds->name, "")) { + fprintf(stderr, "so now add name {%s}\n", buffer); + ds->name = copy_string(buffer); + } else if (!same_string(ds->name, buffer)) { + // coin toss, let's just keep the first name we found + fprintf(stderr, "which means the dive already links to dive site of different name {%s} / {%s}\n", ds->name, buffer); + } + } else { + fprintf(stderr, "no uuid, create new dive site with name {%s}\n", buffer); + dive->dive_site_uuid = create_dive_site(buffer); + } + } } static void gps_picture_location(char *buffer, struct picture *pic) @@ -1173,7 +1261,8 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf) default: break; } - + if (MATCH("divesiteid", hex_value, &dive->dive_site_uuid)) + return; if (MATCH("number", get_index, &dive->number)) return; if (MATCH("tags", divetags, &dive->tag_list)) @@ -1203,9 +1292,9 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf) return; if (MATCH("cylinderendpressure", pressure, &dive->cylinder[0].end)) return; - if (MATCH("gps", gps_location, dive)) + if (MATCH("gps", gps_in_dive, dive)) return; - if (MATCH("Place", gps_location, dive)) + if (MATCH("Place", gps_in_dive, dive)) return; if (MATCH("latitude", gps_lat, dive)) return; @@ -1219,9 +1308,9 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf) return; if (MATCH("lon", gps_long, dive)) return; - if (MATCH("location", utf8_string, &dive->location)) + if (MATCH("location", add_dive_site, dive)) return; - if (MATCH("name.dive", utf8_string, &dive->location)) + if (MATCH("name.dive", add_dive_site, dive)) return; if (MATCH("suit", utf8_string, &dive->suit)) return; @@ -1290,6 +1379,27 @@ static void try_to_fill_trip(dive_trip_t **dive_trip_p, const char *name, char * nonmatch("trip", name, buf); } +/* We're processing a divesite entry - try to fill the components */ +static void try_to_fill_dive_site(struct dive_site **ds_p, const char *name, char *buf) +{ + start_match("divesite", name, buf); + + struct dive_site *ds = *ds_p; + + if (MATCH("uuid", hex_value, &ds->uuid)) + return; + if (MATCH("name", utf8_string, &ds->name)) + return; + if (MATCH("description", utf8_string, &ds->description)) + return; + if (MATCH("notes", utf8_string, &ds->notes)) + return; + if (MATCH("gps", gps_location, ds)) + return; + + nonmatch("divesite", name, buf); +} + /* * While in some formats file boundaries are dive boundaries, in many * others (as for example in our native format) there are @@ -1305,7 +1415,7 @@ static void try_to_fill_trip(dive_trip_t **dive_trip_p, const char *name, char * static bool is_dive(void) { return (cur_dive && - (cur_dive->location || cur_dive->when || cur_dive->dc.samples)); + (cur_dive->dive_site_uuid || cur_dive->when || cur_dive->dc.samples)); } static void reset_dc_info(struct divecomputer *dc) @@ -1349,6 +1459,32 @@ static void dc_settings_end(void) reset_dc_settings(); } +static void dive_site_start(void) +{ + if (cur_dive_site) + return; + cur_dive_site = calloc(1, sizeof(struct dive_site)); +} + +static void dive_site_end(void) +{ + if (!cur_dive_site) + return; + if (cur_dive_site->uuid) { + uint32_t tmp = create_dive_site_with_gps(cur_dive_site->name, cur_dive_site->latitude, cur_dive_site->longitude); + struct dive_site *ds = get_dive_site_by_uuid(tmp); + ds->uuid = cur_dive_site->uuid; + ds->notes = cur_dive_site->notes; + ds->description = cur_dive_site->description; + if (verbose > 3) + printf("completed dive site uuid %x8 name {%s}\n", ds->uuid, ds->name); + } + free(cur_dive_site); + cur_dive_site = NULL; +} + +// now we need to add the code to parse the parts of the divesite enry + static void dive_start(void) { if (cur_dive) @@ -1529,6 +1665,9 @@ static void userid_stop(void) static void entry(const char *name, char *buf) { + if (!strncmp(name, "version.program", sizeof("version.program") - 1) || + !strncmp(name, "version.divelog", sizeof("version.divelog") - 1)) + last_xml_version = atoi(buf); if (in_userid) { try_to_fill_userid(name, buf); return; @@ -1538,6 +1677,10 @@ static void entry(const char *name, char *buf) try_to_match_autogroup(name, buf); return; } + if (cur_dive_site) { + try_to_fill_dive_site(&cur_dive_site, name, buf); + return; + } if (!cur_event.deleted) { try_to_fill_event(name, buf); return; @@ -1666,6 +1809,7 @@ static struct nesting { } nesting[] = { { "divecomputerid", dc_settings_start, dc_settings_end }, { "settings", settings_start, settings_end }, + { "site", dive_site_start, dive_site_end }, { "dive", dive_start, dive_end }, { "Dive", dive_start, dive_end }, { "trip", trip_start, trip_end }, @@ -2291,7 +2435,7 @@ extern int shearwater_dive(void *param, int columns, char **data, char **column) cur_dive->when = (time_t)(atol(data[1])); if (data[2]) - utf8_string(data[2], &cur_dive->location); + add_dive_site(data[2], cur_dive); if (data[3]) utf8_string(data[3], &cur_dive->buddy); if (data[4]) @@ -2388,19 +2532,20 @@ extern int cobalt_visibility(void *handle, int columns, char **data, char **colu extern int cobalt_location(void *handle, int columns, char **data, char **column) { + static char *location = NULL; if (data[0]) { - if (cur_dive->location) { - char *tmp = malloc(strlen(cur_dive->location) + strlen(data[0]) + 4); + if (location) { + char *tmp = malloc(strlen(location) + strlen(data[0]) + 4); if (!tmp) return -1; - sprintf(tmp, "%s / %s", cur_dive->location, data[0]); - free(cur_dive->location); - cur_dive->location = tmp; + sprintf(tmp, "%s / %s", location, data[0]); + free(location); + location = NULL; + cur_dive->dive_site_uuid = create_dive_site(tmp); } else { - utf8_string(data[0], &cur_dive->location); + location = strdup(data[0]); } } - return 0; } diff --git a/qt-ui/completionmodels.cpp b/qt-ui/completionmodels.cpp index fd3cc7504..f2e70afd1 100644 --- a/qt-ui/completionmodels.cpp +++ b/qt-ui/completionmodels.cpp @@ -40,9 +40,21 @@ CREATE_CSV_UPDATE_METHOD(BuddyCompletionModel, buddy); CREATE_CSV_UPDATE_METHOD(DiveMasterCompletionModel, divemaster); -CREATE_UPDATE_METHOD(LocationCompletionModel, location); CREATE_UPDATE_METHOD(SuitCompletionModel, suit); +void LocationCompletionModel::updateModel() +{ + QStringList list; + struct dive_site *ds; + int i = 0; + for_each_dive_site(i, ds) { + if (!list.contains(ds->name)) + list.append(ds->name); + } + std::sort(list.begin(), list.end()); + setStringList(list); +} + void TagCompletionModel::updateModel() { if (g_tag_list == NULL) diff --git a/qt-ui/divecomponentselection.ui b/qt-ui/divecomponentselection.ui index dbd0839ba..7eade039b 100644 --- a/qt-ui/divecomponentselection.ui +++ b/qt-ui/divecomponentselection.ui @@ -9,8 +9,8 @@ <rect> <x>0</x> <y>0</y> - <width>308</width> - <height>263</height> + <width>401</width> + <height>317</height> </rect> </property> <property name="sizePolicy"> @@ -41,9 +41,9 @@ </property> <layout class="QGridLayout" name="gridLayout"> <item row="0" column="0"> - <widget class="QCheckBox" name="location"> + <widget class="QCheckBox" name="divesite"> <property name="text"> - <string>Location</string> + <string>Dive site</string> </property> </widget> </item> @@ -54,34 +54,6 @@ </property> </widget> </item> - <item row="1" column="0"> - <widget class="QCheckBox" name="gps"> - <property name="text"> - <string>GPS coordinates</string> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QCheckBox" name="divemaster"> - <property name="text"> - <string>Divemaster</string> - </property> - </widget> - </item> - <item row="3" column="0"> - <widget class="QCheckBox" name="buddy"> - <property name="text"> - <string>Buddy</string> - </property> - </widget> - </item> - <item row="4" column="0"> - <widget class="QCheckBox" name="rating"> - <property name="text"> - <string>Rating</string> - </property> - </widget> - </item> <item row="5" column="0"> <widget class="QCheckBox" name="visibility"> <property name="text"> @@ -117,6 +89,27 @@ </property> </widget> </item> + <item row="1" column="0"> + <widget class="QCheckBox" name="divemaster"> + <property name="text"> + <string>Divemaster</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QCheckBox" name="buddy"> + <property name="text"> + <string>Buddy</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QCheckBox" name="rating"> + <property name="text"> + <string>Rating</string> + </property> + </widget> + </item> </layout> </widget> </item> diff --git a/qt-ui/filtermodels.cpp b/qt-ui/filtermodels.cpp index 378f46735..f44ab7cf8 100644 --- a/qt-ui/filtermodels.cpp +++ b/qt-ui/filtermodels.cpp @@ -249,7 +249,7 @@ bool LocationFilterModel::doFilter(struct dive *d, QModelIndex &index0, QAbstrac return true; } // Checked means 'Show', Unchecked means 'Hide'. - QString location(d->location); + QString location(get_dive_location(d)); // only show empty location dives if the user checked that. if (location.isEmpty()) { if (rowCount() > 0) @@ -277,7 +277,7 @@ void LocationFilterModel::repopulate() struct dive *dive; int i = 0; for_each_dive (i, dive) { - QString location(dive->location); + QString location(get_dive_location(dive)); if (!location.isEmpty() && !list.contains(location)) { list.append(location); } diff --git a/qt-ui/globe.cpp b/qt-ui/globe.cpp index cda408ddc..91bb4e858 100644 --- a/qt-ui/globe.cpp +++ b/qt-ui/globe.cpp @@ -164,10 +164,11 @@ void GlobeGPS::mouseClicked(qreal lon, qreal lat, GeoDataCoordinates::Unit unit) QList<int> selectedDiveIds; for_each_dive (idx, dive) { long lat_diff, lon_diff; - if (!dive_has_gps_location(dive)) + struct dive_site *ds = get_dive_site_for_dive(dive); + if (!dive_site_has_gps_location(ds)) continue; - lat_diff = labs(dive->latitude.udeg - lat_udeg); - lon_diff = labs(dive->longitude.udeg - lon_udeg); + lat_diff = labs(ds->latitude.udeg - lat_udeg); + lon_diff = labs(ds->longitude.udeg - lon_udeg); if (lat_diff > 180000000) lat_diff = 360000000 - lat_diff; if (lon_diff > 180000000) @@ -186,6 +187,7 @@ void GlobeGPS::mouseClicked(qreal lon, qreal lat, GeoDataCoordinates::Unit unit) void GlobeGPS::repopulateLabels() { + struct dive_site *ds; if (loadedDives) { model()->treeModel()->removeDocument(loadedDives); delete loadedDives; @@ -204,12 +206,16 @@ void GlobeGPS::repopulateLabels() // don't show that flag, it's either already shown as displayed_dive // or it's the one that we are moving right now... continue; - if (dive_has_gps_location(dive)) { - GeoDataPlacemark *place = new GeoDataPlacemark(dive->location); - place->setCoordinate(dive->longitude.udeg / 1000000.0, dive->latitude.udeg / 1000000.0, 0, GeoDataCoordinates::Degree); + if (idx == -1) + ds = &displayed_dive_site; + else + ds = get_dive_site_for_dive(dive); + if (dive_site_has_gps_location(ds)) { + GeoDataPlacemark *place = new GeoDataPlacemark(ds->name); + place->setCoordinate(ds->longitude.udeg / 1000000.0, ds->latitude.udeg / 1000000.0, 0, GeoDataCoordinates::Degree); // don't add dive locations twice, unless they are at least 50m apart - if (locationMap[QString(dive->location)]) { - GeoDataCoordinates existingLocation = locationMap[QString(dive->location)]->coordinate(); + if (locationMap[QString(ds->name)]) { + GeoDataCoordinates existingLocation = locationMap[QString(ds->name)]->coordinate(); GeoDataLineString segment = GeoDataLineString(); segment.append(existingLocation); GeoDataCoordinates newLocation = place->coordinate(); @@ -220,7 +226,7 @@ void GlobeGPS::repopulateLabels() if (dist < 0.05) continue; } - locationMap[QString(dive->location)] = place; + locationMap[QString(ds->name)] = place; loadedDives->append(place); } } @@ -236,23 +242,23 @@ void GlobeGPS::reload() void GlobeGPS::centerOnCurrentDive() { - struct dive *dive = current_dive; + struct dive_site *ds = get_dive_site_for_dive(current_dive); // dive has changed, if we had the 'editingDive', hide it. - if (messageWidget->isVisible() && (!dive || dive_has_gps_location(dive) || amount_selected != 1)) + if (messageWidget->isVisible() && (!ds || dive_site_has_gps_location(ds) || amount_selected != 1)) messageWidget->hide(); editingDiveLocation = false; - if (!dive) + if (!ds) return; - qreal longitude = dive->longitude.udeg / 1000000.0; - qreal latitude = dive->latitude.udeg / 1000000.0; + qreal longitude = ds->longitude.udeg / 1000000.0; + qreal latitude = ds->latitude.udeg / 1000000.0; - if ((!dive_has_gps_location(dive) || MainWindow::instance()->information()->isEditing()) && amount_selected == 1) { + if ((!dive_site_has_gps_location(ds) || MainWindow::instance()->information()->isEditing()) && amount_selected == 1) { prepareForGetDiveCoordinates(); return; } - if (!dive_has_gps_location(dive)) { + if (!dive_site_has_gps_location(ds)) { zoomOutForNoGPS(); return; } @@ -309,8 +315,10 @@ void GlobeGPS::prepareForGetDiveCoordinates() } } +// This needs to update the dive site, not just this dive void GlobeGPS::changeDiveGeoPosition(qreal lon, qreal lat, GeoDataCoordinates::Unit unit) { + struct dive_site *ds; messageWidget->hide(); if (MainWindow::instance()->dive_list()->selectionModel()->selection().isEmpty()) @@ -324,8 +332,8 @@ void GlobeGPS::changeDiveGeoPosition(qreal lon, qreal lat, GeoDataCoordinates::U centerOn(lon, lat, true); // change the location of the displayed_dive and put the UI in edit mode - displayed_dive.latitude.udeg = lrint(lat * 1000000.0); - displayed_dive.longitude.udeg = lrint(lon * 1000000.0); + displayed_dive_site.latitude.udeg = lrint(lat * 1000000.0); + displayed_dive_site.longitude.udeg = lrint(lon * 1000000.0); emit(coordinatesChanged()); repopulateLabels(); editingDiveLocation = false; @@ -341,7 +349,12 @@ void GlobeGPS::mousePressEvent(QMouseEvent *event) // there could be two scenarios that got us here; let's check if we are editing a dive if (MainWindow::instance()->information()->isEditing() && clickOnGlobe) { - MainWindow::instance()->information()->updateCoordinatesText(lat, lon); + // + // FIXME + // TODO + // + // this needs to do this on the dive site screen + // MainWindow::instance()->information()->updateCoordinatesText(lat, lon); repopulateLabels(); } else if (clickOnGlobe) { changeDiveGeoPosition(lon, lat, GeoDataCoordinates::Degree); diff --git a/qt-ui/locationInformation.ui b/qt-ui/locationInformation.ui new file mode 100644 index 000000000..658395b35 --- /dev/null +++ b/qt-ui/locationInformation.ui @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>LocationInformation</class> + <widget class="QGroupBox" name="LocationInformation"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string>GroupBox</string> + </property> + <property name="title"> + <string>Dive Site</string> + </property> + <layout class="QFormLayout" name="formLayout"> + <item row="0" column="0" colspan="2"> + <widget class="KMessageWidget" name="diveSiteMessage" native="true"/> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Name</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="diveSiteName"/> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Coordinates</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLineEdit" name="diveSiteCoordinates"/> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Description</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QLineEdit" name="diveSiteDescription"/> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Notes</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QPlainTextEdit" name="diveSiteNotes"/> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>KMessageWidget</class> + <extends>QWidget</extends> + <header>kmessagewidget.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/qt-ui/maintab.cpp b/qt-ui/maintab.cpp index e0da97a2d..b78280d7a 100644 --- a/qt-ui/maintab.cpp +++ b/qt-ui/maintab.cpp @@ -49,18 +49,19 @@ MainTab::MainTab(QWidget *parent) : QTabWidget(parent), ui.extraData->setModel(extraDataModel); closeMessage(); + connect(ui.manageDiveSite, SIGNAL(clicked()), this, SLOT(prepareDiveSiteEdit())); + QAction *action = new QAction(tr("Apply changes"), this); connect(action, SIGNAL(triggered(bool)), this, SLOT(acceptChanges())); addMessageAction(action); action = new QAction(tr("Discard changes"), this); connect(action, SIGNAL(triggered(bool)), this, SLOT(rejectChanges())); + addMessageAction(action); QShortcut *closeKey = new QShortcut(QKeySequence(Qt::Key_Escape), this); connect(closeKey, SIGNAL(activated()), this, SLOT(escDetected())); - addMessageAction(action); - if (qApp->style()->objectName() == "oxygen") setDocumentMode(true); else @@ -71,7 +72,6 @@ MainTab::MainTab(QWidget *parent) : QTabWidget(parent), setEnabled(false); ui.location->installEventFilter(this); - ui.coordinates->installEventFilter(this); ui.divemaster->installEventFilter(this); ui.buddy->installEventFilter(this); ui.suit->installEventFilter(this); @@ -212,6 +212,10 @@ MainTab::~MainTab() } } +void MainTab::prepareDiveSiteEdit() { + emit requestDiveSiteEdit(displayed_dive.dive_site_uuid); +} + void MainTab::toggleTriggeredColumn() { QAction *action = qobject_cast<QAction *>(sender()); @@ -391,6 +395,11 @@ bool MainTab::isEditing() return editMode != NONE; } +void MainTab::showLocation() +{ + ui.location->setText(get_dive_location(&displayed_dive)); +} + void MainTab::updateDiveInfo(bool clear) { // don't execute this while adding / planning a dive @@ -424,9 +433,7 @@ void MainTab::updateDiveInfo(bool clear) else ui.notes->setPlainText(tmp); } - UPDATE_TEXT(displayed_dive, notes); - UPDATE_TEXT(displayed_dive, location); UPDATE_TEXT(displayed_dive, suit); UPDATE_TEXT(displayed_dive, divemaster); UPDATE_TEXT(displayed_dive, buddy); @@ -435,7 +442,11 @@ void MainTab::updateDiveInfo(bool clear) ui.DiveType->setCurrentIndex(displayed_dive.dc.divemode); if (!clear) { - updateGpsCoordinates(); + struct dive_site *ds = get_dive_site_by_uuid(displayed_dive.dive_site_uuid); + if (ds) + ui.location->setText(ds->name); + else + ui.location->clear(); // Subsurface always uses "local time" as in "whatever was the local time at the location" // so all time stamps have no time zone information and are in UTC QDateTime localTime = QDateTime::fromTime_t(displayed_dive.when - gettimezoneoffset(displayed_dive.when)); @@ -446,8 +457,6 @@ void MainTab::updateDiveInfo(bool clear) setTabText(0, tr("Trip notes")); currentTrip = *MainWindow::instance()->dive_list()->selectedTrips().begin(); // only use trip relevant fields - ui.coordinates->setVisible(false); - ui.CoordinatedLabel->setVisible(false); ui.divemaster->setVisible(false); ui.DivemasterLabel->setVisible(false); ui.buddy->setVisible(false); @@ -477,8 +486,6 @@ void MainTab::updateDiveInfo(bool clear) setTabText(0, tr("Dive notes")); currentTrip = NULL; // make all the fields visible writeable - ui.coordinates->setVisible(true); - ui.CoordinatedLabel->setVisible(true); ui.divemaster->setVisible(true); ui.buddy->setVisible(true); ui.suit->setVisible(true); @@ -647,8 +654,8 @@ void MainTab::updateDiveInfo(bool clear) clearStats(); clearEquipment(); ui.rating->setCurrentStars(0); - ui.coordinates->clear(); ui.visibility->setCurrentStars(0); + ui.location->clear(); } editMode = NONE; ui.cylinders->view()->hideColumn(CylindersModel::DEPTH); @@ -756,8 +763,6 @@ void MainTab::acceptChanges() copy_samples(&displayed_dive.dc, ¤t_dive->dc); } struct dive *cd = current_dive; - //Reset coordinates field, in case it contains garbage. - updateGpsCoordinates(); // now check if something has changed and if yes, edit the selected dives that // were identical with the master dive shown (and mark the divelist as changed) if (!same_string(displayed_dive.buddy, cd->buddy)) @@ -785,17 +790,6 @@ void MainTab::acceptChanges() time_t offset = cd->when - displayed_dive.when; MODIFY_SELECTED_DIVES(mydive->when -= offset;); } - if (displayed_dive.latitude.udeg != cd->latitude.udeg || - displayed_dive.longitude.udeg != cd->longitude.udeg) - MODIFY_SELECTED_DIVES( - if (copyPaste || - (same_string(mydive->location, cd->location) && - mydive->latitude.udeg == cd->latitude.udeg && - mydive->longitude.udeg == cd->longitude.udeg)) - gpsHasChanged(mydive, cd, ui.coordinates->text(), 0); - ); - if (!same_string(displayed_dive.location, cd->location)) - MODIFY_SELECTED_DIVES(EDIT_TEXT(location)); saveTags(); @@ -901,7 +895,6 @@ void MainTab::resetPallete() ui.buddy->setPalette(p); ui.notes->setPalette(p); ui.location->setPalette(p); - ui.coordinates->setPalette(p); ui.divemaster->setPalette(p); ui.suit->setPalette(p); ui.airtemp->setPalette(p); @@ -1139,8 +1132,17 @@ void MainTab::on_location_textChanged(const QString &text) free(displayedTrip.location); displayedTrip.location = strdup(ui.location->text().toUtf8().data()); } else { - free(displayed_dive.location); - displayed_dive.location = strdup(ui.location->text().toUtf8().data()); + // this means we switched dive sites... this requires a lot more thinking + // + // + // FIXME + // + // TODO + // + // + // + // free(displayed_dive.location); + // displayed_dive.location = strdup(ui.location->text().toUtf8().data()); } markChangedWidget(ui.location); } @@ -1148,25 +1150,12 @@ void MainTab::on_location_textChanged(const QString &text) // If we have GPS data for the location entered, add it. void MainTab::on_location_editingFinished() { - // if we have a location and no GPS data, look up the GPS data; - // but if the GPS data was intentionally cleared then don't - if (!currentTrip && - !same_string(displayed_dive.location, "") && - ui.coordinates->text().trimmed().isEmpty() && - !(editMode == DIVE && dive_has_gps_location(current_dive))) { - struct dive *dive; - int i = 0; - for_each_dive (i, dive) { - if (same_string(displayed_dive.location, dive->location) && - (dive->latitude.udeg || dive->longitude.udeg)) { - displayed_dive.latitude = dive->latitude; - displayed_dive.longitude = dive->longitude; - MainWindow::instance()->globe()->reload(); - updateGpsCoordinates(); - break; - } - } - } + // find the dive site or create it + const char *name = ui.location->text().toUtf8().data(); + uint32_t uuid = get_dive_site_uuid_by_name(name, NULL); + if (!uuid) + uuid = create_dive_site(name); + displayed_dive.dive_site_uuid = uuid; } void MainTab::on_suit_textChanged(const QString &text) @@ -1199,6 +1188,7 @@ void MainTab::on_notes_textChanged() markChangedWidget(ui.notes); } +#if 0 // we'll need something like this for the dive site management void MainTab::on_coordinates_textChanged(const QString &text) { if (editMode == IGNORE || acceptingEdit == true) @@ -1215,6 +1205,7 @@ void MainTab::on_coordinates_textChanged(const QString &text) ui.coordinates->setPalette(p); // marks things red } } +#endif void MainTab::on_rating_valueChanged(int value) { @@ -1266,6 +1257,7 @@ void MainTab::editWeightWidget(const QModelIndex &index) ui.weights->edit(index); } +#if 0 // we'll need this for dive sites void MainTab::updateCoordinatesText(qreal lat, qreal lon) { int ulat = rint(lat * 1000000); @@ -1278,9 +1270,16 @@ void MainTab::updateGpsCoordinates() if (editMode == NONE) enableEdition(); - ui.coordinates->setText(printGPSCoords(displayed_dive.latitude.udeg, displayed_dive.longitude.udeg)); - ui.coordinates->setModified(displayed_dive.latitude.udeg || displayed_dive.longitude.udeg); + struct dive_site *ds = get_dive_site_by_uuid(displayed_dive.dive_site_uuid); + if (ds && dive_site_has_gps_location(ds)) { + ui.coordinates->setText(printGPSCoords(ds->latitude.udeg, ds->longitude.udeg)); + ui.coordinates->setModified(true); + } else if (!ui.coordinates->text().isEmpty()) { + ui.coordinates->setModified(true); + ui.coordinates->clear(); + } } +#endif void MainTab::escDetected() { @@ -1312,7 +1311,6 @@ void MainTab::showAndTriggerEditSelective(struct dive_components what) // take the data in our copyPasteDive and apply it to selected dives enableEdition(); copyPaste = true; - SHOW_SELECTIVE(location); SHOW_SELECTIVE(buddy); SHOW_SELECTIVE(divemaster); SHOW_SELECTIVE(suit); @@ -1327,8 +1325,8 @@ void MainTab::showAndTriggerEditSelective(struct dive_components what) ui.rating->setCurrentStars(displayed_dive.rating); if (what.visibility) ui.visibility->setCurrentStars(displayed_dive.visibility); - if (what.gps) - updateGpsCoordinates(); + if (what.divesite) + ui.location->setText(get_dive_location(&displayed_dive)); if (what.tags) { char buf[1024]; taglist_get_tagstring(displayed_dive.tag_list, buf, 1024); diff --git a/qt-ui/maintab.h b/qt-ui/maintab.h index a279baf7a..8869b068e 100644 --- a/qt-ui/maintab.h +++ b/qt-ui/maintab.h @@ -10,6 +10,7 @@ #include <QTabWidget> #include <QDialog> #include <QMap> +#include <QUuid> #include "ui_maintab.h" #include "completionmodels.h" @@ -55,7 +56,7 @@ public: signals: void addDiveFinished(); void dateTimeChanged(); - + void requestDiveSiteEdit(uint32_t uuid); public slots: void addCylinder_clicked(); @@ -65,7 +66,6 @@ slots: void rejectChanges(); void on_location_textChanged(const QString &text); void on_location_editingFinished(); - void on_coordinates_textChanged(const QString &text); void on_divemaster_textChanged(); void on_buddy_textChanged(); void on_suit_textChanged(const QString &text); @@ -92,7 +92,8 @@ slots: void escDetected(void); void photoDoubleClicked(const QString filePath); void removeSelectedPhotos(); - void updateGpsCoordinates(); + void prepareDiveSiteEdit(); + void showLocation(); private: Ui::MainTab ui; diff --git a/qt-ui/maintab.ui b/qt-ui/maintab.ui index 48bad01aa..5267863ff 100644 --- a/qt-ui/maintab.ui +++ b/qt-ui/maintab.ui @@ -22,7 +22,8 @@ <number>0</number> </property> <item row="2" column="1"> - <widget class="KMessageWidget" name="diveNotesMessage" native="true"/> + <widget class="KMessageWidget" name="diveNotesMessage" native="true"> + </widget> </item> <item row="3" column="1"> <widget class="QScrollArea" name="scrollArea"> @@ -40,8 +41,8 @@ <rect> <x>0</x> <y>0</y> - <width>443</width> - <height>758</height> + <width>441</width> + <height>753</height> </rect> </property> <layout class="QVBoxLayout" name="verticalLayout"> @@ -131,7 +132,7 @@ </widget> </item> <item> - <widget class="QPushButton" name="pushButton"> + <widget class="QPushButton" name="manageDiveSite"> <property name="text"> <string>manage</string> </property> @@ -140,40 +141,6 @@ </layout> </item> <item> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="0" column="0"> - <widget class="QLabel" name="CoordinatedLabel"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Coordinates</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QLabel" name="TypeLabel"> - <property name="text"> - <string>Dive mode</string> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLineEdit" name="coordinates"> - <property name="readOnly"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QComboBox" name="DiveType"/> - </item> - </layout> - </item> - <item> <layout class="QGridLayout" name="gridLayout_4"> <item row="0" column="0"> <widget class="QLabel" name="DivemasterLabel"> @@ -276,36 +243,50 @@ </layout> </item> <item> - <widget class="QLabel" name="TagLabel"> - <property name="text"> - <string>Tags</string> - </property> - </widget> - </item> - <item> - <widget class="TagWidget" name="tagWidget"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - <property name="verticalScrollBarPolicy"> - <enum>Qt::ScrollBarAlwaysOff</enum> - </property> - <property name="horizontalScrollBarPolicy"> - <enum>Qt::ScrollBarAlwaysOff</enum> - </property> - <property name="lineWrapMode"> - <enum>QPlainTextEdit::NoWrap</enum> - </property> - </widget> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="1" column="1"> + <widget class="QComboBox" name="DiveType"/> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="TagLabel"> + <property name="text"> + <string>Tags</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="TypeLabel"> + <property name="text"> + <string>Dive mode</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="TagWidget" name="tagWidget"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="verticalScrollBarPolicy"> + <enum>Qt::ScrollBarAlwaysOff</enum> + </property> + <property name="horizontalScrollBarPolicy"> + <enum>Qt::ScrollBarAlwaysOff</enum> + </property> + <property name="lineWrapMode"> + <enum>QPlainTextEdit::NoWrap</enum> + </property> + </widget> + </item> + </layout> </item> <item> <widget class="QLabel" name="NotesLabel"> @@ -400,8 +381,8 @@ <rect> <x>0</x> <y>0</y> - <width>454</width> - <height>752</height> + <width>68</width> + <height>40</height> </rect> </property> <layout class="QGridLayout" name="equipmentTabScrollAreaLayout"> @@ -456,8 +437,8 @@ <rect> <x>0</x> <y>0</y> - <width>454</width> - <height>752</height> + <width>441</width> + <height>363</height> </rect> </property> <layout class="QGridLayout" name="diveInfoScrollAreaLayout"> @@ -773,8 +754,8 @@ <rect> <x>0</x> <y>0</y> - <width>454</width> - <height>752</height> + <width>446</width> + <height>215</height> </rect> </property> <layout class="QGridLayout" name="statsScrollAreaLayout"> @@ -1036,7 +1017,6 @@ <tabstop>rating</tabstop> <tabstop>visibility</tabstop> <tabstop>suit</tabstop> - <tabstop>tagWidget</tabstop> <tabstop>notes</tabstop> </tabstops> <resources> diff --git a/qt-ui/mainwindow.cpp b/qt-ui/mainwindow.cpp index 257f394d6..56f885409 100644 --- a/qt-ui/mainwindow.cpp +++ b/qt-ui/mainwindow.cpp @@ -67,12 +67,15 @@ MainWindow::MainWindow() : QMainWindow(), PlannerSettingsWidget *plannerSettings = new PlannerSettingsWidget(); DivePlannerWidget *plannerWidget = new DivePlannerWidget(); PlannerDetails *plannerDetails = new PlannerDetails(); + LocationInformationWidget *locationInformation = new LocationInformationWidget(); registerApplicationState("Default", mainTab, profileWidget, diveListView, globeGps ); registerApplicationState("AddDive", mainTab, profileWidget, diveListView, globeGps ); registerApplicationState("EditDive", mainTab, profileWidget, diveListView, globeGps ); registerApplicationState("PlanDive", plannerWidget, profileWidget, plannerSettings, plannerDetails ); registerApplicationState("EditPlannedDive", plannerWidget, profileWidget, diveListView, globeGps ); + registerApplicationState("EditDiveSite",locationInformation, profileWidget, diveListView, globeGps ); + setApplicationState("Default"); ui.multiFilter->hide(); @@ -108,6 +111,11 @@ MainWindow::MainWindow() : QMainWindow(), connect(DivePlannerPointsModel::instance(), SIGNAL(planCreated()), this, SLOT(planCreated())); connect(DivePlannerPointsModel::instance(), SIGNAL(planCanceled()), this, SLOT(planCanceled())); connect(plannerDetails->printPlan(), SIGNAL(pressed()), divePlannerWidget(), SLOT(printDecoPlan())); + connect(mainTab, SIGNAL(requestDiveSiteEdit(uint32_t)), this, SLOT(enableDiveSiteEdit(uint32_t))); + connect(locationInformation, SIGNAL(informationManagementEnded()), this, SLOT(setDefaultState())); + connect(locationInformation, SIGNAL(informationManagementEnded()), this, SLOT(refreshDisplay())); + connect(locationInformation, SIGNAL(informationManagementEnded()), information(), SLOT(showLocation())); + #ifdef NO_PRINTING ui.printPlan->hide(); ui.menuFile->removeAction(ui.actionPrint); @@ -128,7 +136,7 @@ MainWindow::MainWindow() : QMainWindow(), #ifdef NO_MARBLE ui.menuView->removeAction(ui.actionViewGlobe); #else - connect(globe(), SIGNAL(coordinatesChanged()), information(), SLOT(updateGpsCoordinates())); + connect(globe(), SIGNAL(coordinatesChanged()), locationInformation, SLOT(updateGpsCoordinates())); #endif #ifdef NO_USERMANUAL ui.menuHelp->removeAction(ui.actionUserManual); @@ -205,6 +213,18 @@ PlannerSettingsWidget *MainWindow::divePlannerSettingsWidget() { return qobject_cast<PlannerSettingsWidget*>(applicationState["PlanDive"].bottomLeft); } +LocationInformationWidget *MainWindow::locationInformationWidget() { + return qobject_cast<LocationInformationWidget*>(applicationState["EditDiveSite"].topLeft); +} + +void MainWindow::enableDiveSiteEdit(uint32_t id) { + setApplicationState("EditDiveSite"); +} + +void MainWindow::setDefaultState() { + setApplicationState("Default"); +} + void MainWindow::setLoadedWithFiles(bool f) { filesAsArguments = f; @@ -255,6 +275,7 @@ void MainWindow::current_dive_changed(int divenr) } graphics()->plotDive(); information()->updateDiveInfo(); + locationInformationWidget()->setLocationId(displayed_dive.dive_site_uuid); } void MainWindow::on_actionNew_triggered() @@ -334,6 +355,8 @@ void MainWindow::closeCurrentFile() clear_git_id(); while (dive_table.nr) delete_single_dive(0); + while (dive_site_table.nr) + delete_dive_site(get_dive_site(0)->uuid); free((void *)existing_filename); existing_filename = NULL; @@ -532,6 +555,7 @@ void MainWindow::setupForAddAndPlan(const char *model) // setup the dive cylinders DivePlannerPointsModel::instance()->clear(); DivePlannerPointsModel::instance()->setupCylinders(); + locationInformationWidget()->setLocationId(0); } void MainWindow::on_actionReplanDive_triggered() diff --git a/qt-ui/mainwindow.h b/qt-ui/mainwindow.h index 25771d650..85a63123b 100644 --- a/qt-ui/mainwindow.h +++ b/qt-ui/mainwindow.h @@ -10,6 +10,7 @@ #include <QMainWindow> #include <QAction> #include <QUrl> +#include <QUuid> #include "ui_mainwindow.h" @@ -68,7 +69,7 @@ public: GlobeGPS *globe(); DivePlannerWidget *divePlannerWidget(); PlannerSettingsWidget *divePlannerSettingsWidget(); - + LocationInformationWidget *locationInformationWidget(); void showError(QString message); void setTitle(enum MainWindowTitleFormat format); @@ -159,6 +160,8 @@ slots: void on_paste_triggered(); void on_actionFilterTags_triggered(); void on_actionConfigure_Dive_Computer_triggered(); + void enableDiveSiteEdit(uint32_t id); + void setDefaultState(); protected: void closeEvent(QCloseEvent *); diff --git a/qt-ui/models.cpp b/qt-ui/models.cpp index ac2f7d899..19f0d12c0 100644 --- a/qt-ui/models.cpp +++ b/qt-ui/models.cpp @@ -1191,7 +1191,7 @@ QVariant DiveItem::data(int column, int role) const retVal = dive->maxcns; break; case LOCATION: - retVal = QString(dive->location); + retVal = QString(get_dive_location(dive)); break; } break; @@ -1232,7 +1232,7 @@ QVariant DiveItem::data(int column, int role) const retVal = dive->maxcns; break; case LOCATION: - retVal = QString(dive->location); + retVal = QString(get_dive_location(dive)); break; case GAS: const char *gas_string = get_dive_gas_string(dive); @@ -2110,7 +2110,7 @@ QVariant ProfilePrintModel::data(const QModelIndex &index, int role) const } if (row == 1) { if (col == 0) - return QString(dive->location); + return QString(get_dive_location(dive)); if (col == 3) return QString(tr("Duration: %1 min")).arg(di.displayDuration()); } diff --git a/qt-ui/printlayout.cpp b/qt-ui/printlayout.cpp index d9752d235..4be5fef73 100644 --- a/qt-ui/printlayout.cpp +++ b/qt-ui/printlayout.cpp @@ -462,7 +462,7 @@ void PrintLayout::addTablePrintDataRow(TablePrintModel *model, int row, struct d model->setData(model->index(row, 3), di.displayDuration(), Qt::DisplayRole); model->setData(model->index(row, 4), dive->divemaster, Qt::DisplayRole); model->setData(model->index(row, 5), dive->buddy, Qt::DisplayRole); - model->setData(model->index(row, 6), dive->location, Qt::DisplayRole); + model->setData(model->index(row, 6), get_dive_location(dive), Qt::DisplayRole); } void PrintLayout::addTablePrintHeadingRow(TablePrintModel *model, int row) const diff --git a/qt-ui/simplewidgets.cpp b/qt-ui/simplewidgets.cpp index 5c08a3f7e..27050f6e2 100644 --- a/qt-ui/simplewidgets.cpp +++ b/qt-ui/simplewidgets.cpp @@ -6,6 +6,7 @@ #include <QShortcut> #include <QCalendarWidget> #include <QKeyEvent> +#include <QAction> #include "file.h" #include "mainwindow.h" @@ -456,8 +457,7 @@ DiveComponentSelection::DiveComponentSelection(QWidget *parent, struct dive *tar { ui.setupUi(this); what = _what; - UI_FROM_COMPONENT(location); - UI_FROM_COMPONENT(gps); + UI_FROM_COMPONENT(divesite); UI_FROM_COMPONENT(divemaster); UI_FROM_COMPONENT(buddy); UI_FROM_COMPONENT(rating); @@ -477,8 +477,7 @@ DiveComponentSelection::DiveComponentSelection(QWidget *parent, struct dive *tar void DiveComponentSelection::buttonClicked(QAbstractButton *button) { if (ui.buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole) { - COMPONENT_FROM_UI(location); - COMPONENT_FROM_UI(gps); + COMPONENT_FROM_UI(divesite); COMPONENT_FROM_UI(divemaster); COMPONENT_FROM_UI(buddy); COMPONENT_FROM_UI(rating); @@ -646,3 +645,93 @@ void MultiFilter::closeFilter() MultiFilterSortModel::instance()->clearFilter(); hide(); } +#include <QDebug> +#include <QShowEvent> + +LocationInformationWidget::LocationInformationWidget(QWidget *parent) : QGroupBox(parent) +{ + ui.setupUi(this); + ui.diveSiteMessage->setText("You are editing the Dive Site"); + ui.diveSiteMessage->setCloseButtonVisible(false); + + QAction *action = new QAction(tr("Apply changes"), this); + connect(action, SIGNAL(triggered(bool)), this, SLOT(acceptChanges())); + ui.diveSiteMessage->addAction(action); + + action = new QAction(tr("Discard changes"), this); + connect(action, SIGNAL(triggered(bool)), this, SLOT(rejectChanges())); + ui.diveSiteMessage->addAction(action); +} + +void LocationInformationWidget::setLocationId(uint32_t uuid) +{ + currentDs = get_dive_site_by_uuid(uuid); + + if (!currentDs) { + currentDs = get_dive_site_by_uuid(create_dive_site("")); + displayed_dive.dive_site_uuid = currentDs->uuid; + ui.diveSiteName->clear(); + ui.diveSiteDescription->clear(); + ui.diveSiteNotes->clear(); + ui.diveSiteCoordinates->clear(); + } + displayed_dive_site = *currentDs; + ui.diveSiteName->setText(displayed_dive_site.name); + ui.diveSiteDescription->setText(displayed_dive_site.description); + ui.diveSiteNotes->setPlainText(displayed_dive_site.notes); + ui.diveSiteCoordinates->setText(printGPSCoords(displayed_dive_site.latitude.udeg, displayed_dive_site.longitude.udeg)); +} + +void LocationInformationWidget::updateGpsCoordinates() +{ + ui.diveSiteCoordinates->setText(printGPSCoords(displayed_dive_site.latitude.udeg, displayed_dive_site.longitude.udeg)); + MainWindow::instance()->setApplicationState("EditDiveSite"); +} + +void LocationInformationWidget::acceptChanges() +{ + char *uiString; + currentDs->latitude = displayed_dive_site.latitude; + currentDs->longitude = displayed_dive_site.longitude; + uiString = ui.diveSiteName->text().toUtf8().data(); + if (!same_string(uiString, currentDs->name)) { + free(currentDs->name); + currentDs->name = copy_string(uiString); + } + uiString = ui.diveSiteDescription->text().toUtf8().data(); + if (!same_string(uiString, currentDs->description)) { + free(currentDs->description); + currentDs->description = copy_string(uiString); + } + uiString = ui.diveSiteNotes->document()->toPlainText().toUtf8().data(); + if (!same_string(uiString, currentDs->notes)) { + free(currentDs->notes); + currentDs->notes = copy_string(uiString); + } + if (dive_site_is_empty(currentDs)) { + delete_dive_site(currentDs->uuid); + displayed_dive.dive_site_uuid = 0; + setLocationId(0); + } else { + setLocationId(currentDs->uuid); + } + mark_divelist_changed(true); + emit informationManagementEnded(); +} + +void LocationInformationWidget::rejectChanges() +{ + Q_ASSERT(currentDs != NULL); + if (dive_site_is_empty(currentDs)) { + delete_dive_site(currentDs->uuid); + displayed_dive.dive_site_uuid = 0; + setLocationId(0); + } else { + setLocationId(currentDs->uuid); + } + emit informationManagementEnded(); +} + +void LocationInformationWidget::showEvent(QShowEvent *ev) { + ui.diveSiteMessage->setCloseButtonVisible(false); +} diff --git a/qt-ui/simplewidgets.h b/qt-ui/simplewidgets.h index 8d5b4f73c..d0cb60508 100644 --- a/qt-ui/simplewidgets.h +++ b/qt-ui/simplewidgets.h @@ -6,6 +6,7 @@ class QAbstractButton; class QNetworkReply; #include <QWidget> +#include <QGroupBox> #include <QDialog> #include <stdint.h> @@ -214,6 +215,30 @@ private: Ui::FilterWidget ui; }; +#include "ui_locationInformation.h" + +class LocationInformationWidget : public QGroupBox { +Q_OBJECT +public: + LocationInformationWidget(QWidget *parent = 0); + +public slots: + void acceptChanges(); + void rejectChanges(); + + void showEvent(QShowEvent *); + + void setLocationId(uint32_t uuid); + void updateGpsCoordinates(void); + +signals: + void informationManagementEnded(); + +private: + struct dive_site *currentDs; + Ui::LocationInformation ui; +}; + bool isGnome3Session(); QImage grayImage(const QImage &coloredImg); diff --git a/qt-ui/socialnetworks.cpp b/qt-ui/socialnetworks.cpp index 21ccf9354..6a81d5db7 100644 --- a/qt-ui/socialnetworks.cpp +++ b/qt-ui/socialnetworks.cpp @@ -302,7 +302,7 @@ void SocialNetworkDialog::selectionChanged() tr("min", "abbreviation for minutes"))); } if (ui->Location->isChecked()) { - fullText += tr("Dive location: %1 \n").arg(d->location); + fullText += tr("Dive location: %1 \n").arg(get_dive_location(d)); } if (ui->Buddy->isChecked()) { fullText += tr("Buddy: %1 \n").arg(d->buddy); diff --git a/qt-ui/subsurfacewebservices.cpp b/qt-ui/subsurfacewebservices.cpp index 72e7e3d27..17c15583f 100644 --- a/qt-ui/subsurfacewebservices.cpp +++ b/qt-ui/subsurfacewebservices.cpp @@ -29,7 +29,25 @@ #endif struct dive_table gps_location_table; -static bool merge_locations_into_dives(void); + +// we don't overwrite any existing GPS info in the dive +// so get the dive site and if there is none or there is one without GPS fix, add it +static void copy_gps_location(struct dive *from, struct dive *to) +{ + struct dive_site *ds = get_dive_site_for_dive(to); + if (!ds || !dive_site_has_gps_location(ds)) { + struct dive_site *gds = get_dive_site_for_dive(from); + if (!ds) { + // simply link to the one created for the fake dive + to->dive_site_uuid = gds->uuid; + } else { + ds->latitude = gds->latitude; + ds->longitude = gds->longitude; + if (same_string(ds->name, "")) + ds->name = copy_string(gds->name); + } + } +} #define SAME_GROUP 6 * 3600 // six hours //TODO: C Code. static functions are not good if we plan to have a test for them. @@ -42,14 +60,14 @@ static bool merge_locations_into_dives(void) for_each_dive (i, dive) { if (!dive_has_gps_location(dive)) { - for (j = tracer; (gpsfix = get_gps_location(j, &gps_location_table)) !=NULL; j++) { + for (j = tracer; (gpsfix = get_dive_from_table(j, &gps_location_table)) !=NULL; j++) { if (dive_within_time_range (dive, gpsfix->when, SAME_GROUP)) { /* * If position is fixed during dive. This is the good one. * Asign and mark position, and end gps_location loop */ if ((dive->when <= gpsfix->when && gpsfix->when <= dive->when + dive->duration.seconds)) { - copy_gps_location(gpsfix,dive); + copy_gps_location(gpsfix, dive); changed++; tracer = j; break; @@ -57,7 +75,7 @@ static bool merge_locations_into_dives(void) /* * If it is not, check if there are more position fixes in SAME_GROUP range */ - if ((nextgpsfix = get_gps_location(j+1,&gps_location_table)) && + if ((nextgpsfix = get_dive_from_table(j+1,&gps_location_table)) && dive_within_time_range (dive, nextgpsfix->when, SAME_GROUP)) { /* * If distance from gpsfix to end of dive is shorter than distance between @@ -65,7 +83,7 @@ static bool merge_locations_into_dives(void) * If not, simply fail and nextgpsfix will be evaluated in next iteration. */ if ((dive->when + dive->duration.seconds - gpsfix->when) < (nextgpsfix->when - gpsfix->when)) { - copy_gps_location(gpsfix,dive); + copy_gps_location(gpsfix, dive); tracer = j; break; } @@ -73,7 +91,7 @@ static bool merge_locations_into_dives(void) * If no more positions in range, the actual is the one. Asign, mark and end loop. */ } else { - copy_gps_location(gpsfix,dive); + copy_gps_location(gpsfix, dive); changed++; tracer = j; break; @@ -329,10 +347,19 @@ void SubsurfaceWebServices::buttonClicked(QAbstractButton *button) ui.buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false); switch (ui.buttonBox->buttonRole(button)) { case QDialogButtonBox::ApplyRole: { + int i; + struct dive *d; + struct dive_site *ds; clear_table(&gps_location_table); QByteArray url = tr("Webservice").toLocal8Bit(); parse_xml_buffer(url.data(), downloadedData.data(), downloadedData.length(), &gps_location_table, NULL); - + // make sure we mark all the dive sites that were created + for (i = 0; i < gps_location_table.nr; i++) { + d = get_dive_from_table(i, &gps_location_table); + ds = get_dive_site_by_uuid(d->dive_site_uuid); + if (ds) + ds->notes = strdup("SubsurfaceWebservice"); + } /* now merge the data in the gps_location table into the dive_table */ if (merge_locations_into_dives()) { mark_divelist_changed(true); @@ -361,6 +388,16 @@ void SubsurfaceWebServices::buttonClicked(QAbstractButton *button) hide(); close(); resetState(); + /* and now clean up and remove all the extra dive sites that were created */ + QSet<uint32_t> usedUuids; + for_each_dive(i, d) { + if (d->dive_site_uuid) + usedUuids.insert(d->dive_site_uuid); + } + for_each_dive_site(i, ds) { + if (!usedUuids.contains(ds->uuid) && same_string(ds->notes, "SubsurfaceWebservice")) + delete_dive_site(ds->uuid); + } } break; case QDialogButtonBox::RejectRole: if (reply != NULL && reply->isOpen()) { diff --git a/qthelper.cpp b/qthelper.cpp index acb1e103a..902dc5e6d 100644 --- a/qthelper.cpp +++ b/qthelper.cpp @@ -165,6 +165,7 @@ bool parseGpsText(const QString &gps_text, double *latitude, double *longitude) pos == gps_text.size(); } +#if 0 // we'll need something like this for the dive site management, eventually bool gpsHasChanged(struct dive *dive, struct dive *master, const QString &gps_text, bool *parsed_out) { double latitude, longitude; @@ -193,6 +194,7 @@ bool gpsHasChanged(struct dive *dive, struct dive *master, const QString &gps_te dive->longitude.udeg = longudeg; return true; } +#endif QList<int> getDivesInTrip(dive_trip_t *trip) { diff --git a/save-git.c b/save-git.c index 6c2587bf8..84eb1a316 100644 --- a/save-git.c +++ b/save-git.c @@ -104,8 +104,6 @@ static void show_utf8(struct membuffer *b, const char *prefix, const char *value static void save_overview(struct membuffer *b, struct dive *dive) { - show_gps(b, dive->latitude, dive->longitude); - show_utf8(b, "location ", dive->location, "\n"); show_utf8(b, "divemaster ", dive->divemaster, "\n"); show_utf8(b, "buddy ", dive->buddy, "\n"); show_utf8(b, "suit ", dive->suit, "\n"); @@ -390,6 +388,7 @@ static void create_dive_buffer(struct dive *dive, struct membuffer *b) SAVE("visibility", visibility); cond_put_format(dive->tripflag == NO_TRIP, b, "notrip\n"); save_tags(b, dive->tag_list); + cond_put_format(dive->dive_site_uuid, b, "divesiteid %08x\n", dive->dive_site_uuid); save_overview(b, dive); save_cylinder_info(b, dive); @@ -804,7 +803,7 @@ static void save_one_device(void *_b, const char *model, uint32_t deviceid, put_string(b, "\n"); } -#define VERSION 2 +#define VERSION 3 static void save_settings(git_repository *repo, struct dir *tree) { @@ -818,6 +817,38 @@ static void save_settings(git_repository *repo, struct dir *tree) blob_insert(repo, tree, &b, "00-Subsurface"); } +static void save_divesites(git_repository *repo, struct dir *tree) +{ + struct dir *subdir; + struct membuffer dirname = { 0 }; + put_format(&dirname, "01-Divesites"); + subdir = new_directory(repo, tree, &dirname); + + for (int i = 0; i < dive_site_table.nr; i++) { + struct membuffer b = { 0 }; + struct dive_site *ds = get_dive_site(i); + if (dive_site_is_empty(ds)) { + int j; + struct dive *d; + for_each_dive(j, d) { + if (d->dive_site_uuid == ds->uuid) + d->dive_site_uuid = 0; + } + delete_dive_site(get_dive_site(i)->uuid); + i--; // since we just deleted that one + continue; + } + int size = sizeof("Site-012345678"); + char name[size]; + snprintf(name, size, "Site-%08x", ds->uuid); + show_utf8(&b, "name ", ds->name, "\n"); + show_utf8(&b, "description ", ds->description, "\n"); + show_utf8(&b, "notes ", ds->notes, "\n"); + show_gps(&b, ds->latitude, ds->longitude); + blob_insert(repo, subdir, &b, name); + } +} + static int create_git_tree(git_repository *repo, struct dir *root, bool select_only) { int i; @@ -826,6 +857,8 @@ static int create_git_tree(git_repository *repo, struct dir *root, bool select_o save_settings(repo, root); + save_divesites(repo, root); + for (trip = dive_trip_list; trip != NULL; trip = trip->next) trip->index = 0; @@ -938,7 +971,7 @@ static void create_commit_message(struct membuffer *msg) if (dive) { dive_trip_t *trip = dive->divetrip; - const char *location = dive->location ? : "no location"; + const char *location = get_dive_location(dive) ? : "no location"; struct divecomputer *dc = &dive->dc; const char *sep = "\n"; diff --git a/save-html.c b/save-html.c index d67931d8f..13d2fd559 100644 --- a/save-html.c +++ b/save-html.c @@ -172,8 +172,11 @@ void put_HTML_samples(struct membuffer *b, struct dive *dive) void put_HTML_coordinates(struct membuffer *b, struct dive *dive) { - degrees_t latitude = dive->latitude; - degrees_t longitude = dive->longitude; + struct dive_site *ds = get_dive_site_for_dive(dive); + if (!ds) + return; + degrees_t latitude = ds->latitude; + degrees_t longitude = ds->longitude; //don't put coordinates if in (0,0) if (!latitude.udeg && !longitude.udeg) @@ -304,7 +307,7 @@ void write_one_dive(struct membuffer *b, struct dive *dive, const char *photos_d put_format(b, "\"subsurface_number\":%d,", dive->number); put_HTML_date(b, dive, "\"date\":\"", "\","); put_HTML_time(b, dive, "\"time\":\"", "\","); - write_attribute(b, "location", dive->location, ", "); + write_attribute(b, "location", get_dive_location(dive), ", "); put_HTML_coordinates(b, dive); put_format(b, "\"rating\":%d,", dive->rating); put_format(b, "\"visibility\":%d,", dive->visibility); diff --git a/save-xml.c b/save-xml.c index 053b8fc96..c09b90812 100644 --- a/save-xml.c +++ b/save-xml.c @@ -110,38 +110,8 @@ static void save_salinity(struct membuffer *b, struct divecomputer *dc) put_string(b, " />\n"); } -static void show_location(struct membuffer *b, struct dive *dive) -{ - degrees_t latitude = dive->latitude; - degrees_t longitude = dive->longitude; - - /* Should we write a location tag at all? */ - if (!(latitude.udeg || longitude.udeg) && !dive->location) - return; - - put_string(b, " <location"); - - /* - * Ok, theoretically I guess you could dive at - * exactly 0,0. But we don't support that. So - * if you do, just fudge it a bit, and say that - * you dove a few meters away. - */ - if (latitude.udeg || longitude.udeg) { - put_degrees(b, latitude, " gps='", " "); - put_degrees(b, longitude, "", "'"); - } - - /* Do we have a location name or should we write a empty tag? */ - if (dive->location && dive->location[0] != '\0') - show_utf8(b, dive->location, ">", "</location>\n", 0); - else - put_string(b, "/>\n"); -} - static void save_overview(struct membuffer *b, struct dive *dive) { - show_location(b, dive); show_utf8(b, dive->divemaster, " <divemaster>", "</divemaster>\n", 0); show_utf8(b, dive->buddy, " <buddy>", "</buddy>\n", 0); show_utf8(b, dive->notes, " <notes>", "</notes>\n", 0); @@ -424,7 +394,8 @@ void save_one_dive(struct membuffer *b, struct dive *dive) if (dive->visibility) put_format(b, " visibility='%d'", dive->visibility); save_tags(b, dive->tag_list); - + if (dive->dive_site_uuid) + put_format(b, " divesiteid='%8x'", dive->dive_site_uuid); show_date(b, dive->when); put_format(b, " duration='%u:%02u min'>\n", FRACTION(dive->dc.duration.seconds, 60)); @@ -507,7 +478,7 @@ static void save_one_device(void *_f, const char *model, uint32_t deviceid, put_format(b, "/>\n"); } -#define VERSION 2 +#define VERSION 3 int save_dives(const char *filename) { @@ -529,8 +500,34 @@ void save_dives_buffer(struct membuffer *b, const bool select_only) call_for_each_dc(b, save_one_device); if (autogroup) put_format(b, " <autogroup state='1' />\n"); - put_format(b, "</settings>\n<dives>\n"); - + put_format(b, "</settings>\n"); + + /* save the dive sites */ + put_format(b, "<divesites>\n"); + for (i = 0; i < dive_site_table.nr; i++) { + struct dive_site *ds = get_dive_site(i); + if (dive_site_is_empty(ds)) { + int j; + struct dive *d; + for_each_dive(j, d) { + if (d->dive_site_uuid == ds->uuid) + d->dive_site_uuid = 0; + } + delete_dive_site(get_dive_site(i)->uuid); + i--; // since we just deleted that one + continue; + } + put_format(b, "<site uuid='%8x' ", ds->uuid); + show_utf8(b, ds->name, " name='", "'", 1); + if (ds->latitude.udeg || ds->longitude.udeg) { + put_degrees(b, ds->latitude, " gps='", " "); + put_degrees(b, ds->longitude, "", "'"); + } + show_utf8(b, ds->description, " description='", "'", 1); + show_utf8(b, ds->notes, " notes='", "'", 1); + put_format(b, "/>\n"); + } + put_format(b, "</divesites>\n<dives>\n"); for (trip = dive_trip_list; trip != NULL; trip = trip->next) trip->index = 0; @@ -605,7 +602,15 @@ static void try_to_backup(const char *filename) while (extension[i][0] != '\0') { int elen = strlen(extension[i]); if (strcasecmp(filename + flen - elen, extension[i]) == 0) { - save_backup(filename, extension[i], "bak"); + if (last_xml_version < VERSION) { + int se_len = strlen(extension[i]) + 5; + char *special_ext = malloc(se_len); + snprintf(special_ext, se_len, "%s.v%d", extension[i], last_xml_version); + save_backup(filename, extension[i], special_ext); + free(special_ext); + } else { + save_backup(filename, extension[i], "bak"); + } break; } i++; diff --git a/subsurface.pro b/subsurface.pro index d65c94f50..4853796c0 100644 --- a/subsurface.pro +++ b/subsurface.pro @@ -29,6 +29,7 @@ HEADERS = \ display.h \ dive.h \ divelist.h \ + divesite.h \ file.h \ gettextfromc.h \ gettext.h \ @@ -119,6 +120,7 @@ SOURCES = \ device.c \ dive.c \ divelist.c \ + divesite.c \ equipment.c \ file.c \ gettextfromc.cpp \ @@ -238,7 +240,8 @@ FORMS = \ qt-ui/listfilter.ui \ qt-ui/diveshareexportdialog.ui \ qt-ui/filterwidget.ui \ - qt-ui/plannerDetails.ui + qt-ui/plannerDetails.ui \ + qt-ui/locationInformation.ui # Nether usermanual or printing is supported on android right now android: FORMS -= qt-ui/printoptions.ui diff --git a/uemis-downloader.c b/uemis-downloader.c index 7ce25cd57..b9ea57b62 100644 --- a/uemis-downloader.c +++ b/uemis-downloader.c @@ -638,12 +638,12 @@ static void parse_divespot(char *buf) uemis_set_divelocation(divespot, locationstring, latitude, longitude); } -static void track_divespot(char *val, int diveid, char **location, degrees_t *latitude, degrees_t *longitude) +static void track_divespot(char *val, int diveid, uint32_t dive_site_uuid) { int id = atoi(val); if (id >= 0 && id > nr_divespots) nr_divespots = id; - uemis_mark_divelocation(diveid, id, location, latitude, longitude); + uemis_mark_divelocation(diveid, id, dive_site_uuid); return; } @@ -783,7 +783,8 @@ static bool process_raw_buffer(device_data_t *devdata, uint32_t deviceid, char * if (for_dive) *for_dive = atoi(val); } else if (!log && dive && !strcmp(tag, "divespot_id")) { - track_divespot(val, dive->dc.diveid, &dive->location, &dive->latitude, &dive->longitude); + dive->dive_site_uuid = create_dive_site("from Uemis"); + track_divespot(val, dive->dc.diveid, dive->dive_site_uuid); } else if (dive) { parse_tag(dive, tag, val); } @@ -103,9 +103,7 @@ struct uemis_helper { int diveid; int lbs; int divespot; - char **location; - degrees_t *latitude; - degrees_t *longitude; + int dive_site_uuid; struct uemis_helper *next; }; static struct uemis_helper *uemis_helper = NULL; @@ -150,27 +148,22 @@ int uemis_get_weight_unit(int diveid) return 0; } -void uemis_mark_divelocation(int diveid, int divespot, char **location, degrees_t *latitude, degrees_t *longitude) +void uemis_mark_divelocation(int diveid, int divespot, uint32_t dive_site_uuid) { struct uemis_helper *hp = uemis_get_helper(diveid); hp->divespot = divespot; - hp->location = location; - hp->longitude = longitude; - hp->latitude = latitude; + hp->dive_site_uuid = dive_site_uuid; } void uemis_set_divelocation(int divespot, char *text, double longitude, double latitude) { struct uemis_helper *hp = uemis_helper; -#if 0 /* seems overkill */ - if (!g_utf8_validate(text, -1, NULL)) - return; -#endif while (hp) { - if (hp->divespot == divespot && hp->location) { - *hp->location = strdup(text); - hp->longitude->udeg = round(longitude * 1000000); - hp->latitude->udeg = round(latitude * 1000000); + if (hp->divespot == divespot) { + struct dive_site *ds = get_dive_site_by_uuid(hp->dive_site_uuid); + ds->name = strdup(text); + ds->longitude.udeg = round(longitude * 1000000); + ds->latitude.udeg = round(latitude * 1000000); } hp = hp->next; } @@ -14,7 +14,7 @@ extern "C" { void uemis_parse_divelog_binary(char *base64, void *divep); int uemis_get_weight_unit(int diveid); -void uemis_mark_divelocation(int diveid, int divespot, char **location, degrees_t *latitude, degrees_t *longitude); +void uemis_mark_divelocation(int diveid, int divespot, uint32_t dive_site_uuid); void uemis_set_divelocation(int divespot, char *text, double longitude, double latitude); typedef struct diff --git a/worldmap-save.c b/worldmap-save.c index a7e9d82c2..22bfe583e 100644 --- a/worldmap-save.c +++ b/worldmap-save.c @@ -27,11 +27,11 @@ void writeMarkers(struct membuffer *b, const bool selected_only) if (!dive->selected) continue; } - if (dive->latitude.udeg == 0 && dive->longitude.udeg == 0) + struct dive_site *ds = get_dive_site_for_dive(dive); + if (!ds || !dive_site_has_gps_location(ds)) continue; - - put_degrees(b, dive->latitude, "temp = new google.maps.Marker({position: new google.maps.LatLng(", ""); - put_degrees(b, dive->longitude, ",", ")});\n"); + put_degrees(b, ds->latitude, "temp = new google.maps.Marker({position: new google.maps.LatLng(", ""); + put_degrees(b, ds->longitude, ",", ")});\n"); put_string(b, "markers.push(temp);\ntempinfowindow = new google.maps.InfoWindow({content: '<div id=\"content\">'+'<div id=\"siteNotice\">'+'</div>'+'<div id=\"bodyContent\">"); snprintf(pre, sizeof(pre), "<p>%s ", translate("gettextFromC", "Date:")); put_HTML_date(b, dive, pre, "</p>"); @@ -49,7 +49,7 @@ void writeMarkers(struct membuffer *b, const bool selected_only) put_HTML_watertemp(b, dive, pre, "</p>"); snprintf(pre, sizeof(pre), "<p>%s <b>", translate("gettextFromC", "Location:")); put_string(b, pre); - put_HTML_quoted(b, dive->location); + put_HTML_quoted(b, get_dive_location(dive)); put_string(b, "</b></p>"); snprintf(pre, sizeof(pre), "<p> %s ", translate("gettextFromC", "Notes:")); put_HTML_notes(b, dive, pre, " </p>"); |