mirror of
https://github.com/subsurface/subsurface.git
synced 2025-01-20 06:45:27 +00:00
Merge branch 'integrate-from-webservice'
Bring in the better implementation of merging gps locations from the webservice
This commit is contained in:
commit
36b34bd5a5
9 changed files with 142 additions and 77 deletions
35
dive.c
35
dive.c
|
@ -1519,3 +1519,38 @@ struct dive *merge_dives(struct dive *a, struct dive *b, int offset, gboolean pr
|
|||
fixup_dive(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
struct dive *find_dive_including(timestamp_t when)
|
||||
{
|
||||
int i;
|
||||
struct dive *dive;
|
||||
|
||||
/* binary search, anyone? Too lazy for now;
|
||||
* also we always use the duration from the first divecomputer
|
||||
* could this ever be a problem? */
|
||||
for_each_dive(i, dive) {
|
||||
if (dive->when <= when && when <= dive->when + dive->dc.duration.seconds)
|
||||
return dive;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean dive_within_time_range(struct dive *dive, timestamp_t when, timestamp_t offset)
|
||||
{
|
||||
return when - offset <= dive->when && dive->when + dive->dc.duration.seconds <= when + offset;
|
||||
}
|
||||
|
||||
/* find the n-th dive that is part of a group of dives within the offset around 'when'.
|
||||
* How is that for a vague definition of what this function should do... */
|
||||
struct dive *find_dive_n_near(timestamp_t when, int n, timestamp_t offset)
|
||||
{
|
||||
int i, j = 0;
|
||||
struct dive *dive;
|
||||
|
||||
for_each_dive(i, dive) {
|
||||
if (dive_within_time_range(dive, when, offset))
|
||||
if (++j == n)
|
||||
return dive;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
27
dive.h
27
dive.h
|
@ -321,11 +321,19 @@ struct dive {
|
|||
struct divecomputer dc;
|
||||
};
|
||||
|
||||
static inline int dive_has_location(struct dive *dive)
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pa = N/m^2 - so we determine the weight (in N) of the mass of 10m
|
||||
* of water (and use standard salt water at 1.03kg per liter if we don't know salinity)
|
||||
* and add that to the surface pressure (or to 1013 if that's unknown) */
|
||||
|
@ -433,6 +441,13 @@ extern struct dive_table dive_table;
|
|||
extern int selected_dive;
|
||||
#define current_dive (get_dive(selected_dive))
|
||||
|
||||
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)
|
||||
|
@ -450,6 +465,9 @@ static inline struct dive *get_dive(int nr)
|
|||
#define for_each_dive(_i,_x) \
|
||||
for ((_i) = 0; ((_x) = get_dive(_i)) != NULL; (_i)++)
|
||||
|
||||
#define for_each_gps_location(_i,_x) \
|
||||
for ((_i) = 0; ((_x) = get_gps_location(_i, &gps_location_table)) != NULL; (_i)++)
|
||||
|
||||
static inline struct dive *get_dive_by_diveid(int diveid, int deviceid)
|
||||
{
|
||||
int i;
|
||||
|
@ -464,12 +482,15 @@ static inline struct dive *get_dive_by_diveid(int diveid, int deviceid)
|
|||
}
|
||||
return NULL;
|
||||
}
|
||||
extern struct dive *find_dive_including(timestamp_t when);
|
||||
extern gboolean dive_within_time_range(struct dive *dive, timestamp_t when, timestamp_t offset);
|
||||
struct dive *find_dive_n_near(timestamp_t when, int n, timestamp_t offset);
|
||||
|
||||
/* Check if two dive computer entries are the exact same dive (-1=no/0=maybe/1=yes) */
|
||||
extern int match_one_dc(struct divecomputer *a, struct divecomputer *b);
|
||||
|
||||
extern void parse_xml_init(void);
|
||||
extern void parse_xml_buffer(const char *url, const char *buf, int size, GError **error);
|
||||
extern void parse_xml_buffer(const char *url, const char *buf, int size, struct dive_table *table, GError **error);
|
||||
extern void parse_xml_exit(void);
|
||||
extern void set_filename(const char *filename, gboolean force);
|
||||
|
||||
|
@ -500,11 +521,11 @@ extern void utc_mkdate(timestamp_t, struct tm *tm);
|
|||
|
||||
extern struct dive *alloc_dive(void);
|
||||
extern void record_dive(struct dive *dive);
|
||||
extern void delete_dive(struct dive *dive);
|
||||
|
||||
extern struct sample *prepare_sample(struct divecomputer *dc);
|
||||
extern void finish_sample(struct divecomputer *dc);
|
||||
|
||||
extern void sort_table(struct dive_table *table);
|
||||
extern void report_dives(gboolean imported, gboolean prefer_imported);
|
||||
extern struct dive *fixup_dive(struct dive *dive);
|
||||
extern struct dive *merge_dives(struct dive *a, struct dive *b, int offset, gboolean prefer_downloaded);
|
||||
|
|
|
@ -875,7 +875,7 @@ GdkPixbuf *get_gps_icon(void)
|
|||
|
||||
static GdkPixbuf *get_gps_icon_for_dive(struct dive *dive)
|
||||
{
|
||||
if (dive_has_location(dive))
|
||||
if (dive_has_gps_location(dive))
|
||||
return get_gps_icon();
|
||||
else
|
||||
return NULL;
|
||||
|
@ -1608,7 +1608,7 @@ gboolean icon_click_cb(GtkWidget *w, GdkEventButton *event, gpointer data)
|
|||
gtk_tree_model_get_iter(MODEL(dive_list), &iter, path);
|
||||
gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &idx, -1);
|
||||
dive = get_dive(idx);
|
||||
if (dive && dive_has_location(dive))
|
||||
if (dive && dive_has_gps_location(dive))
|
||||
show_gps_location(dive, NULL);
|
||||
}
|
||||
if (path)
|
||||
|
@ -2435,7 +2435,7 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int
|
|||
}
|
||||
#if HAVE_OSM_GPS_MAP
|
||||
/* Only offer to show on map if it has a location. */
|
||||
if (dive_has_location(dive)) {
|
||||
if (dive_has_gps_location(dive)) {
|
||||
menuitem = gtk_menu_item_new_with_label(_("Show in map"));
|
||||
g_signal_connect(menuitem, "activate", G_CALLBACK(show_gps_location_cb), dive);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
|
||||
|
|
2
file.c
2
file.c
|
@ -246,7 +246,7 @@ static void parse_file_buffer(const char *filename, struct memblock *mem, GError
|
|||
if (fmt && open_by_filename(filename, fmt+1, mem, error))
|
||||
return;
|
||||
|
||||
parse_xml_buffer(filename, mem->buffer, mem->size, error);
|
||||
parse_xml_buffer(filename, mem->buffer, mem->size, &dive_table, error);
|
||||
}
|
||||
|
||||
void parse_file(const char *filename, GError **error, gboolean possible_default_filename)
|
||||
|
|
2
gps.c
2
gps.c
|
@ -242,7 +242,7 @@ void show_gps_locations()
|
|||
map = init_map();
|
||||
|
||||
for_each_dive(idx, dive) {
|
||||
if (dive_has_location(dive)) {
|
||||
if (dive_has_gps_location(dive)) {
|
||||
add_gps_point(map, dive->latitude.udeg / 1000000.0,
|
||||
dive->longitude.udeg / 1000000.0);
|
||||
}
|
||||
|
|
2
info.c
2
info.c
|
@ -675,7 +675,7 @@ static void dive_info_widget(GtkWidget *box, struct dive *dive, struct dive_info
|
|||
|
||||
info->location = text_entry(box, _("Location"), location_list, dive->location);
|
||||
|
||||
if (dive_has_location(dive))
|
||||
if (dive_has_gps_location(dive))
|
||||
print_gps_coordinates(gps_text, sizeof(gps_text), dive->latitude.udeg / 1000000.0,
|
||||
dive->longitude.udeg / 1000000.0);
|
||||
hbox = gtk_hbox_new(FALSE, 2);
|
||||
|
|
7
main.c
7
main.c
|
@ -50,6 +50,11 @@ static int sortfn(const void *_a, const void *_b)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void sort_table(struct dive_table *table)
|
||||
{
|
||||
qsort(table->dives, table->nr, sizeof(struct dive *), sortfn);
|
||||
}
|
||||
|
||||
const char *weekday(int wday)
|
||||
{
|
||||
static const char wday_array[7][7] = {
|
||||
|
@ -157,7 +162,7 @@ void report_dives(gboolean is_imported, gboolean prefer_imported)
|
|||
/* This does the right thing for -1: NULL */
|
||||
last = get_dive(preexisting-1);
|
||||
|
||||
qsort(dive_table.dives, dive_table.nr, sizeof(struct dive *), sortfn);
|
||||
sort_table(&dive_table);
|
||||
|
||||
for (i = 1; i < dive_table.nr; i++) {
|
||||
struct dive **pp = &dive_table.dives[i-1];
|
||||
|
|
82
parse-xml.c
82
parse-xml.c
|
@ -4,6 +4,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#define __USE_XOPEN
|
||||
#include <time.h>
|
||||
#include <libxml/parser.h>
|
||||
|
@ -18,85 +19,34 @@
|
|||
|
||||
int verbose;
|
||||
|
||||
/* the dive table holds the overall dive list; target table points at
|
||||
* the table we are currently filling */
|
||||
struct dive_table dive_table;
|
||||
|
||||
struct dive_table *target_table = NULL;
|
||||
/*
|
||||
* Add a dive into the dive_table array
|
||||
*/
|
||||
void record_dive(struct dive *dive)
|
||||
static void record_dive_to_table(struct dive *dive, struct dive_table *table)
|
||||
{
|
||||
int nr = dive_table.nr, allocated = dive_table.allocated;
|
||||
struct dive **dives = dive_table.dives;
|
||||
assert(table != NULL);
|
||||
int nr = table->nr, allocated = table->allocated;
|
||||
struct dive **dives = table->dives;
|
||||
|
||||
if (nr >= allocated) {
|
||||
allocated = (nr + 32) * 3 / 2;
|
||||
dives = realloc(dives, allocated * sizeof(struct dive *));
|
||||
if (!dives)
|
||||
exit(1);
|
||||
dive_table.dives = dives;
|
||||
dive_table.allocated = allocated;
|
||||
table->dives = dives;
|
||||
table->allocated = allocated;
|
||||
}
|
||||
dives[nr] = fixup_dive(dive);
|
||||
dive_table.nr = nr+1;
|
||||
table->nr = nr+1;
|
||||
}
|
||||
|
||||
static void delete_dive_renumber(struct dive **dives, int i, int nr)
|
||||
void record_dive(struct dive *dive)
|
||||
{
|
||||
struct dive *dive = dives[i];
|
||||
int number = dive->number, j;
|
||||
|
||||
if (!number)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Check that all numbered dives after the deleted
|
||||
* ones are consecutive, return without renumbering
|
||||
* if that is not the case.
|
||||
*/
|
||||
for (j = i+1; j < nr; j++) {
|
||||
struct dive *next = dives[j];
|
||||
if (!next->number)
|
||||
break;
|
||||
number++;
|
||||
if (next->number != number)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ok, we hit the end of the dives or a unnumbered
|
||||
* dive - renumber.
|
||||
*/
|
||||
for (j = i+1 ; j < nr; j++) {
|
||||
struct dive *next = dives[j];
|
||||
if (!next->number)
|
||||
break;
|
||||
next->number--;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove a dive from the dive_table array
|
||||
*/
|
||||
void delete_dive(struct dive *dive)
|
||||
{
|
||||
int nr = dive_table.nr, i;
|
||||
struct dive **dives = dive_table.dives;
|
||||
|
||||
/*
|
||||
* Stupid. We know the dive table is sorted by date,
|
||||
* we could do a binary lookup. Sue me.
|
||||
*/
|
||||
for (i = 0; i < nr; i++) {
|
||||
struct dive *d = dives[i];
|
||||
if (d != dive)
|
||||
continue;
|
||||
/* should we re-number? */
|
||||
delete_dive_renumber(dives, i, nr);
|
||||
memmove(dives+i, dives+i+1, sizeof(struct dive *)*(nr-i-1));
|
||||
dives[nr] = NULL;
|
||||
dive_table.nr = nr-1;
|
||||
break;
|
||||
}
|
||||
record_dive_to_table(dive, &dive_table);
|
||||
}
|
||||
|
||||
static void start_match(const char *type, const char *name, char *buffer)
|
||||
|
@ -1172,7 +1122,7 @@ static void dive_end(void)
|
|||
if (!is_dive())
|
||||
free(cur_dive);
|
||||
else
|
||||
record_dive(cur_dive);
|
||||
record_dive_to_table(cur_dive, target_table);
|
||||
cur_dive = NULL;
|
||||
cur_dc = NULL;
|
||||
cur_cylinder_index = 0;
|
||||
|
@ -1480,10 +1430,12 @@ static void reset_all(void)
|
|||
import_source = UNKNOWN;
|
||||
}
|
||||
|
||||
void parse_xml_buffer(const char *url, const char *buffer, int size, GError **error)
|
||||
void parse_xml_buffer(const char *url, const char *buffer, int size,
|
||||
struct dive_table *table, GError **error)
|
||||
{
|
||||
xmlDoc *doc;
|
||||
|
||||
target_table = table;
|
||||
doc = xmlReadMemory(buffer, size, url, NULL, 0);
|
||||
if (!doc) {
|
||||
fprintf(stderr, _("Failed to parse '%s'.\n"), url);
|
||||
|
|
56
webservice.c
56
webservice.c
|
@ -4,8 +4,11 @@
|
|||
#include <libxml/tree.h>
|
||||
#include <libxml/parser.h>
|
||||
#include "dive.h"
|
||||
#include "divelist.h"
|
||||
#include "display-gtk.h"
|
||||
|
||||
struct dive_table gps_location_table;
|
||||
|
||||
enum {
|
||||
DD_STATUS_OK,
|
||||
DD_STATUS_ERROR_CONNECT,
|
||||
|
@ -142,6 +145,52 @@ static void download_dialog_delete(GtkWidget *w, gpointer data)
|
|||
download_dialog_release_xml(state);
|
||||
}
|
||||
|
||||
static gboolean is_automatic_fix(struct dive *gpsfix)
|
||||
{
|
||||
if (gpsfix && gpsfix->location && !strcmp(gpsfix->location, "automatic fix"))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#define SAME_GROUP 6 * 3600 // six hours
|
||||
|
||||
static void merge_locations_into_dives(void)
|
||||
{
|
||||
int i, nr = 0;
|
||||
struct dive *gpsfix, *last_named_fix = NULL, *dive;
|
||||
|
||||
sort_table(&gps_location_table);
|
||||
|
||||
for_each_gps_location(i, gpsfix) {
|
||||
if (is_automatic_fix(gpsfix)) {
|
||||
dive = find_dive_including(gpsfix->when);
|
||||
if (dive && !dive_has_gps_location(dive))
|
||||
copy_gps_location(gpsfix, dive);
|
||||
} else {
|
||||
if (last_named_fix && dive_within_time_range(last_named_fix, gpsfix->when, SAME_GROUP)) {
|
||||
nr++;
|
||||
} else {
|
||||
nr = 1;
|
||||
last_named_fix = gpsfix;
|
||||
}
|
||||
dive = find_dive_n_near(gpsfix->when, nr, SAME_GROUP);
|
||||
if (dive) {
|
||||
if (!dive_has_gps_location(dive))
|
||||
copy_gps_location(gpsfix, dive);
|
||||
if (!dive->location)
|
||||
dive->location = strdup(gpsfix->location);
|
||||
} else {
|
||||
struct tm tm;
|
||||
utc_mkdate(gpsfix->when, &tm);
|
||||
printf("didn't find dive matching gps fix named %s @ %04d-%02d-%02d %02d:%02d:%02d\n",
|
||||
gpsfix->location,
|
||||
tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void webservice_download_dialog(void)
|
||||
{
|
||||
const guint pad = 6;
|
||||
|
@ -203,8 +252,11 @@ void webservice_download_dialog(void)
|
|||
result = gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
if (result == GTK_RESPONSE_ACCEPT) {
|
||||
/* apply download */
|
||||
parse_xml_buffer(_("Webservice"), state.xmldata, state.xmldata_len, NULL);
|
||||
report_dives(TRUE, FALSE);
|
||||
parse_xml_buffer(_("Webservice"), state.xmldata, state.xmldata_len, &gps_location_table, NULL);
|
||||
/* now merge the data in the gps_location table into the dive_table */
|
||||
merge_locations_into_dives();
|
||||
mark_divelist_changed(TRUE);
|
||||
dive_list_update_dives();
|
||||
/* store last entered uid in config */
|
||||
subsurface_set_conf("webservice_uid", gtk_entry_get_text(GTK_ENTRY(uid)));
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue