diff options
-rw-r--r-- | dive.c | 5 | ||||
-rw-r--r-- | dive.h | 77 | ||||
-rw-r--r-- | divelist.c | 200 | ||||
-rw-r--r-- | info.c | 8 | ||||
-rw-r--r-- | parse-xml.c | 23 |
5 files changed, 206 insertions, 107 deletions
@@ -710,6 +710,11 @@ struct dive *try_to_merge(struct dive *a, struct dive *b) res = alloc_dive(); res->when = a->when; + /* the larger tripflag is more relevant */ + if(a->tripflag > b->tripflag) + res->tripflag = a->tripflag; + else + res->tripflag = b->tripflag; MERGE_NONZERO(res, a, b, latitude); MERGE_NONZERO(res, a, b, longitude); MERGE_TXT(res, a, b, location); @@ -237,13 +237,21 @@ struct event { #define W_IDX_SECONDARY 1 typedef gint64 timestamp_t; -typedef enum { TF_NONE, NO_TRIP, IN_TRIP, NUM_TRIPFLAGS } tripflag_t; +typedef enum { TF_NONE, NO_TRIP, IN_TRIP, ASSIGNED_TRIP, AUTOGEN_TRIP, NUM_TRIPFLAGS } tripflag_t; extern const char *tripflag_names[NUM_TRIPFLAGS]; +typedef struct dive_trip { + tripflag_t tripflag; + timestamp_t when; + timestamp_t when_from_file; + char *location; + char *notes; +} dive_trip_t; + struct dive { int number; tripflag_t tripflag; - struct dive *divetrip; + dive_trip_t *divetrip; int selected; timestamp_t when; char *location; @@ -276,72 +284,15 @@ extern gboolean autogroup; #define TRIP_THRESHOLD 3600*24*3 #define UNGROUPED_DIVE(_dive) ((_dive)->tripflag == NO_TRIP) -#define DIVE_IN_TRIP(_dive) ((_dive)->tripflag == IN_TRIP) +#define DIVE_IN_TRIP(_dive) ((_dive)->tripflag == IN_TRIP || (_dive)->tripflag == ASSIGNED_TRIP) #define DIVE_NEEDS_TRIP(_dive) ((_dive)->tripflag == TF_NONE) #define NEXT_TRIP(_entry) ((_entry) ? g_list_next(_entry) : (dive_trip_list)) #define PREV_TRIP(_entry) ((_entry) ? g_list_previous(_entry) : g_list_last(dive_trip_list)) -#define DIVE_TRIP(_trip) ((struct dive *)(_trip)->data) +#define DIVE_TRIP(_trip) ((dive_trip_t *)(_trip)->data) #define DIVE_FITS_TRIP(_dive, _dive_trip) ((_dive_trip)->when - TRIP_THRESHOLD <= (_dive)->when) -/* compare two dives by when they happened */ -static inline int dive_date_cmp(gconstpointer _a, gconstpointer _b) { - return ((struct dive *)_a)->when - ((struct dive *)_b)->when; -} - -/* returns 0 if the dive happened exactly at time */ -static inline int dive_when_find(gconstpointer _listentry, gconstpointer _when) -{ - const struct dive *dive = _listentry; - const timestamp_t *tsp = _when; - return dive->when != *tsp; -} - -static inline GList *FIND_TRIP(timestamp_t *when) -{ - return g_list_find_custom(dive_trip_list, when, dive_when_find); -} +extern void insert_trip(dive_trip_t **trip); -#ifdef DEBUG_TRIP -static void dump_trip_list(void) -{ - GList *p = NULL; - int i=0; - while ((p = NEXT_TRIP(p))) { - struct tm tm; - utc_mkdate(DIVE_TRIP(p)->when, &tm); - printf("trip %d to \"%s\" on %04u-%02u-%02u %02u:%02u:%02u\n", ++i, DIVE_TRIP(p)->location, - tm.tm_year + 1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); - } - printf("-----\n"); -} -#endif - -/* insert the trip into the dive_trip_list - but ensure you don't have - * two trips for the same date; but if you have, make sure you don't - * keep the one with less information */ -static void inline insert_trip(struct dive **trip) -{ - struct dive *dive_trip = *trip; - GList *result = FIND_TRIP(&dive_trip->when); - if (result) { - if (! DIVE_TRIP(result)->location) - DIVE_TRIP(result)->location = dive_trip->location; - *trip = DIVE_TRIP(result); - } else { - dive_trip_list = g_list_insert_sorted(dive_trip_list, dive_trip, dive_date_cmp); - } -#ifdef DEBUG_TRIP - dump_trip_list(); -#endif -} - -static inline void delete_trip(GList *trip) -{ - dive_trip_list = g_list_delete_link(dive_trip_list, trip); -#ifdef DEBUG_TRIP - dump_trip_list(); -#endif -} /* * We keep our internal data in well-specified units, but * the input and output may come in some random format. This @@ -456,7 +407,7 @@ extern void remember_event(const char *eventname); extern void evn_foreach(void (*callback)(const char *, int *, void *), void *data); extern int add_new_dive(struct dive *dive); -extern gboolean edit_trip(struct dive *trip); +extern gboolean edit_trip(dive_trip_t *trip); extern int edit_dive_info(struct dive *dive); extern int edit_multi_dive_info(struct dive *single_dive); extern void dive_list_update_dives(void); diff --git a/divelist.c b/divelist.c index 9a3493c99..d0332c2bb 100644 --- a/divelist.c +++ b/divelist.c @@ -41,7 +41,10 @@ static struct DiveList dive_list; GList *dive_trip_list; gboolean autogroup = FALSE; -const char *tripflag_names[NUM_TRIPFLAGS] = { "TF_NONE", "NOTRIP", "INTRIP" }; +/* this duplicate assignment of "INTRIP" causes the save_xml code + * to convert an ASSIGNED_TRIP (which is temporary in memory) to + * a statically assigned trip (INTRIP) in file */ +const char *tripflag_names[NUM_TRIPFLAGS] = { "TF_NONE", "NOTRIP", "INTRIP", "INTRIP", "AUTOGEN_TRIP" }; /* * The dive list has the dive data in both string format (for showing) @@ -942,19 +945,113 @@ void update_dive_list_col_visibility(void) return; } +/* + * helper functions for dive_trip handling + */ + +#ifdef DEBUG_TRIP +static void dump_trip_list(void) +{ + GList *p = NULL; + int i=0; + timestamp_t last_time = 0; + while ((p = NEXT_TRIP(p))) { + dive_trip_t *dive_trip = DIVE_TRIP(p); + struct tm *tm = gmtime(&dive_trip->when); + if (dive_trip->when < last_time) + printf("\n\ndive_trip_list OUT OF ORDER!!!\n\n\n"); + printf("%s trip %d to \"%s\" on %04u-%02u-%02u %02u:%02u:%02u\n", + dive_trip->tripflag == AUTOGEN_TRIP ? "autogen " : "", + ++i, dive_trip->location, + tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); + if (dive_trip->when_from_file && dive_trip->when != dive_trip->when_from_file) { + tm = gmtime(&dive_trip->when_from_file); + printf("originally on %04u-%02u-%02u %02u:%02u:%02u\n", tm->tm_year + 1900, + tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); + } + last_time = dive_trip->when; + } + printf("-----\n"); +} +#endif + +/* this finds a trip that starts at precisely the time given */ +static GList *find_trip(timestamp_t when) +{ + GList *trip = dive_trip_list; + while (trip && DIVE_TRIP(trip)->when < when) + trip = trip->next; + if (DIVE_TRIP(trip)->when == when) { +#ifdef DEBUG_TRIP + struct tm *tm; + tm = gmtime(&DIVE_TRIP(trip)->when); + printf("found trip @ %04d-%02d-%02d %02d:%02d:%02d\n", + tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); +#endif + return trip; + } +#ifdef DEBUG_TRIP + printf("no matching trip\n"); +#endif + return NULL; +} + +/* this finds the last trip that at or before the time given */ static GList *find_matching_trip(timestamp_t when) { GList *trip = dive_trip_list; - if (!trip || DIVE_TRIP(trip)->when > when) + if (!trip || DIVE_TRIP(trip)->when > when) { +#ifdef DEBUG_TRIP + printf("no matching trip\n"); +#endif return NULL; + } while (trip->next && DIVE_TRIP(trip->next)->when <= when) trip = trip->next; +#ifdef DEBUG_TRIP + { + struct tm *tm; + tm = gmtime(&DIVE_TRIP(trip)->when); + printf("found trip @ %04d-%02d-%02d %02d:%02d:%02d\n", + tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + } +#endif return trip; } -static struct dive *create_and_hookup_trip_from_dive(struct dive *dive) +/* insert the trip into the dive_trip_list - but ensure you don't have + * two trips for the same date; but if you have, make sure you don't + * keep the one with less information */ +void insert_trip(dive_trip_t **dive_trip_p) { - struct dive *dive_trip = alloc_dive(); + dive_trip_t *dive_trip = *dive_trip_p; + GList *trip = dive_trip_list; + while (trip && DIVE_TRIP(trip)->when < dive_trip->when) + trip = trip->next; + if (trip && DIVE_TRIP(trip)->when == dive_trip->when) { + if (! DIVE_TRIP(trip)->location) + DIVE_TRIP(trip)->location = dive_trip->location; + *dive_trip_p = DIVE_TRIP(trip); + } else { + dive_trip_list = g_list_insert_before(dive_trip_list, trip, *dive_trip_p); + } +#ifdef DEBUG_TRIP + dump_trip_list(); +#endif +} + +static inline void delete_trip(GList *trip) +{ + dive_trip_list = g_list_delete_link(dive_trip_list, trip); +#ifdef DEBUG_TRIP + dump_trip_list(); +#endif +} +static dive_trip_t *create_and_hookup_trip_from_dive(struct dive *dive) +{ + dive_trip_t *dive_trip = calloc(sizeof(dive_trip_t),1); dive_trip->when = dive->when; if (dive->location) dive_trip->location = strdup(dive->location); @@ -971,7 +1068,7 @@ static struct dive *create_and_hookup_trip_from_dive(struct dive *dive) * that starts at when and check on the way that there is no ungrouped * dive and no break beyond the 3 day threshold between dives that * haven't already been assigned to this trip */ -static gboolean dive_can_be_in_trip(int idx, struct dive *dive_trip) +static gboolean dive_can_be_in_trip(int idx, dive_trip_t *dive_trip) { struct dive *dive, *pdive; int i = idx; @@ -1012,9 +1109,9 @@ static void fill_dive_list(void) int i; GtkTreeIter iter, parent_iter, *parent_ptr = NULL; GtkTreeStore *liststore, *treestore; - struct dive *last_trip = NULL; + dive_trip_t *last_trip = NULL; GList *trip; - struct dive *dive_trip = NULL; + dive_trip_t *dive_trip = NULL; /* if we have pre-existing trips, start on the last one */ trip = g_list_last(dive_trip_list); @@ -1047,25 +1144,42 @@ static void fill_dive_list(void) dive_trip = NULL; } else if (autogroup && DIVE_NEEDS_TRIP(dive)){ /* if we already have existing trips there are up to two trips that this - * could potentially be part of. Let's try the one we are on, first */ - if (! (dive_trip && dive_can_be_in_trip(i, dive_trip))) { - /* there could be a better trip in our list already */ - trip = find_matching_trip(dive->when); - if (! (trip && dive_can_be_in_trip(i, DIVE_TRIP(trip)))) { + * could potentially be part of. + * Let's see if there is a matching one already */ + GList *matching_trip; + matching_trip = find_matching_trip(dive->when); + if (matching_trip && dive_can_be_in_trip(i, DIVE_TRIP(matching_trip))) { + trip = matching_trip; + } else { + /* is there a trip we can extend ? */ + if (! matching_trip && dive_trip) { + /* careful - this is before the first trip + yet we have a trip we're looking at; make + sure that is indeed the first trip */ + dive_trip = DIVE_TRIP(dive_trip_list); + trip = dive_trip_list; + } + /* maybe we can extend the current trip */ + if (! (dive_trip && dive_can_be_in_trip(i, dive_trip))) { /* seems like neither of these trips work, so create * a new one; all fields default to 0 and get filled * in further down */ parent_ptr = NULL; dive_trip = create_and_hookup_trip_from_dive(dive); - dive_trip->tripflag = IN_TRIP; - trip = FIND_TRIP(&dive_trip->when); + dive_trip->tripflag = AUTOGEN_TRIP; + trip = find_trip(dive_trip->when); } - if (trip) - dive_trip = DIVE_TRIP(trip); } + if (trip) + dive_trip = DIVE_TRIP(trip); } else if (DIVE_IN_TRIP(dive)) { trip = find_matching_trip(dive->when); - dive_trip = DIVE_TRIP(trip); + if (trip) + dive_trip = DIVE_TRIP(trip); + else + printf ("data seems inconsistent - dive claims to be in dive trip " + "yet there appears to be no matching trip\n" + "Trying to recover\n"); } else { /* dive is not in a trip and we aren't autogrouping */ dive_trip = NULL; @@ -1074,7 +1188,8 @@ static void fill_dive_list(void) /* update dive as part of dive_trip and * (if necessary) update dive_trip time and location */ if (dive_trip) { - dive->tripflag = IN_TRIP; + if(DIVE_NEEDS_TRIP(dive)) + dive->tripflag = ASSIGNED_TRIP; dive->divetrip = dive_trip; if (dive_trip->when > dive->when) dive_trip->when = dive->when; @@ -1123,6 +1238,9 @@ static void fill_dive_list(void) DIVE_SUIT, dive->suit, DIVE_SAC, 0, -1); +#ifdef DEBUG_TRIP + dump_trip_list(); +#endif } /* make sure we display the first date of the trip in previous summary */ @@ -1260,12 +1378,12 @@ void edit_trip_cb(GtkWidget *menuitem, GtkTreePath *path) { GtkTreeIter iter; timestamp_t when; - struct dive *dive_trip; + dive_trip_t *dive_trip; GList *trip; gtk_tree_model_get_iter(MODEL(dive_list), &iter, path); gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_DATE, &when, -1); - trip = FIND_TRIP(&when); + trip = find_trip(when); dive_trip = DIVE_TRIP(trip); if (edit_trip(dive_trip)) gtk_tree_store_set(STORE(dive_list), &iter, DIVE_LOCATION, dive_trip->location, -1); @@ -1336,7 +1454,7 @@ static int copy_tree_node(GtkTreeIter *a, GtkTreeIter *b) /* to avoid complicated special cases based on ordering or number of children, we always take the first and last child and pick the smaller timestamp_t (which works regardless of ordering and also with just one child) */ -static void update_trip_timestamp(GtkTreeIter *parent, struct dive *divetrip) +static void update_trip_timestamp(GtkTreeIter *parent, dive_trip_t *divetrip) { GtkTreeIter first_child, last_child; int nr; @@ -1366,7 +1484,8 @@ static GtkTreeIter *move_dive_between_trips(GtkTreeIter *dive_iter, GtkTreeIter { int idx; timestamp_t old_when, new_when; - struct dive *dive, *old_divetrip, *new_divetrip; + struct dive *dive; + dive_trip_t *old_divetrip, *new_divetrip; GtkTreeIter *new_iter = malloc(sizeof(GtkTreeIter)); if (before) @@ -1444,6 +1563,7 @@ static void turn_dive_into_trip(GtkTreePath *path) char *location; int idx; struct dive *dive; + dive_trip_t *dive_trip; /* this is a dive on the top level, insert trip AFTER it, populate its date / location, and * then move the dive below that trip */ @@ -1458,8 +1578,10 @@ static void turn_dive_into_trip(GtkTreePath *path) treepath = gtk_tree_model_get_path(MODEL(dive_list), newiter); gtk_tree_view_expand_to_path(GTK_TREE_VIEW(dive_list.tree_view), treepath); dive = get_dive(idx); - /* we don't need the return value - everything is hooked up in the function */ - (void)create_and_hookup_trip_from_dive(dive); + /* this trip is intentionally created so it should be treated as if + * it was read from a file */ + dive_trip = create_and_hookup_trip_from_dive(dive); + dive_trip->when_from_file = dive_trip->when; } /* we know that path is pointing at a dive in a trip and are asked to split this trip into two */ @@ -1467,7 +1589,8 @@ static void insert_trip_before(GtkTreePath *path) { GtkTreeIter iter, prev_iter, parent, newparent, nextsibling; GtkTreePath *treepath, *prev_path; - struct dive *dive, *prev_dive, *new_divetrip; + struct dive *dive, *prev_dive; + dive_trip_t *new_divetrip; int idx, nr, i; gtk_tree_model_get_iter(MODEL(dive_list), &iter, path); @@ -1506,6 +1629,8 @@ static void insert_trip_before(GtkTreePath *path) /* we copied the dive we were called with; we are done */ break; } + /* treat this divetrip as if it had been read from a file */ + new_divetrip->when_from_file = new_divetrip->when; treepath = gtk_tree_model_get_path(MODEL(dive_list), &newparent); gtk_tree_view_expand_to_path(GTK_TREE_VIEW(dive_list.tree_view), treepath); #ifdef DEBUG_TRIP @@ -1564,7 +1689,7 @@ static void remove_from_trip(GtkTreePath *path) /* if this was the last dive on the trip, remove the trip */ if (! gtk_tree_model_iter_has_child(MODEL(dive_list), &parent)) { gtk_tree_store_remove(STORE(dive_list), &parent); - delete_trip(FIND_TRIP(&dive->divetrip->when)); + delete_trip(find_trip(dive->divetrip->when)); free(dive->divetrip); } /* mark the dive as intentionally at the top level */ @@ -1639,7 +1764,8 @@ static void remove_from_trip_cb(GtkWidget *menuitem, GtkTreePath *path) void remove_trip(GtkTreePath *trippath, gboolean force_no_trip) { GtkTreeIter newiter, parent, child, *lastiter = &parent; - struct dive *dive, *dive_trip = NULL; + struct dive *dive; + dive_trip_t *dive_trip = NULL; int idx; GtkTreePath *childpath; GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view)); @@ -1672,7 +1798,7 @@ void remove_trip(GtkTreePath *trippath, gboolean force_no_trip) } /* finally, remove the trip */ gtk_tree_store_remove(STORE(dive_list), &parent); - delete_trip(FIND_TRIP(&dive_trip->when)); + delete_trip(find_trip(dive_trip->when)); free(dive_trip); #ifdef DEBUG_TRIP dump_trip_list(); @@ -2097,12 +2223,26 @@ void remove_autogen_trips() while(gtk_tree_model_get_iter(TREEMODEL(dive_list), &iter, path)) { gtk_tree_model_get(TREEMODEL(dive_list), &iter, DIVE_INDEX, &idx, DIVE_DATE, &when, -1); if (idx < 0) { - trip = FIND_TRIP(&when); - if (DIVE_TRIP(trip)->tripflag == IN_TRIP) { /* this was autogen */ + trip = find_trip(when); + if (trip && DIVE_TRIP(trip)->tripflag == AUTOGEN_TRIP) { /* this was autogen */ remove_trip(path, FALSE); continue; } } gtk_tree_path_next(path); } + /* now walk the remaining trips in the dive_trip_list and restore + * their original time stamp; we don't do this in the loop above + * to ensure that the list stays in chronological order */ + trip = NULL; + while(NEXT_TRIP(trip)) { + trip = NEXT_TRIP(trip); + DIVE_TRIP(trip)->when = DIVE_TRIP(trip)->when_from_file; + } + /* finally walk the dives and remove the 'ASSIGNED_TRIP' designator */ + for (idx = 0; idx < dive_table.nr; idx++) { + struct dive *dive = get_dive(idx); + if (dive->tripflag == ASSIGNED_TRIP) + dive->tripflag = TF_NONE; + } } @@ -445,7 +445,7 @@ static void save_dive_info_changes(struct dive *dive, struct dive *master, struc } } -static void dive_trip_widget(GtkWidget *box, struct dive *trip, struct dive_info *info) +static void dive_trip_widget(GtkWidget *box, dive_trip_t *trip, struct dive_info *info) { GtkWidget *hbox, *label; char buffer[80] = "Edit trip summary"; @@ -537,7 +537,7 @@ void update_equipment_data(struct dive *dive, struct dive *master) memcpy(dive->weightsystem, master->weightsystem, WS_BYTES); } -gboolean edit_trip(struct dive *trip) +gboolean edit_trip(dive_trip_t *trip) { GtkWidget *dialog, *vbox; int success; @@ -571,10 +571,8 @@ gboolean edit_trip(struct dive *trip) if (old_text) g_free(old_text); } - if (changed) { + if (changed) mark_divelist_changed(TRUE); - flush_divelist(trip); - } } gtk_widget_destroy(dialog); return changed; diff --git a/parse-xml.c b/parse-xml.c index f83deb705..da150d27e 100644 --- a/parse-xml.c +++ b/parse-xml.c @@ -156,7 +156,8 @@ const struct units IMPERIAL_units = { /* * Dive info as it is being built up.. */ -static struct dive *cur_dive, *cur_trip = NULL; +static struct dive *cur_dive; +static dive_trip_t *cur_trip = NULL; static struct sample *cur_sample; static struct { int active; @@ -512,8 +513,10 @@ static void get_tripflag(char *buffer, void *_tf) *tf = TF_NONE; for (i = NO_TRIP; i < NUM_TRIPFLAGS; i++) - if(! strcmp(buffer, tripflag_names[i])) + if(! strcmp(buffer, tripflag_names[i])) { *tf = i; + break; + } } static void centibar(char *buffer, void *_pressure) @@ -1122,21 +1125,23 @@ static void try_to_fill_dive(struct dive **divep, const char *name, char *buf) } /* We're in the top-level trip xml. Try to convert whatever value to a trip value */ -static void try_to_fill_trip(struct dive **divep, const char *name, char *buf) +static void try_to_fill_trip(dive_trip_t **dive_trip_p, const char *name, char *buf) { int len = strlen(name); start_match("trip", name, buf); - struct dive *dive = *divep; + dive_trip_t *dive_trip = *dive_trip_p; - if (MATCH(".date", divedate, &dive->when)) + if (MATCH(".date", divedate, &dive_trip->when)) return; - if (MATCH(".time", divetime, &dive->when)) + if (MATCH(".time", divetime, &dive_trip->when)) { + dive_trip->when_from_file = dive_trip->when; return; - if (MATCH(".location", utf8_string, &dive->location)) + } + if (MATCH(".location", utf8_string, &dive_trip->location)) return; - if (MATCH(".notes", utf8_string, &dive->notes)) + if (MATCH(".notes", utf8_string, &dive_trip->notes)) return; nonmatch("trip", name, buf); @@ -1182,7 +1187,7 @@ static void trip_start(void) { if (cur_trip) return; - cur_trip = alloc_dive(); + cur_trip = calloc(sizeof(dive_trip_t),1); memset(&cur_tm, 0, sizeof(cur_tm)); } |