From ca16f438ac74ae1c35824353d710e47aea6893c5 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Wed, 29 Aug 2012 15:43:00 -0700 Subject: Store time_t as long value The tree_storage only provided enough space for an int for DIVE_DATE. But at least on 64bit Linux, an int is 32bit yet a time_t is 64bit. Until 2038 this only causes issues in some odd situations, after 2038 this would be an obvious bug. Signed-off-by: Dirk Hohndel --- divelist.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/divelist.c b/divelist.c index 1e1d1c921..4ac50444f 100644 --- a/divelist.c +++ b/divelist.c @@ -1293,7 +1293,7 @@ GtkWidget *dive_list_create(void) dive_list.listmodel = gtk_tree_store_new(DIVELIST_COLUMNS, G_TYPE_INT, /* index */ G_TYPE_INT, /* nr */ - G_TYPE_INT, /* Date */ + G_TYPE_LONG, /* Date */ G_TYPE_INT, /* Star rating */ G_TYPE_INT, /* Depth */ G_TYPE_INT, /* Duration */ @@ -1309,7 +1309,7 @@ GtkWidget *dive_list_create(void) dive_list.treemodel = gtk_tree_store_new(DIVELIST_COLUMNS, G_TYPE_INT, /* index */ G_TYPE_INT, /* nr */ - G_TYPE_INT, /* Date */ + G_TYPE_LONG, /* Date */ G_TYPE_INT, /* Star rating */ G_TYPE_INT, /* Depth */ G_TYPE_INT, /* Duration */ -- cgit v1.2.3-70-g09d2 From a5f894d1d3b53a3a99580d2da467a46d04c65266 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Wed, 29 Aug 2012 17:24:15 -0700 Subject: Clean up macros and auxiliary functions In preparation for the next stage of the trips handling this commit makes the macros used to access trips (and some frequently used variables for the tree and list models) more consistent. This also changes the way we display un-grouped dives in the dive list, i.e. dives that are not part of a dive trip. Their dive number is now printed bold. Signed-off-by: Dirk Hohndel --- dive.h | 40 +++++++++++++++++++++++++-------------- divelist.c | 63 ++++++++++++++++++++++++++++++++++++++++--------------------- parse-xml.c | 8 ++++---- save-xml.c | 4 +++- 4 files changed, 75 insertions(+), 40 deletions(-) diff --git a/dive.h b/dive.h index dffe75325..e15fd7763 100644 --- a/dive.h +++ b/dive.h @@ -270,49 +270,61 @@ extern gboolean autogroup; #define UNGROUPED_DIVE(_dive) ((_dive)->tripflag == NO_TRIP) #define DIVE_IN_TRIP(_dive) ((_dive)->tripflag == IN_TRIP) -#define NEXT_TRIP(_entry, _list) ((_entry) ? g_list_next(_entry) : (_list)) -#define PREV_TRIP(_entry, _list) ((_entry) ? g_list_previous(_entry) : g_list_last(_list)) +#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_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; + return ((struct dive *)_a)->when - ((struct dive *)_b)->when; } -#define FIND_TRIP(_trip, _list) g_list_find_custom((_list), (_trip), dive_date_cmp) +/* returns 0 if the dive happened exactly at time */ +static inline int dive_when_find(gconstpointer _dive, gconstpointer _time) { + return ((struct dive *)_dive)->when != (time_t) _time; +} + +#define FIND_TRIP(_when) g_list_find_custom(dive_trip_list, (gconstpointer)(_when), dive_when_find) #ifdef DEBUG_TRIP static void dump_trip_list(void) { GList *p = NULL; int i=0; - while ((p = NEXT_TRIP(p, dive_trip_list))) { + while ((p = NEXT_TRIP(p))) { struct tm *tm = gmtime(&DIVE_TRIP(p)->when); - printf("trip %d to \"%s\" on %04u-%02u-%02u\n", ++i, DIVE_TRIP(p)->location, - tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday); + 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 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 inline GList *insert_trip(struct dive *_trip, GList *_list) +/* 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 inline void insert_trip(struct dive *_trip) { - GList *result = FIND_TRIP(_trip, _list); + GList *result = FIND_TRIP(_trip->when); if (result) { if (! DIVE_TRIP(result)->location) DIVE_TRIP(result)->location = _trip->location; } else { - result = g_list_insert_sorted((_list), (_trip), dive_date_cmp); + dive_trip_list = g_list_insert_sorted(dive_trip_list, (_trip), dive_date_cmp); } #ifdef DEBUG_TRIP dump_trip_list(); #endif - return result; } +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 diff --git a/divelist.c b/divelist.c index 4ac50444f..49166c8b5 100644 --- a/divelist.c +++ b/divelist.c @@ -31,6 +31,11 @@ struct DiveList { }; static struct DiveList dive_list; +#define TREEMODEL(_dl) GTK_TREE_MODEL((_dl).treemodel) +#define TREESTORE(_dl) GTK_TREE_STORE((_dl).treemodel) +#define LISTMODEL(_dl) GTK_TREE_MODEL((_dl).listmodel) +#define LISTSTORE(_dl) GTK_TREE_STORE((_dl).listmodel) + GList *dive_trip_list; gboolean autogroup = FALSE; @@ -65,9 +70,17 @@ static gboolean dump_model_entry(GtkTreeModel *model, GtkTreePath *path, char *location; int idx, nr, duration; struct dive *dive; + time_t when; + struct tm *tm; - gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_NR, &nr, DIVE_DURATION, &duration, DIVE_LOCATION, &location, -1); - printf("entry #%d : nr %d duration %d location %s ", idx, nr, duration, location); + gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_NR, &nr, DIVE_DATE, &when, + DIVE_DURATION, &duration, DIVE_LOCATION, &location, -1); + tm = gmtime(&when); + printf("iter %x:%x entry #%d : nr %d @ %04d-%02d-%02d %02d:%02d:%02d duration %d location %s ", + iter->stamp, iter->user_data, idx, nr, + tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec, + duration, location); dive = get_dive(idx); if (dive) printf("tripflag %d\n", dive->tripflag); @@ -82,6 +95,7 @@ static gboolean dump_model_entry(GtkTreeModel *model, GtkTreePath *path, static void dump_model(GtkListStore *store) { gtk_tree_model_foreach(GTK_TREE_MODEL(store), dump_model_entry, NULL); + printf("\n---\n\n"); } #endif @@ -125,7 +139,7 @@ static void first_leaf(GtkTreeModel *model, GtkTreeIter *iter, int *diveidx) void row_expanded_cb(GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer data) { GtkTreeIter child; - GtkTreeModel *model = GTK_TREE_MODEL(dive_list.model); + GtkTreeModel *model = TREEMODEL(dive_list); GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view)); if (!gtk_tree_model_iter_children(model, &child, iter)) @@ -169,7 +183,7 @@ static int selected_children(GtkTreeModel *model, GtkTreeIter *iter) shows up as selected too */ void row_collapsed_cb(GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer data) { - GtkTreeModel *model = GTK_TREE_MODEL(dive_list.model); + GtkTreeModel *model = TREEMODEL(dive_list); GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view)); if (selected_children(model, iter)) @@ -253,7 +267,7 @@ static void select_dive_group(GtkTreeModel *model, GtkTreeSelection *selection, */ static void check_selection_cb(GtkTreeIter *iter, GtkTreeSelection *selection) { - GtkTreeModel *model = GTK_TREE_MODEL(dive_list.model); + GtkTreeModel *model = TREEMODEL(dive_list); struct dive *dive; int idx, gtk_selected; @@ -449,13 +463,20 @@ static void nr_data_func(GtkTreeViewColumn *col, { int idx, nr; char buffer[40]; + struct dive *dive; gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_NR, &nr, -1); - if (idx < 0) + if (idx < 0) { *buffer = '\0'; - else - snprintf(buffer, sizeof(buffer), "%d", nr); - g_object_set(renderer, "text", buffer, NULL); + } else { + /* make dives that are not in trips stand out */ + dive = get_dive(idx); + if (!DIVE_IN_TRIP(dive)) + snprintf(buffer, sizeof(buffer), "%d", nr); + else + snprintf(buffer, sizeof(buffer), "%d", nr); + } + g_object_set(renderer, "markup", buffer, NULL); } /* @@ -808,7 +829,7 @@ static void fill_one_dive(struct dive *dive, free(cylinder); free(suit); - if (model == GTK_TREE_MODEL(dive_list.treemodel)) + if (model == TREEMODEL(dive_list)) othermodel = dive_list.listmodel; else othermodel = dive_list.treemodel; @@ -841,7 +862,7 @@ static gboolean set_one_dive(GtkTreeModel *model, void flush_divelist(struct dive *dive) { - GtkTreeModel *model = GTK_TREE_MODEL(dive_list.model); + GtkTreeModel *model = TREEMODEL(dive_list); gtk_tree_model_foreach(model, set_one_dive, dive); } @@ -856,7 +877,7 @@ void set_divelist_font(const char *font) void update_dive_list_units(void) { const char *unit; - GtkTreeModel *model = GTK_TREE_MODEL(dive_list.model); + GtkTreeModel *model = TREEMODEL(dive_list); (void) get_depth_units(0, NULL, &unit); gtk_tree_view_column_set_title(dive_list.depth, unit); @@ -894,8 +915,8 @@ static void fill_dive_list(void) /* if we have pre-existing trips, start on the last one */ trip = g_list_last(dive_trip_list); - treestore = GTK_TREE_STORE(dive_list.treemodel); - liststore = GTK_TREE_STORE(dive_list.listmodel); + treestore = TREESTORE(dive_list); + liststore = LISTSTORE(dive_list); i = dive_table.nr; while (--i >= 0) { @@ -925,21 +946,21 @@ static void fill_dive_list(void) /* allocate new trip - all fields default to 0 and get filled in further down */ dive_trip = alloc_dive(); - dive_trip_list = insert_trip(dive_trip, dive_trip_list); - trip = FIND_TRIP(dive_trip, dive_trip_list); + insert_trip(dive_trip); + trip = FIND_TRIP(dive_trip->when); } } else { /* either the dive has a trip or we aren't creating trips */ if (! (trip && DIVE_FITS_TRIP(dive, DIVE_TRIP(trip)))) { GList *last_trip = trip; - trip = PREV_TRIP(trip, dive_trip_list); + trip = PREV_TRIP(trip); if (! (trip && DIVE_FITS_TRIP(dive, DIVE_TRIP(trip)))) { /* we could get here if there are no trips in the XML file * and we aren't creating trips, either. * Otherwise we need to create a new trip */ if (autogroup) { dive_trip = alloc_dive(); - dive_trip_list = insert_trip(dive_trip, dive_trip_list); - trip = FIND_TRIP(dive_trip, dive_trip_list); + insert_trip(dive_trip); + trip = FIND_TRIP(dive_trip->when); } else { /* let's go back to the last valid trip */ trip = last_trip; @@ -1020,8 +1041,8 @@ static void fill_dive_list(void) void dive_list_update_dives(void) { - gtk_tree_store_clear(GTK_TREE_STORE(dive_list.treemodel)); - gtk_tree_store_clear(GTK_TREE_STORE(dive_list.listmodel)); + gtk_tree_store_clear(TREESTORE(dive_list)); + gtk_tree_store_clear(LISTSTORE(dive_list)); fill_dive_list(); repaint_dive(); } diff --git a/parse-xml.c b/parse-xml.c index 5159a334f..1569c8c5c 100644 --- a/parse-xml.c +++ b/parse-xml.c @@ -41,7 +41,7 @@ void record_dive(struct dive *dive) void record_trip(struct dive *trip) { - dive_trip_list = insert_trip(trip, dive_trip_list); + insert_trip(trip); } static void delete_dive_renumber(struct dive **dives, int i, int nr) @@ -1165,10 +1165,10 @@ static void try_to_fill_trip(struct dive **divep, const char *name, char *buf) struct dive *dive = *divep; - if (MATCH(".date", divedate, &dive->when)) { - dive->when = utc_mktime(&cur_tm); + if (MATCH(".date", divedate, &dive->when)) + return; + if (MATCH(".time", divetime, &dive->when)) return; - } if (MATCH(".location", utf8_string, &dive->location)) return; if (MATCH(".notes", utf8_string, &dive->notes)) diff --git a/save-xml.c b/save-xml.c index b797475e5..3bea2adfa 100644 --- a/save-xml.c +++ b/save-xml.c @@ -291,6 +291,8 @@ static void save_trip(FILE *f, struct dive *trip) fprintf(f, "tm_year+1900, tm->tm_mon+1, tm->tm_mday); + fprintf(f, " time='%02u:%02u:%02u'", + tm->tm_hour, tm->tm_min, tm->tm_sec); if (trip->location) show_utf8(f, trip->location, " location=\'","\'", 1); fprintf(f, " />\n"); @@ -341,7 +343,7 @@ void save_dives(const char *filename) fprintf(f, "\n\n", VERSION); /* save the trips */ - while ((trip = NEXT_TRIP(trip, dive_trip_list)) != 0) + while ((trip = NEXT_TRIP(trip)) != NULL) save_trip(f, trip->data); /* save the dives */ -- cgit v1.2.3-70-g09d2 From c3debc10fdcb0f7e939872ea24d525f41039f5bd Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Fri, 31 Aug 2012 16:26:04 -0700 Subject: Allow modification and edits of trips Now that we can load and store trips we needed to add the capability to manipulate those trips as well. This commit allows us remove a dive from a trip via a right click operation on the dive list. The commit also adds code to split a trip into two, to merge two trips and to create a new trip out of a top level dive. To make all that useful this commit changes the right-click on the dive list to identify and act on the record we are actually on (instead of acting on the selection). The right-click menu ("context menu") changes depending which divelist entry the mouse pointer is on - so different operations are offered, depending on where you are. We also add simplistic editing of location and notes for a trip (but the notes are never displayed so far). To make our lives easier this commit adds a link from the dive to the dive trip it is part of. This allowed to hugely simplify the auto trip generation algorithm (among other things). The downside of this change is that there are now three different ways in which we express the relationship of dives and trips: in the dive_trip_list, in the tree_model, and with these pointers. Somehow this screams that I should rethink my data structures... Signed-off-by: Dirk Hohndel --- dive.h | 2 + divelist.c | 444 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- info.c | 62 ++++++++- 3 files changed, 474 insertions(+), 34 deletions(-) diff --git a/dive.h b/dive.h index e15fd7763..384c7e4ca 100644 --- a/dive.h +++ b/dive.h @@ -241,6 +241,7 @@ extern const char *tripflag_names[NUM_TRIPFLAGS]; struct dive { int number; tripflag_t tripflag; + struct dive *divetrip; int selected; time_t when; char *location; @@ -433,6 +434,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 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 49166c8b5..4e0f940bb 100644 --- a/divelist.c +++ b/divelist.c @@ -903,6 +903,28 @@ void update_dive_list_col_visibility(void) return; } +static GList *find_matching_trip(time_t when) +{ + GList *trip = dive_trip_list; + if (!trip || DIVE_TRIP(trip)->when > when) + return NULL; + while (trip->next && DIVE_TRIP(trip->next)->when <= when) + trip = trip->next; + return trip; +} + +static struct dive *create_and_hookup_trip_from_dive(struct dive *dive) +{ + struct dive *dive_trip = alloc_dive(); + dive_trip->when = dive->when; + if (dive->location) + dive_trip->location = strdup(dive->location); + insert_trip(dive_trip); + dive->divetrip = dive_trip; + dive->tripflag = IN_TRIP; + return dive_trip; +} + static void fill_dive_list(void) { int i; @@ -945,35 +967,20 @@ static void fill_dive_list(void) if ( ! dive_trip || ! DIVE_FITS_TRIP(dive, dive_trip)) { /* allocate new trip - all fields default to 0 and get filled in further down */ - dive_trip = alloc_dive(); - insert_trip(dive_trip); + dive_trip = create_and_hookup_trip_from_dive(dive); trip = FIND_TRIP(dive_trip->when); } - } else { /* either the dive has a trip or we aren't creating trips */ - if (! (trip && DIVE_FITS_TRIP(dive, DIVE_TRIP(trip)))) { - GList *last_trip = trip; - trip = PREV_TRIP(trip); - if (! (trip && DIVE_FITS_TRIP(dive, DIVE_TRIP(trip)))) { - /* we could get here if there are no trips in the XML file - * and we aren't creating trips, either. - * Otherwise we need to create a new trip */ - if (autogroup) { - dive_trip = alloc_dive(); - insert_trip(dive_trip); - trip = FIND_TRIP(dive_trip->when); - } else { - /* let's go back to the last valid trip */ - trip = last_trip; - } - } else { - dive_trip = trip->data; - } - } + } else if (DIVE_IN_TRIP(dive)) { + trip = find_matching_trip(dive->when); + dive_trip = DIVE_TRIP(trip); } - /* update dive_trip time and (if necessary) location */ + /* update dive as part of dive_trip and + * (if necessary) update dive_trip time and location */ if (dive_trip) { dive->tripflag = IN_TRIP; - dive_trip->when = dive->when; + dive->divetrip = dive_trip; + if (dive_trip->when > dive->when) + dive_trip->when = dive->when; if (!dive_trip->location && dive->location) dive_trip->location = dive->location; if (dive_trip != last_trip) { @@ -1152,11 +1159,39 @@ void add_dive_cb(GtkWidget *menuitem, gpointer data) free(dive); } -void edit_dive_cb(GtkWidget *menuitem, gpointer data) +void edit_trip_cb(GtkWidget *menuitem, GtkTreePath *path) +{ + GtkTreeIter iter; + time_t when; + struct dive *dive_trip; + GList *trip; + + gtk_tree_model_get_iter(TREEMODEL(dive_list), &iter, path); + gtk_tree_model_get(TREEMODEL(dive_list), &iter, DIVE_DATE, &when, -1); + trip = FIND_TRIP(when); + dive_trip = DIVE_TRIP(trip); + if (edit_trip(dive_trip)) + gtk_tree_store_set(TREESTORE(dive_list), &iter, DIVE_LOCATION, dive_trip->location, -1); +} + +void edit_selected_dives_cb(GtkWidget *menuitem, gpointer data) { edit_multi_dive_info(NULL); } +void edit_dive_from_path_cb(GtkWidget *menuitem, GtkTreePath *path) +{ + GtkTreeIter iter; + int idx; + struct dive *dive; + + gtk_tree_model_get_iter(TREEMODEL(dive_list), &iter, path); + gtk_tree_model_get(TREEMODEL(dive_list), &iter, DIVE_INDEX, &idx, -1); + dive = get_dive(idx); + + edit_multi_dive_info(dive); +} + static void expand_all_cb(GtkWidget *menuitem, GtkTreeView *tree_view) { gtk_tree_view_expand_all(tree_view); @@ -1167,10 +1202,309 @@ static void collapse_all_cb(GtkWidget *menuitem, GtkTreeView *tree_view) gtk_tree_view_collapse_all(tree_view); } -static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int button) +/* copy the node and return the index */ +static int copy_tree_node(GtkTreeIter *a, GtkTreeIter *b) +{ + struct dive store_dive; + int totalweight, idx; + char *cylinder_text; + + gtk_tree_model_get(TREEMODEL(dive_list), a, + DIVE_INDEX, &idx, + DIVE_NR, &store_dive.number, + DIVE_DATE, &store_dive.when, + DIVE_RATING, &store_dive.rating, + DIVE_DEPTH, &store_dive.maxdepth, + DIVE_DURATION, &store_dive.duration, + DIVE_TEMPERATURE, &store_dive.duration, + DIVE_TOTALWEIGHT, &totalweight, + DIVE_SUIT, &store_dive.suit, + DIVE_CYLINDER, &cylinder_text, + DIVE_SAC, &store_dive.sac, + DIVE_OTU, &store_dive.otu, + DIVE_LOCATION, &store_dive.location, + -1); + gtk_tree_store_set(TREESTORE(dive_list), b, + DIVE_INDEX, idx, + DIVE_NR, store_dive.number, + DIVE_DATE, store_dive.when, + DIVE_RATING, store_dive.rating, + DIVE_DEPTH, store_dive.maxdepth, + DIVE_DURATION, store_dive.duration, + DIVE_TEMPERATURE, store_dive.duration, + DIVE_TOTALWEIGHT, totalweight, + DIVE_SUIT, store_dive.suit, + DIVE_CYLINDER, cylinder_text, + DIVE_SAC, store_dive.sac, + DIVE_OTU, store_dive.otu, + DIVE_LOCATION, store_dive.location, + -1); + return idx; +} + +/* to avoid complicated special cases based on ordering or number of children, + we always take the first and last child and pick the smaller time_t (which + works regardless of ordering and also with just one child) */ +static void update_trip_timestamp(GtkTreeIter *parent, struct dive *divetrip) +{ + GtkTreeIter first_child, last_child; + int nr; + time_t t1, t2, tnew; + + if (gtk_tree_store_iter_depth(TREESTORE(dive_list), parent) != 0) + return; + nr = gtk_tree_model_iter_n_children(TREEMODEL(dive_list), parent); + gtk_tree_model_iter_nth_child(TREEMODEL(dive_list), &first_child, parent, 0); + gtk_tree_model_get(TREEMODEL(dive_list), &first_child, DIVE_DATE, &t1, -1); + gtk_tree_model_iter_nth_child(TREEMODEL(dive_list), &last_child, parent, nr - 1); + gtk_tree_model_get(TREEMODEL(dive_list), &last_child, DIVE_DATE, &t2, -1); + tnew = MIN(t1, t2); + gtk_tree_store_set(TREESTORE(dive_list), parent, DIVE_DATE, tnew, -1); + if (divetrip) + divetrip->when = tnew; +} + +/* move dive_iter, which is a child of old_trip (could be NULL) to new_trip (could be NULL); + * either of the trips being NULL means that this was (or will be) a dive without a trip; + * update the dive trips (especially the starting times) accordingly + * maintain the selected status of the dive + * IMPORTANT - the move needs to keep the tree consistant - so no out of order moving... */ +static GtkTreeIter *move_dive_between_trips(GtkTreeIter *dive_iter, GtkTreeIter *old_trip, GtkTreeIter *new_trip, + GtkTreeIter *sibling, gboolean before) +{ + int idx; + time_t old_when, new_when; + struct dive *dive, *old_divetrip, *new_divetrip; + GtkTreeIter *new_iter = malloc(sizeof(GtkTreeIter)); + + if (before) + gtk_tree_store_insert_before(GTK_TREE_STORE(TREEMODEL(dive_list)), new_iter, new_trip, sibling); + else + gtk_tree_store_insert_after(GTK_TREE_STORE(TREEMODEL(dive_list)), new_iter, new_trip, sibling); + idx = copy_tree_node(dive_iter, new_iter); + gtk_tree_model_get(TREEMODEL(dive_list), new_iter, DIVE_INDEX, &idx, -1); + dive = get_dive(idx); + gtk_tree_store_remove(GTK_TREE_STORE(TREEMODEL(dive_list)), dive_iter); + if (old_trip) { + gtk_tree_model_get(TREEMODEL(dive_list), old_trip, DIVE_DATE, &old_when, -1); + old_divetrip = DIVE_TRIP(find_matching_trip(old_when)); + update_trip_timestamp(old_trip, old_divetrip); + } + if (new_trip) { + gtk_tree_model_get(TREEMODEL(dive_list), new_trip, DIVE_DATE, &new_when, -1); + new_divetrip = dive->divetrip; + update_trip_timestamp(new_trip, new_divetrip); + } + if (dive->selected) { + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view)); + gtk_tree_selection_select_iter(selection, new_iter); + } + return new_iter; +} + +static void turn_dive_into_trip(GtkTreePath *path) +{ + GtkTreeIter iter, *newiter, newparent; + GtkTreePath *treepath; + time_t when; + char *location; + int idx; + struct dive *dive; + + /* this is a dive on the top level, insert trip AFTER it, populate its date / location, and + * then move the dive below that trip */ + gtk_tree_model_get_iter(TREEMODEL(dive_list), &iter, path); + gtk_tree_store_insert_after(TREESTORE(dive_list), &newparent, NULL, &iter); + gtk_tree_model_get(TREEMODEL(dive_list), &iter, + DIVE_INDEX, &idx, DIVE_DATE, &when, DIVE_LOCATION, &location, -1); + gtk_tree_store_set(TREESTORE(dive_list), &newparent, + DIVE_INDEX, -1, DIVE_DATE, when, DIVE_LOCATION, location, -1); + free(location); + newiter = move_dive_between_trips(&iter, NULL, &newparent, NULL, FALSE); + treepath = gtk_tree_model_get_path(TREEMODEL(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); +} + +/* we know that path is pointing at a dive in a trip and are asked to split this trip into two */ +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; + int idx, nr, i; + + gtk_tree_model_get_iter(TREEMODEL(dive_list), &iter, path); + prev_path = gtk_tree_path_copy(path); + if (!gtk_tree_path_prev(prev_path) || + !gtk_tree_model_iter_parent(TREEMODEL(dive_list), &parent, &iter)) + return; + gtk_tree_model_get_iter(TREEMODEL(dive_list), &prev_iter, prev_path); + gtk_tree_model_get(TREEMODEL(dive_list), &prev_iter, DIVE_INDEX, &idx, -1); + prev_dive = get_dive(idx); + gtk_tree_store_insert_after(TREESTORE(dive_list), &newparent, NULL, &parent); + copy_tree_node(&parent, &newparent); + gtk_tree_model_get(TREEMODEL(dive_list), &iter, DIVE_INDEX, &idx, -1); + dive = get_dive(idx); + /* make sure that the time_t of the previous divetrip is correct before + * inserting a new one */ + if (dive->when < prev_dive->when) + if (prev_dive->divetrip && prev_dive->divetrip->when < prev_dive->when) + prev_dive->divetrip->when = prev_dive->when; + new_divetrip = create_and_hookup_trip_from_dive(dive); + + /* in order for the data structures to stay consistent we need to walk from + * the last child backwards to this one. The easiest way seems to be to do + * this with the nth iterator API */ + nr = gtk_tree_model_iter_n_children(TREEMODEL(dive_list), &parent); + for (i = nr - 1; i >= 0; i--) { + gtk_tree_model_iter_nth_child(TREEMODEL(dive_list), &nextsibling, &parent, i); + treepath = gtk_tree_model_get_path(TREEMODEL(dive_list), &nextsibling); + gtk_tree_model_get(TREEMODEL(dive_list), &nextsibling, DIVE_INDEX, &idx, -1); + dive = get_dive(idx); + dive->divetrip = new_divetrip; + if (dive->when < dive->divetrip->when) + dive->divetrip->when = dive->when; + (void) move_dive_between_trips(&nextsibling, &parent, &newparent, NULL, FALSE); + if (gtk_tree_path_compare(path, treepath) == 0) + /* we copied the dive we were called with; we are done */ + break; + } + treepath = gtk_tree_model_get_path(TREEMODEL(dive_list), &newparent); + gtk_tree_view_expand_to_path(GTK_TREE_VIEW(dive_list.tree_view), treepath); +#ifdef DEBUG_TRIP + dump_trip_list(); +#endif +} + +static void insert_trip_before_cb(GtkWidget *menuitem, GtkTreePath *path) +{ + /* is this splitting a trip or turning a dive into a trip? */ + if (gtk_tree_path_get_depth(path) == 2) + insert_trip_before(path); + else + turn_dive_into_trip(path); +} + +static void remove_from_trip_cb(GtkWidget *menuitem, GtkTreePath *path) +{ + GtkTreeIter iter, newiter, parent; + GtkTreePath *nextpath; + struct dive *dive; + int idx; + + gtk_tree_model_get_iter(TREEMODEL(dive_list), &iter, path); + if (!gtk_tree_model_iter_parent(TREEMODEL(dive_list), &parent, &iter)) + return; + + /* if this isn't the last dive in a trip we simply split the trip + in two right after this dive */ + nextpath = gtk_tree_path_copy(path); + gtk_tree_path_next(nextpath); + if (gtk_tree_model_get_iter(TREEMODEL(dive_list), &newiter, nextpath)) + insert_trip_before(nextpath); + /* now create a new node as sibling right after the current parent */ + gtk_tree_store_insert_after(TREESTORE(dive_list), &newiter, NULL, &parent); + copy_tree_node(&iter, &newiter); + + gtk_tree_model_get(TREEMODEL(dive_list), &iter, DIVE_INDEX, &idx, -1); + dive = get_dive(idx); + if (dive->selected) { + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view)); + gtk_tree_selection_select_iter(selection, &newiter); + } + gtk_tree_store_remove(TREESTORE(dive_list), &iter); + /* if this was the last dive on the trip, remove the trip */ + if (! gtk_tree_model_iter_has_child(TREEMODEL(dive_list), &parent)) { + gtk_tree_store_remove(TREESTORE(dive_list), &parent); + delete_trip(FIND_TRIP(dive->divetrip->when)); + } + dive->tripflag = NO_TRIP; + dive->divetrip = NULL; +} + +void remove_trip_cb(GtkWidget *menuitem, GtkTreePath *trippath) +{ + GtkTreeIter newiter, parent, child, *lastiter = &parent; + struct dive *dive, *dive_trip = NULL; + int idx; + GtkTreePath *childpath; + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view)); + + /* what a pain - we can't just move the nodes, we have to + * create new ones and delete the existing ones instead */ + gtk_tree_model_get_iter(TREEMODEL(dive_list), &parent, trippath); + childpath = gtk_tree_path_copy(trippath); + gtk_tree_path_down(childpath); + for (;;) { + if( ! gtk_tree_model_get_iter(TREEMODEL(dive_list), &child, childpath)) + break; + gtk_tree_store_insert_after(TREESTORE(dive_list), &newiter, NULL, lastiter); + copy_tree_node(&child, &newiter); + /* we need to track what was selected */ + gtk_tree_model_get(TREEMODEL(dive_list), &child, DIVE_INDEX, &idx, -1); + dive = get_dive(idx); + if (dive->selected) + gtk_tree_selection_select_iter(selection, &newiter); + dive->tripflag = NO_TRIP; + if (!dive_trip) + dive_trip = dive->divetrip; + dive->divetrip = NULL; + /* this removes the child - now childpath points to the next child */ + gtk_tree_store_remove(TREESTORE(dive_list), &child); + lastiter = &newiter; + } + /* finally, remove the trip */ + gtk_tree_store_remove(TREESTORE(dive_list), &parent); + delete_trip(FIND_TRIP(dive_trip->when)); + free(dive_trip); +} + +void merge_trips_cb(GtkWidget *menuitem, GtkTreePath *trippath) +{ + GtkTreePath *prevpath; + GtkTreeIter thistripiter, prevtripiter, newiter, iter; + GtkTreeModel *tm = TREEMODEL(dive_list); + GList *trip, *prevtrip; + time_t when; + + /* this only gets called when we are on a trip and there is another trip right before */ + prevpath = gtk_tree_path_copy(trippath); + gtk_tree_path_prev(prevpath); + gtk_tree_model_get_iter(tm, &thistripiter, trippath); + gtk_tree_model_get(tm, &thistripiter, DIVE_DATE, &when, -1); + trip = find_matching_trip(when); + gtk_tree_model_get_iter(tm, &prevtripiter, prevpath); + gtk_tree_model_get(tm, &prevtripiter, DIVE_DATE, &when, -1); + prevtrip = find_matching_trip(when); + while (gtk_tree_model_iter_children(tm, &iter, &thistripiter)) { + int idx; + gtk_tree_store_insert_before(TREESTORE(dive_list), &newiter, &prevtripiter, NULL); + idx = copy_tree_node(&iter, &newiter); + gtk_tree_store_remove(TREESTORE(dive_list), &iter); + get_dive(idx)->divetrip = DIVE_TRIP(prevtrip); + } + update_trip_timestamp(&prevtripiter, DIVE_TRIP(prevtrip)); + free(DIVE_TRIP(trip)); + delete_trip(trip); + gtk_tree_store_remove(TREESTORE(dive_list), &thistripiter); +} + +static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int button, GdkEventButton *event) { GtkWidget *menu, *menuitem, *image; char editlabel[] = "Edit dives"; + GtkTreePath *path, *prevpath; + GtkTreeIter iter, previter; + int idx, previdx; + struct dive *dive; + + if (!gtk_tree_view_get_path_at_pos(tree_view, event->x, event->y, &path, NULL, NULL, NULL)) + return; + gtk_tree_model_get_iter(TREEMODEL(dive_list), &iter, path); + gtk_tree_model_get(TREEMODEL(dive_list), &iter, DIVE_INDEX, &idx, -1); menu = gtk_menu_new(); menuitem = gtk_image_menu_item_new_with_label("Add dive"); @@ -1178,12 +1512,56 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image); g_signal_connect(menuitem, "activate", G_CALLBACK(add_dive_cb), NULL); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - if (amount_selected) { - if (amount_selected == 1) - editlabel[strlen(editlabel) - 1] = '\0'; - menuitem = gtk_menu_item_new_with_label(editlabel); - g_signal_connect(menuitem, "activate", G_CALLBACK(edit_dive_cb), model); + + if (idx < 0) { + /* mouse pointer is on a trip summary entry */ + menuitem = gtk_menu_item_new_with_label("Edit Trip Summary"); + g_signal_connect(menuitem, "activate", G_CALLBACK(edit_trip_cb), path); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + prevpath = gtk_tree_path_copy(path); + if (gtk_tree_path_prev(prevpath) && + gtk_tree_model_get_iter(TREEMODEL(dive_list), &previter, prevpath)) { + gtk_tree_model_get(TREEMODEL(dive_list), &previter, DIVE_INDEX, &previdx, -1); + if (previdx < 0) { + menuitem = gtk_menu_item_new_with_label("Merge trip with previous"); + g_signal_connect(menuitem, "activate", G_CALLBACK(merge_trips_cb), path); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + } + } + menuitem = gtk_menu_item_new_with_label("Remove Trip"); + g_signal_connect(menuitem, "activate", G_CALLBACK(remove_trip_cb), path); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + } else { + dive = get_dive(idx); + /* if we right click on selected dive(s), edit those */ + if (dive->selected) { + if (amount_selected == 1) + editlabel[strlen(editlabel) - 1] = '\0'; + menuitem = gtk_menu_item_new_with_label(editlabel); + g_signal_connect(menuitem, "activate", G_CALLBACK(edit_selected_dives_cb), NULL); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + } else { + editlabel[strlen(editlabel) - 1] = '\0'; + menuitem = gtk_menu_item_new_with_label(editlabel); + g_signal_connect(menuitem, "activate", G_CALLBACK(edit_dive_from_path_cb), path); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + } + /* only offer trip editing options when we are displaying the tree model */ + if (dive_list.model == dive_list.treemodel) { + int depth; + int *indices = gtk_tree_path_get_indices_with_depth(path, &depth); + + if (depth == 1 || indices[1] > 0) { + menuitem = gtk_menu_item_new_with_label("Add new trip above"); + g_signal_connect(menuitem, "activate", G_CALLBACK(insert_trip_before_cb), path); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + } + if (DIVE_IN_TRIP(dive)) { + menuitem = gtk_menu_item_new_with_label("Remove from trip"); + g_signal_connect(menuitem, "activate", G_CALLBACK(remove_from_trip_cb), path); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + } + } } menuitem = gtk_menu_item_new_with_label("Expand all"); g_signal_connect(menuitem, "activate", G_CALLBACK(expand_all_cb), tree_view); @@ -1199,14 +1577,14 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int static void popup_menu_cb(GtkTreeView *tree_view, gpointer userdata) { - popup_divelist_menu(tree_view, GTK_TREE_MODEL(dive_list.model), 0); + popup_divelist_menu(tree_view, GTK_TREE_MODEL(dive_list.model), 0, NULL); } static gboolean button_press_cb(GtkWidget *treeview, GdkEventButton *event, gpointer userdata) { /* Right-click? Bring up the menu */ if (event->type == GDK_BUTTON_PRESS && event->button == 3) { - popup_divelist_menu(GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(dive_list.model), 3); + popup_divelist_menu(GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(dive_list.model), 3, event); return TRUE; } return FALSE; diff --git a/info.c b/info.c index d9379ac68..d43d531a0 100644 --- a/info.c +++ b/info.c @@ -415,6 +415,24 @@ 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) +{ + GtkWidget *hbox, *label; + char buffer[80] = "Edit trip summary"; + + label = gtk_label_new(buffer); + gtk_box_pack_start(GTK_BOX(box), label, FALSE, TRUE, 0); + + info->location = text_entry(box, "Location", location_list, trip->location); + + hbox = gtk_hbox_new(FALSE, 3); + gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, TRUE, 0); + + info->notes = text_view(box, "Notes", READ_WRITE); + if (trip->notes && *trip->notes) + gtk_text_buffer_set_text(gtk_text_view_get_buffer(info->notes), trip->notes, -1); +} + static void dive_info_widget(GtkWidget *box, struct dive *dive, struct dive_info *info, gboolean multi) { GtkWidget *hbox, *label, *frame, *equipment; @@ -489,7 +507,49 @@ void update_equipment_data(struct dive *dive, struct dive *master) memcpy(dive->weightsystem, master->weightsystem, WS_BYTES); } -/* A negative index means "all selected" */ +gboolean edit_trip(struct dive *trip) +{ + GtkWidget *dialog, *vbox; + int success; + gboolean changed = FALSE; + char *old_text, *new_text; + struct dive_info info; + + memset(&info, 0, sizeof(struct dive_info)); + dialog = gtk_dialog_new_with_buttons("Edit Trip Info", + GTK_WINDOW(main_window), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, + GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, + NULL); + vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + dive_trip_widget(vbox, trip, &info); + gtk_widget_show_all(dialog); + success = gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT; + if (success) { + /* we need to store the edited location and notes */ + new_text = get_combo_box_entry_text(info.location, &trip->location, trip->location); + if (new_text) { + add_location(new_text); + changed = 1; + } + if (info.notes) { + old_text = trip->notes; + trip->notes = get_text(info.notes); + if (text_changed(old_text, trip->notes)) + changed = 1; + if (old_text) + g_free(old_text); + } + if (changed) { + mark_divelist_changed(TRUE); + flush_divelist(trip); + } + } + gtk_widget_destroy(dialog); + return changed; +} + int edit_multi_dive_info(struct dive *single_dive) { int success; -- cgit v1.2.3-70-g09d2 From ea2900a34a5ec186620b9a4f5caceb65a2be4ff7 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Sun, 2 Sep 2012 11:17:31 -0700 Subject: Use truth values with gboolean Just a little cosmetic oversight Signed-off-by: Dirk Hohndel --- info.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/info.c b/info.c index d43d531a0..3efb40cf8 100644 --- a/info.c +++ b/info.c @@ -531,13 +531,13 @@ gboolean edit_trip(struct dive *trip) new_text = get_combo_box_entry_text(info.location, &trip->location, trip->location); if (new_text) { add_location(new_text); - changed = 1; + changed = TRUE; } if (info.notes) { old_text = trip->notes; trip->notes = get_text(info.notes); if (text_changed(old_text, trip->notes)) - changed = 1; + changed = TRUE; if (old_text) g_free(old_text); } -- cgit v1.2.3-70-g09d2 From 22ff8df880461c6e66d45fa8eaba9c9c26edb1bd Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Sun, 2 Sep 2012 21:46:48 -0700 Subject: Fix a crash when changing sort column We were using the tree model to check the selection, even though the active model is the list model after switching to a different sort column. To make things clearer I renamed the access macros to be more consistent. Signed-off-by: Dirk Hohndel --- divelist.c | 162 +++++++++++++++++++++++++++++++------------------------------ 1 file changed, 82 insertions(+), 80 deletions(-) diff --git a/divelist.c b/divelist.c index 4e0f940bb..5f45e900b 100644 --- a/divelist.c +++ b/divelist.c @@ -31,9 +31,11 @@ struct DiveList { }; static struct DiveList dive_list; +#define MODEL(_dl) GTK_TREE_MODEL((_dl).model) #define TREEMODEL(_dl) GTK_TREE_MODEL((_dl).treemodel) -#define TREESTORE(_dl) GTK_TREE_STORE((_dl).treemodel) #define LISTMODEL(_dl) GTK_TREE_MODEL((_dl).listmodel) +#define STORE(_dl) GTK_TREE_STORE((_dl).model) +#define TREESTORE(_dl) GTK_TREE_STORE((_dl).treemodel) #define LISTSTORE(_dl) GTK_TREE_STORE((_dl).listmodel) GList *dive_trip_list; @@ -130,7 +132,7 @@ static void first_leaf(GtkTreeModel *model, GtkTreeIter *iter, int *diveidx) return; if(!gtk_tree_view_row_expanded(GTK_TREE_VIEW(dive_list.tree_view), tpath)) gtk_tree_view_expand_row(GTK_TREE_VIEW(dive_list.tree_view), tpath, FALSE); - gtk_tree_model_get(GTK_TREE_MODEL(model), iter, DIVE_INDEX, diveidx, -1); + gtk_tree_model_get(model, iter, DIVE_INDEX, diveidx, -1); } } @@ -139,7 +141,7 @@ static void first_leaf(GtkTreeModel *model, GtkTreeIter *iter, int *diveidx) void row_expanded_cb(GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer data) { GtkTreeIter child; - GtkTreeModel *model = TREEMODEL(dive_list); + GtkTreeModel *model = MODEL(dive_list); GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view)); if (!gtk_tree_model_iter_children(model, &child, iter)) @@ -183,7 +185,7 @@ static int selected_children(GtkTreeModel *model, GtkTreeIter *iter) shows up as selected too */ void row_collapsed_cb(GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer data) { - GtkTreeModel *model = TREEMODEL(dive_list); + GtkTreeModel *model = MODEL(dive_list); GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view)); if (selected_children(model, iter)) @@ -267,7 +269,7 @@ static void select_dive_group(GtkTreeModel *model, GtkTreeSelection *selection, */ static void check_selection_cb(GtkTreeIter *iter, GtkTreeSelection *selection) { - GtkTreeModel *model = TREEMODEL(dive_list); + GtkTreeModel *model = MODEL(dive_list); struct dive *dive; int idx, gtk_selected; @@ -808,7 +810,7 @@ static void fill_one_dive(struct dive *dive, GtkTreeIter *iter) { char *location, *cylinder, *suit; - GtkTreeStore *othermodel; + GtkTreeModel *othermodel; get_cylinder(dive, &cylinder); get_location(dive, &location); @@ -830,12 +832,12 @@ static void fill_one_dive(struct dive *dive, free(suit); if (model == TREEMODEL(dive_list)) - othermodel = dive_list.listmodel; + othermodel = LISTMODEL(dive_list); else - othermodel = dive_list.treemodel; - if (othermodel != dive_list.model) + othermodel = TREEMODEL(dive_list); + if (othermodel != MODEL(dive_list)) /* recursive call */ - gtk_tree_model_foreach(GTK_TREE_MODEL(othermodel), set_one_dive, dive); + gtk_tree_model_foreach(othermodel, set_one_dive, dive); } static gboolean set_one_dive(GtkTreeModel *model, @@ -862,7 +864,7 @@ static gboolean set_one_dive(GtkTreeModel *model, void flush_divelist(struct dive *dive) { - GtkTreeModel *model = TREEMODEL(dive_list); + GtkTreeModel *model = MODEL(dive_list); gtk_tree_model_foreach(model, set_one_dive, dive); } @@ -877,7 +879,7 @@ void set_divelist_font(const char *font) void update_dive_list_units(void) { const char *unit; - GtkTreeModel *model = TREEMODEL(dive_list); + GtkTreeModel *model = MODEL(dive_list); (void) get_depth_units(0, NULL, &unit); gtk_tree_view_column_set_title(dive_list.depth, unit); @@ -1035,12 +1037,12 @@ static void fill_dive_list(void) DIVE_LOCATION, dive_trip->location, -1); update_dive_list_units(); - if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(dive_list.model), &iter)) { + if (gtk_tree_model_get_iter_first(MODEL(dive_list), &iter)) { GtkTreeSelection *selection; /* select the last dive (and make sure it's an actual dive that is selected) */ - gtk_tree_model_get(GTK_TREE_MODEL(dive_list.model), &iter, DIVE_INDEX, &selected_dive, -1); - first_leaf(GTK_TREE_MODEL(dive_list.model), &iter, &selected_dive); + gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &selected_dive, -1); + first_leaf(MODEL(dive_list), &iter, &selected_dive); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view)); gtk_tree_selection_select_iter(selection, &iter); } @@ -1134,10 +1136,10 @@ static void row_activated_cb(GtkTreeView *tree_view, int index; GtkTreeIter iter; - if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(dive_list.model), &iter, path)) + if (!gtk_tree_model_get_iter(MODEL(dive_list), &iter, path)) return; - gtk_tree_model_get(GTK_TREE_MODEL(dive_list.model), &iter, DIVE_INDEX, &index, -1); + gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &index, -1); /* a negative index is special for the "group by date" entries */ if (index < 0) { collapse_expand(tree_view, path); @@ -1166,12 +1168,12 @@ void edit_trip_cb(GtkWidget *menuitem, GtkTreePath *path) struct dive *dive_trip; GList *trip; - gtk_tree_model_get_iter(TREEMODEL(dive_list), &iter, path); - gtk_tree_model_get(TREEMODEL(dive_list), &iter, DIVE_DATE, &when, -1); + 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); dive_trip = DIVE_TRIP(trip); if (edit_trip(dive_trip)) - gtk_tree_store_set(TREESTORE(dive_list), &iter, DIVE_LOCATION, dive_trip->location, -1); + gtk_tree_store_set(STORE(dive_list), &iter, DIVE_LOCATION, dive_trip->location, -1); } void edit_selected_dives_cb(GtkWidget *menuitem, gpointer data) @@ -1185,8 +1187,8 @@ void edit_dive_from_path_cb(GtkWidget *menuitem, GtkTreePath *path) int idx; struct dive *dive; - gtk_tree_model_get_iter(TREEMODEL(dive_list), &iter, path); - gtk_tree_model_get(TREEMODEL(dive_list), &iter, DIVE_INDEX, &idx, -1); + 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); edit_multi_dive_info(dive); @@ -1209,7 +1211,7 @@ static int copy_tree_node(GtkTreeIter *a, GtkTreeIter *b) int totalweight, idx; char *cylinder_text; - gtk_tree_model_get(TREEMODEL(dive_list), a, + gtk_tree_model_get(MODEL(dive_list), a, DIVE_INDEX, &idx, DIVE_NR, &store_dive.number, DIVE_DATE, &store_dive.when, @@ -1224,7 +1226,7 @@ static int copy_tree_node(GtkTreeIter *a, GtkTreeIter *b) DIVE_OTU, &store_dive.otu, DIVE_LOCATION, &store_dive.location, -1); - gtk_tree_store_set(TREESTORE(dive_list), b, + gtk_tree_store_set(STORE(dive_list), b, DIVE_INDEX, idx, DIVE_NR, store_dive.number, DIVE_DATE, store_dive.when, @@ -1251,15 +1253,15 @@ static void update_trip_timestamp(GtkTreeIter *parent, struct dive *divetrip) int nr; time_t t1, t2, tnew; - if (gtk_tree_store_iter_depth(TREESTORE(dive_list), parent) != 0) + if (gtk_tree_store_iter_depth(STORE(dive_list), parent) != 0) return; - nr = gtk_tree_model_iter_n_children(TREEMODEL(dive_list), parent); - gtk_tree_model_iter_nth_child(TREEMODEL(dive_list), &first_child, parent, 0); - gtk_tree_model_get(TREEMODEL(dive_list), &first_child, DIVE_DATE, &t1, -1); - gtk_tree_model_iter_nth_child(TREEMODEL(dive_list), &last_child, parent, nr - 1); - gtk_tree_model_get(TREEMODEL(dive_list), &last_child, DIVE_DATE, &t2, -1); + nr = gtk_tree_model_iter_n_children(MODEL(dive_list), parent); + gtk_tree_model_iter_nth_child(MODEL(dive_list), &first_child, parent, 0); + gtk_tree_model_get(MODEL(dive_list), &first_child, DIVE_DATE, &t1, -1); + gtk_tree_model_iter_nth_child(MODEL(dive_list), &last_child, parent, nr - 1); + gtk_tree_model_get(MODEL(dive_list), &last_child, DIVE_DATE, &t2, -1); tnew = MIN(t1, t2); - gtk_tree_store_set(TREESTORE(dive_list), parent, DIVE_DATE, tnew, -1); + gtk_tree_store_set(STORE(dive_list), parent, DIVE_DATE, tnew, -1); if (divetrip) divetrip->when = tnew; } @@ -1278,20 +1280,20 @@ static GtkTreeIter *move_dive_between_trips(GtkTreeIter *dive_iter, GtkTreeIter GtkTreeIter *new_iter = malloc(sizeof(GtkTreeIter)); if (before) - gtk_tree_store_insert_before(GTK_TREE_STORE(TREEMODEL(dive_list)), new_iter, new_trip, sibling); + gtk_tree_store_insert_before(STORE(dive_list), new_iter, new_trip, sibling); else - gtk_tree_store_insert_after(GTK_TREE_STORE(TREEMODEL(dive_list)), new_iter, new_trip, sibling); + gtk_tree_store_insert_after(STORE(dive_list), new_iter, new_trip, sibling); idx = copy_tree_node(dive_iter, new_iter); - gtk_tree_model_get(TREEMODEL(dive_list), new_iter, DIVE_INDEX, &idx, -1); + gtk_tree_model_get(MODEL(dive_list), new_iter, DIVE_INDEX, &idx, -1); dive = get_dive(idx); - gtk_tree_store_remove(GTK_TREE_STORE(TREEMODEL(dive_list)), dive_iter); + gtk_tree_store_remove(STORE(dive_list), dive_iter); if (old_trip) { - gtk_tree_model_get(TREEMODEL(dive_list), old_trip, DIVE_DATE, &old_when, -1); + gtk_tree_model_get(MODEL(dive_list), old_trip, DIVE_DATE, &old_when, -1); old_divetrip = DIVE_TRIP(find_matching_trip(old_when)); update_trip_timestamp(old_trip, old_divetrip); } if (new_trip) { - gtk_tree_model_get(TREEMODEL(dive_list), new_trip, DIVE_DATE, &new_when, -1); + gtk_tree_model_get(MODEL(dive_list), new_trip, DIVE_DATE, &new_when, -1); new_divetrip = dive->divetrip; update_trip_timestamp(new_trip, new_divetrip); } @@ -1313,15 +1315,15 @@ static void turn_dive_into_trip(GtkTreePath *path) /* this is a dive on the top level, insert trip AFTER it, populate its date / location, and * then move the dive below that trip */ - gtk_tree_model_get_iter(TREEMODEL(dive_list), &iter, path); - gtk_tree_store_insert_after(TREESTORE(dive_list), &newparent, NULL, &iter); - gtk_tree_model_get(TREEMODEL(dive_list), &iter, + gtk_tree_model_get_iter(MODEL(dive_list), &iter, path); + gtk_tree_store_insert_after(STORE(dive_list), &newparent, NULL, &iter); + gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &idx, DIVE_DATE, &when, DIVE_LOCATION, &location, -1); - gtk_tree_store_set(TREESTORE(dive_list), &newparent, + gtk_tree_store_set(STORE(dive_list), &newparent, DIVE_INDEX, -1, DIVE_DATE, when, DIVE_LOCATION, location, -1); free(location); newiter = move_dive_between_trips(&iter, NULL, &newparent, NULL, FALSE); - treepath = gtk_tree_model_get_path(TREEMODEL(dive_list), newiter); + 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 */ @@ -1336,17 +1338,17 @@ static void insert_trip_before(GtkTreePath *path) struct dive *dive, *prev_dive, *new_divetrip; int idx, nr, i; - gtk_tree_model_get_iter(TREEMODEL(dive_list), &iter, path); + gtk_tree_model_get_iter(MODEL(dive_list), &iter, path); prev_path = gtk_tree_path_copy(path); if (!gtk_tree_path_prev(prev_path) || - !gtk_tree_model_iter_parent(TREEMODEL(dive_list), &parent, &iter)) + !gtk_tree_model_iter_parent(MODEL(dive_list), &parent, &iter)) return; - gtk_tree_model_get_iter(TREEMODEL(dive_list), &prev_iter, prev_path); - gtk_tree_model_get(TREEMODEL(dive_list), &prev_iter, DIVE_INDEX, &idx, -1); + gtk_tree_model_get_iter(MODEL(dive_list), &prev_iter, prev_path); + gtk_tree_model_get(MODEL(dive_list), &prev_iter, DIVE_INDEX, &idx, -1); prev_dive = get_dive(idx); - gtk_tree_store_insert_after(TREESTORE(dive_list), &newparent, NULL, &parent); + gtk_tree_store_insert_after(STORE(dive_list), &newparent, NULL, &parent); copy_tree_node(&parent, &newparent); - gtk_tree_model_get(TREEMODEL(dive_list), &iter, DIVE_INDEX, &idx, -1); + gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &idx, -1); dive = get_dive(idx); /* make sure that the time_t of the previous divetrip is correct before * inserting a new one */ @@ -1358,11 +1360,11 @@ static void insert_trip_before(GtkTreePath *path) /* in order for the data structures to stay consistent we need to walk from * the last child backwards to this one. The easiest way seems to be to do * this with the nth iterator API */ - nr = gtk_tree_model_iter_n_children(TREEMODEL(dive_list), &parent); + nr = gtk_tree_model_iter_n_children(MODEL(dive_list), &parent); for (i = nr - 1; i >= 0; i--) { - gtk_tree_model_iter_nth_child(TREEMODEL(dive_list), &nextsibling, &parent, i); - treepath = gtk_tree_model_get_path(TREEMODEL(dive_list), &nextsibling); - gtk_tree_model_get(TREEMODEL(dive_list), &nextsibling, DIVE_INDEX, &idx, -1); + gtk_tree_model_iter_nth_child(MODEL(dive_list), &nextsibling, &parent, i); + treepath = gtk_tree_model_get_path(MODEL(dive_list), &nextsibling); + gtk_tree_model_get(MODEL(dive_list), &nextsibling, DIVE_INDEX, &idx, -1); dive = get_dive(idx); dive->divetrip = new_divetrip; if (dive->when < dive->divetrip->when) @@ -1372,7 +1374,7 @@ static void insert_trip_before(GtkTreePath *path) /* we copied the dive we were called with; we are done */ break; } - treepath = gtk_tree_model_get_path(TREEMODEL(dive_list), &newparent); + 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 dump_trip_list(); @@ -1395,30 +1397,30 @@ static void remove_from_trip_cb(GtkWidget *menuitem, GtkTreePath *path) struct dive *dive; int idx; - gtk_tree_model_get_iter(TREEMODEL(dive_list), &iter, path); - if (!gtk_tree_model_iter_parent(TREEMODEL(dive_list), &parent, &iter)) + gtk_tree_model_get_iter(MODEL(dive_list), &iter, path); + if (!gtk_tree_model_iter_parent(MODEL(dive_list), &parent, &iter)) return; /* if this isn't the last dive in a trip we simply split the trip in two right after this dive */ nextpath = gtk_tree_path_copy(path); gtk_tree_path_next(nextpath); - if (gtk_tree_model_get_iter(TREEMODEL(dive_list), &newiter, nextpath)) + if (gtk_tree_model_get_iter(MODEL(dive_list), &newiter, nextpath)) insert_trip_before(nextpath); /* now create a new node as sibling right after the current parent */ - gtk_tree_store_insert_after(TREESTORE(dive_list), &newiter, NULL, &parent); + gtk_tree_store_insert_after(STORE(dive_list), &newiter, NULL, &parent); copy_tree_node(&iter, &newiter); - gtk_tree_model_get(TREEMODEL(dive_list), &iter, DIVE_INDEX, &idx, -1); + gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &idx, -1); dive = get_dive(idx); if (dive->selected) { GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view)); gtk_tree_selection_select_iter(selection, &newiter); } - gtk_tree_store_remove(TREESTORE(dive_list), &iter); + gtk_tree_store_remove(STORE(dive_list), &iter); /* if this was the last dive on the trip, remove the trip */ - if (! gtk_tree_model_iter_has_child(TREEMODEL(dive_list), &parent)) { - gtk_tree_store_remove(TREESTORE(dive_list), &parent); + 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)); } dive->tripflag = NO_TRIP; @@ -1435,16 +1437,16 @@ void remove_trip_cb(GtkWidget *menuitem, GtkTreePath *trippath) /* what a pain - we can't just move the nodes, we have to * create new ones and delete the existing ones instead */ - gtk_tree_model_get_iter(TREEMODEL(dive_list), &parent, trippath); + gtk_tree_model_get_iter(MODEL(dive_list), &parent, trippath); childpath = gtk_tree_path_copy(trippath); gtk_tree_path_down(childpath); for (;;) { - if( ! gtk_tree_model_get_iter(TREEMODEL(dive_list), &child, childpath)) + if( ! gtk_tree_model_get_iter(MODEL(dive_list), &child, childpath)) break; - gtk_tree_store_insert_after(TREESTORE(dive_list), &newiter, NULL, lastiter); + gtk_tree_store_insert_after(STORE(dive_list), &newiter, NULL, lastiter); copy_tree_node(&child, &newiter); /* we need to track what was selected */ - gtk_tree_model_get(TREEMODEL(dive_list), &child, DIVE_INDEX, &idx, -1); + gtk_tree_model_get(MODEL(dive_list), &child, DIVE_INDEX, &idx, -1); dive = get_dive(idx); if (dive->selected) gtk_tree_selection_select_iter(selection, &newiter); @@ -1453,11 +1455,11 @@ void remove_trip_cb(GtkWidget *menuitem, GtkTreePath *trippath) dive_trip = dive->divetrip; dive->divetrip = NULL; /* this removes the child - now childpath points to the next child */ - gtk_tree_store_remove(TREESTORE(dive_list), &child); + gtk_tree_store_remove(STORE(dive_list), &child); lastiter = &newiter; } /* finally, remove the trip */ - gtk_tree_store_remove(TREESTORE(dive_list), &parent); + gtk_tree_store_remove(STORE(dive_list), &parent); delete_trip(FIND_TRIP(dive_trip->when)); free(dive_trip); } @@ -1466,7 +1468,7 @@ void merge_trips_cb(GtkWidget *menuitem, GtkTreePath *trippath) { GtkTreePath *prevpath; GtkTreeIter thistripiter, prevtripiter, newiter, iter; - GtkTreeModel *tm = TREEMODEL(dive_list); + GtkTreeModel *tm = MODEL(dive_list); GList *trip, *prevtrip; time_t when; @@ -1481,15 +1483,15 @@ void merge_trips_cb(GtkWidget *menuitem, GtkTreePath *trippath) prevtrip = find_matching_trip(when); while (gtk_tree_model_iter_children(tm, &iter, &thistripiter)) { int idx; - gtk_tree_store_insert_before(TREESTORE(dive_list), &newiter, &prevtripiter, NULL); + gtk_tree_store_insert_before(STORE(dive_list), &newiter, &prevtripiter, NULL); idx = copy_tree_node(&iter, &newiter); - gtk_tree_store_remove(TREESTORE(dive_list), &iter); + gtk_tree_store_remove(STORE(dive_list), &iter); get_dive(idx)->divetrip = DIVE_TRIP(prevtrip); } update_trip_timestamp(&prevtripiter, DIVE_TRIP(prevtrip)); free(DIVE_TRIP(trip)); delete_trip(trip); - gtk_tree_store_remove(TREESTORE(dive_list), &thistripiter); + gtk_tree_store_remove(STORE(dive_list), &thistripiter); } static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int button, GdkEventButton *event) @@ -1503,8 +1505,8 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int if (!gtk_tree_view_get_path_at_pos(tree_view, event->x, event->y, &path, NULL, NULL, NULL)) return; - gtk_tree_model_get_iter(TREEMODEL(dive_list), &iter, path); - gtk_tree_model_get(TREEMODEL(dive_list), &iter, DIVE_INDEX, &idx, -1); + gtk_tree_model_get_iter(MODEL(dive_list), &iter, path); + gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &idx, -1); menu = gtk_menu_new(); menuitem = gtk_image_menu_item_new_with_label("Add dive"); @@ -1520,8 +1522,8 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); prevpath = gtk_tree_path_copy(path); if (gtk_tree_path_prev(prevpath) && - gtk_tree_model_get_iter(TREEMODEL(dive_list), &previter, prevpath)) { - gtk_tree_model_get(TREEMODEL(dive_list), &previter, DIVE_INDEX, &previdx, -1); + gtk_tree_model_get_iter(MODEL(dive_list), &previter, prevpath)) { + gtk_tree_model_get(MODEL(dive_list), &previter, DIVE_INDEX, &previdx, -1); if (previdx < 0) { menuitem = gtk_menu_item_new_with_label("Merge trip with previous"); g_signal_connect(menuitem, "activate", G_CALLBACK(merge_trips_cb), path); @@ -1577,14 +1579,14 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int static void popup_menu_cb(GtkTreeView *tree_view, gpointer userdata) { - popup_divelist_menu(tree_view, GTK_TREE_MODEL(dive_list.model), 0, NULL); + popup_divelist_menu(tree_view, MODEL(dive_list), 0, NULL); } static gboolean button_press_cb(GtkWidget *treeview, GdkEventButton *event, gpointer userdata) { /* Right-click? Bring up the menu */ if (event->type == GDK_BUTTON_PRESS && event->button == 3) { - popup_divelist_menu(GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(dive_list.model), 3, event); + popup_divelist_menu(GTK_TREE_VIEW(treeview), MODEL(dive_list), 3, event); return TRUE; } return FALSE; @@ -1675,9 +1677,9 @@ static void sort_column_change_cb(GtkTreeSortable *treeview, gpointer data) if (dive_list.model != currentmodel) { GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view)); - gtk_tree_view_set_model(GTK_TREE_VIEW(dive_list.tree_view), GTK_TREE_MODEL(dive_list.model)); + gtk_tree_view_set_model(GTK_TREE_VIEW(dive_list.tree_view), MODEL(dive_list)); update_column_and_order(colid); - gtk_tree_model_foreach(GTK_TREE_MODEL(dive_list.model), set_selected, selection); + gtk_tree_model_foreach(MODEL(dive_list), set_selected, selection); } else { if (order != sortorder[colid]) { update_column_and_order(colid); @@ -1722,7 +1724,7 @@ GtkWidget *dive_list_create(void) G_TYPE_STRING /* Location */ ); dive_list.model = dive_list.treemodel; - dive_list.tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dive_list.model)); + dive_list.tree_view = gtk_tree_view_new_with_model(TREEMODEL(dive_list)); set_divelist_font(divelist_font); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view)); -- cgit v1.2.3-70-g09d2 From f6e8903a528a65f0e0fd050c203c95d57afd2db9 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Sun, 2 Sep 2012 21:48:30 -0700 Subject: Add autogen menu command This adds the ability to auto create trips from the menu. It's a toggle entry (and while at it, we made the zoom toggle a toggle entry as well). We can therfore switch back and forth between auto generated trips. There is one bug. Assume you have no trips. You manually create a trip from some dives out of a group of trips that autogen would turn into a trip. Now you turn on autogen and this trip gets expanded with all the dives that would normally be grouped together. If you turn off autogen again, all those dives are still part of the remaining (initially manually created) trip. Working around this issue seemed a lot more work than the likelihood of anyone running into it seemed worth. Signed-off-by: Dirk Hohndel --- divelist.c | 40 ++++++++++++++++++++++++++++++++++++++-- divelist.h | 1 + gtk-gui.c | 17 ++++++++++++++++- 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/divelist.c b/divelist.c index 5f45e900b..64b392f54 100644 --- a/divelist.c +++ b/divelist.c @@ -970,11 +970,16 @@ static void fill_dive_list(void) /* allocate new trip - all fields default to 0 and get filled in further down */ dive_trip = create_and_hookup_trip_from_dive(dive); + dive_trip->tripflag = IN_TRIP; /* this marks an autogen trip */ trip = FIND_TRIP(dive_trip->when); } } else if (DIVE_IN_TRIP(dive)) { trip = find_matching_trip(dive->when); dive_trip = DIVE_TRIP(trip); + } else { + /* dive is not in a trip and we aren't autogrouping */ + dive_trip = NULL; + parent_ptr = NULL; } /* update dive as part of dive_trip and * (if necessary) update dive_trip time and location */ @@ -1427,7 +1432,7 @@ static void remove_from_trip_cb(GtkWidget *menuitem, GtkTreePath *path) dive->divetrip = NULL; } -void remove_trip_cb(GtkWidget *menuitem, GtkTreePath *trippath) +void remove_trip(GtkTreePath *trippath, gboolean force_no_trip) { GtkTreeIter newiter, parent, child, *lastiter = &parent; struct dive *dive, *dive_trip = NULL; @@ -1450,7 +1455,10 @@ void remove_trip_cb(GtkWidget *menuitem, GtkTreePath *trippath) dive = get_dive(idx); if (dive->selected) gtk_tree_selection_select_iter(selection, &newiter); - dive->tripflag = NO_TRIP; + if (force_no_trip) + dive->tripflag = NO_TRIP; + else + dive->tripflag = TF_NONE; if (!dive_trip) dive_trip = dive->divetrip; dive->divetrip = NULL; @@ -1464,6 +1472,11 @@ void remove_trip_cb(GtkWidget *menuitem, GtkTreePath *trippath) free(dive_trip); } +void remove_trip_cb(GtkWidget *menuitem, GtkTreePath *trippath) +{ + remove_trip(trippath, TRUE); +} + void merge_trips_cb(GtkWidget *menuitem, GtkTreePath *trippath) { GtkTreePath *prevpath; @@ -1784,3 +1797,26 @@ int unsaved_changes() { return dive_list.changed; } + +void remove_autogen_trips() +{ + GtkTreeIter iter; + GtkTreePath *path; + time_t when; + int idx; + GList *trip; + + /* start with the first top level entry and walk all of them */ + path = gtk_tree_path_new_from_string("0"); + 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 */ + remove_trip(path, FALSE); + continue; + } + } + gtk_tree_path_next(path); + } +} diff --git a/divelist.h b/divelist.h index c170941db..45c1a18f8 100644 --- a/divelist.h +++ b/divelist.h @@ -10,4 +10,5 @@ extern void flush_divelist(struct dive *); extern void update_cylinder_related_info(struct dive *); extern void mark_divelist_changed(int); extern int unsaved_changes(void); +extern void remove_autogen_trips(void); #endif diff --git a/gtk-gui.c b/gtk-gui.c index 7db777ab9..03d2862c1 100644 --- a/gtk-gui.c +++ b/gtk-gui.c @@ -634,6 +634,14 @@ static void selectevents_dialog(GtkWidget *w, gpointer data) gtk_widget_destroy(dialog); } +static void autogroup_cb(GtkWidget *w, gpointer data) +{ + autogroup = !autogroup; + if (! autogroup) + remove_autogen_trips(); + dive_list_update_dives(); +} + static void renumber_dialog(GtkWidget *w, gpointer data) { int result; @@ -757,10 +765,15 @@ static GtkActionEntry menu_items[] = { { "ViewProfile", NULL, "Profile", CTRLCHAR "2", NULL, G_CALLBACK(view_profile) }, { "ViewInfo", NULL, "Info", CTRLCHAR "3", NULL, G_CALLBACK(view_info) }, { "ViewThree", NULL, "Three", CTRLCHAR "4", NULL, G_CALLBACK(view_three) }, - { "ToggleZoom", NULL, "Toggle Zoom", CTRLCHAR "0", NULL, G_CALLBACK(toggle_zoom) }, }; static gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]); +static GtkToggleActionEntry toggle_items[] = { + { "Autogroup", NULL, "Autogroup", NULL, NULL, G_CALLBACK(autogroup_cb), FALSE }, + { "ToggleZoom", NULL, "Toggle Zoom", CTRLCHAR "0", NULL, G_CALLBACK(toggle_zoom), FALSE }, +}; +static gint ntoggle_items = sizeof (toggle_items) / sizeof (toggle_items[0]); + static const gchar* ui_string = " \ \ \ @@ -779,6 +792,7 @@ static const gchar* ui_string = " \ \ \ \ + \ \ \ \ @@ -801,6 +815,7 @@ static GtkWidget *get_menubar_menu(GtkWidget *window, GtkUIManager *ui_manager) { GtkActionGroup *action_group = gtk_action_group_new("Menu"); gtk_action_group_add_actions(action_group, menu_items, nmenu_items, 0); + gtk_action_group_add_toggle_actions(action_group, toggle_items, ntoggle_items, 0); gtk_ui_manager_insert_action_group(ui_manager, action_group, 0); GError* error = 0; -- cgit v1.2.3-70-g09d2 From f4f5536baddf8dc7dc8ed9e913eabbc904960f94 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Mon, 3 Sep 2012 07:58:11 -0700 Subject: Fix copy_tree_node to no longer overwrite dive duration Cut and paste error when creating this function. Reported-by: Henrik Brautaset Aronsen Signed-off-by: Dirk Hohndel --- divelist.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/divelist.c b/divelist.c index 64b392f54..1c5db5d9b 100644 --- a/divelist.c +++ b/divelist.c @@ -1223,7 +1223,7 @@ static int copy_tree_node(GtkTreeIter *a, GtkTreeIter *b) DIVE_RATING, &store_dive.rating, DIVE_DEPTH, &store_dive.maxdepth, DIVE_DURATION, &store_dive.duration, - DIVE_TEMPERATURE, &store_dive.duration, + DIVE_TEMPERATURE, &store_dive.watertemp.mkelvin, DIVE_TOTALWEIGHT, &totalweight, DIVE_SUIT, &store_dive.suit, DIVE_CYLINDER, &cylinder_text, @@ -1238,7 +1238,7 @@ static int copy_tree_node(GtkTreeIter *a, GtkTreeIter *b) DIVE_RATING, store_dive.rating, DIVE_DEPTH, store_dive.maxdepth, DIVE_DURATION, store_dive.duration, - DIVE_TEMPERATURE, store_dive.duration, + DIVE_TEMPERATURE, store_dive.watertemp.mkelvin, DIVE_TOTALWEIGHT, totalweight, DIVE_SUIT, store_dive.suit, DIVE_CYLINDER, cylinder_text, -- cgit v1.2.3-70-g09d2 From 8b021de8d9838f4591b50cb15fc8774c31f8ed14 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Mon, 3 Sep 2012 08:01:21 -0700 Subject: Correctly initialize the toggle state of the autogroup menu entry If we move to Linus' tri-state variable we need to separate those two items, anyway. But for now this fixes the obvious bug. Reported-by: Henrik Brautaset Aronsen Signed-off-by: Dirk Hohndel --- gtk-gui.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gtk-gui.c b/gtk-gui.c index 03d2862c1..a2f130ac2 100644 --- a/gtk-gui.c +++ b/gtk-gui.c @@ -815,6 +815,7 @@ static GtkWidget *get_menubar_menu(GtkWidget *window, GtkUIManager *ui_manager) { GtkActionGroup *action_group = gtk_action_group_new("Menu"); gtk_action_group_add_actions(action_group, menu_items, nmenu_items, 0); + toggle_items[0].is_active = autogroup; gtk_action_group_add_toggle_actions(action_group, toggle_items, ntoggle_items, 0); gtk_ui_manager_insert_action_group(ui_manager, action_group, 0); -- cgit v1.2.3-70-g09d2 From 1f252fedd1c53bb347ff79740f6dcad32691f0cd Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Mon, 3 Sep 2012 10:30:48 -0700 Subject: Fix crash when removing the first dive of a trip The update_trip_timestamp function can indeed get called with no children present, just before that trip is then removed. So instead of adding complicated special cases, this just bails out of the function. Reported-by: Henrik Brautaset Aronsen Signed-off-by: Dirk Hohndel --- divelist.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/divelist.c b/divelist.c index 1c5db5d9b..de7304520 100644 --- a/divelist.c +++ b/divelist.c @@ -1258,7 +1258,8 @@ static void update_trip_timestamp(GtkTreeIter *parent, struct dive *divetrip) int nr; time_t t1, t2, tnew; - if (gtk_tree_store_iter_depth(STORE(dive_list), parent) != 0) + if (gtk_tree_store_iter_depth(STORE(dive_list), parent) != 0 || + gtk_tree_model_iter_n_children(MODEL(dive_list), parent) == 0) return; nr = gtk_tree_model_iter_n_children(MODEL(dive_list), parent); gtk_tree_model_iter_nth_child(MODEL(dive_list), &first_child, parent, 0); -- cgit v1.2.3-70-g09d2 From 2a1d7a510c60ad26e456b40e4f34caeb145339e3 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Mon, 3 Sep 2012 10:31:25 -0700 Subject: Correct the trip related test dives They still had the old "date only" format, but the code now relies on date and time being both set. Signed-off-by: Dirk Hohndel --- dives/test21.xml | 2 +- dives/test22.xml | 2 +- dives/test23.xml | 9 +++++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/dives/test21.xml b/dives/test21.xml index 5f5f6c981..ce6b82f35 100644 --- a/dives/test21.xml +++ b/dives/test21.xml @@ -1,6 +1,6 @@ - + 20th test dive - this should be in a trip with same location diff --git a/dives/test22.xml b/dives/test22.xml index a61032327..e8112287d 100644 --- a/dives/test22.xml +++ b/dives/test22.xml @@ -1,6 +1,6 @@ - + 21st test dive - this should be in a trip with a trip location diff --git a/dives/test23.xml b/dives/test23.xml index c61ad2db9..defdfdd90 100644 --- a/dives/test23.xml +++ b/dives/test23.xml @@ -1,7 +1,12 @@ - - + + + + 23rd test dive - this should be in a trip + We are testing that the NOTRIP flag works + + 22nd test dive - this should not be in a trip We are testing that the NOTRIP flag works -- cgit v1.2.3-70-g09d2 From 70d254ab844ca5d4129eebdadd0b8729acd0d1e8 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Mon, 3 Sep 2012 20:36:46 -0700 Subject: Use the infrastructure for moving dives in more places Instead of using our generic helper function the code in remove_from_trip_cb tried to implement the special case - and got it wrong. This fixes yet another crash that Henrik found. Reported-by: Henrik Brautaset Aronsen Signed-off-by: Dirk Hohndel --- divelist.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/divelist.c b/divelist.c index de7304520..90b3f693d 100644 --- a/divelist.c +++ b/divelist.c @@ -1398,7 +1398,7 @@ static void insert_trip_before_cb(GtkWidget *menuitem, GtkTreePath *path) static void remove_from_trip_cb(GtkWidget *menuitem, GtkTreePath *path) { - GtkTreeIter iter, newiter, parent; + GtkTreeIter iter, nextiter, *newiter, parent; GtkTreePath *nextpath; struct dive *dive; int idx; @@ -1411,26 +1411,28 @@ static void remove_from_trip_cb(GtkWidget *menuitem, GtkTreePath *path) in two right after this dive */ nextpath = gtk_tree_path_copy(path); gtk_tree_path_next(nextpath); - if (gtk_tree_model_get_iter(MODEL(dive_list), &newiter, nextpath)) + if (gtk_tree_model_get_iter(MODEL(dive_list), &nextiter, nextpath)) insert_trip_before(nextpath); - /* now create a new node as sibling right after the current parent */ - gtk_tree_store_insert_after(STORE(dive_list), &newiter, NULL, &parent); - copy_tree_node(&iter, &newiter); - - gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &idx, -1); + /* now move the dive to the top level, as sibling after its former parent */ + newiter = move_dive_between_trips(&iter, &parent, NULL, &parent, FALSE); + gtk_tree_model_get(MODEL(dive_list), newiter, DIVE_INDEX, &idx, -1); dive = get_dive(idx); if (dive->selected) { GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view)); - gtk_tree_selection_select_iter(selection, &newiter); + gtk_tree_selection_select_iter(selection, newiter); } - gtk_tree_store_remove(STORE(dive_list), &iter); /* 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)); + free(dive->divetrip); } + /* mark the dive as intentionally at the top level */ dive->tripflag = NO_TRIP; dive->divetrip = NULL; +#ifdef DEBUG_TRIP + dump_trip_list(); +#endif } void remove_trip(GtkTreePath *trippath, gboolean force_no_trip) @@ -1471,6 +1473,9 @@ void remove_trip(GtkTreePath *trippath, gboolean force_no_trip) gtk_tree_store_remove(STORE(dive_list), &parent); delete_trip(FIND_TRIP(dive_trip->when)); free(dive_trip); +#ifdef DEBUG_TRIP + dump_trip_list(); +#endif } void remove_trip_cb(GtkWidget *menuitem, GtkTreePath *trippath) -- cgit v1.2.3-70-g09d2 From b9d74580d0ef68393934d5d651318254f006b786 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Mon, 3 Sep 2012 20:51:09 -0700 Subject: Add ability to merge trip with trip below Miika suggested this - we should be able to merge with the trip below and not just the trip above (oh, and call them "above/below" instead of "previous"). Signed-off-by: Dirk Hohndel --- divelist.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/divelist.c b/divelist.c index 90b3f693d..c73ac5b22 100644 --- a/divelist.c +++ b/divelist.c @@ -1517,9 +1517,9 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int { GtkWidget *menu, *menuitem, *image; char editlabel[] = "Edit dives"; - GtkTreePath *path, *prevpath; - GtkTreeIter iter, previter; - int idx, previdx; + GtkTreePath *path, *prevpath, *nextpath; + GtkTreeIter iter, previter, nextiter; + int idx, previdx, nextidx; struct dive *dive; if (!gtk_tree_view_get_path_at_pos(tree_view, event->x, event->y, &path, NULL, NULL, NULL)) @@ -1544,11 +1544,21 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int gtk_tree_model_get_iter(MODEL(dive_list), &previter, prevpath)) { gtk_tree_model_get(MODEL(dive_list), &previter, DIVE_INDEX, &previdx, -1); if (previdx < 0) { - menuitem = gtk_menu_item_new_with_label("Merge trip with previous"); + menuitem = gtk_menu_item_new_with_label("Merge trip with trip above"); g_signal_connect(menuitem, "activate", G_CALLBACK(merge_trips_cb), path); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); } } + nextpath = gtk_tree_path_copy(path); + gtk_tree_path_next(nextpath); + if (gtk_tree_model_get_iter(MODEL(dive_list), &nextiter, nextpath)) { + gtk_tree_model_get(MODEL(dive_list), &nextiter, DIVE_INDEX, &nextidx, -1); + if (nextidx < 0) { + menuitem = gtk_menu_item_new_with_label("Merge trip with trip below"); + g_signal_connect(menuitem, "activate", G_CALLBACK(merge_trips_cb), nextpath); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + } + } menuitem = gtk_menu_item_new_with_label("Remove Trip"); g_signal_connect(menuitem, "activate", G_CALLBACK(remove_trip_cb), path); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); -- cgit v1.2.3-70-g09d2 From 6d0af91398b9ccd1cc29f087a9b695d0ffdf92fe Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Wed, 5 Sep 2012 13:31:56 -0700 Subject: More trip manipulations: remove selected dives from trip There are a few obvious trip manipulations on multiple dives that haven't been implemented, yet. This commit handles the case when we have multiple dives selected and right click on one of them. It now removes all of those dives from their trips (instead of just the one that we clicked on). Still todo is the inverse operation. Select a group of consecutive dives and turn them into a trip. Signed-off-by: Dirk Hohndel --- divelist.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 3 deletions(-) diff --git a/divelist.c b/divelist.c index c73ac5b22..33a421076 100644 --- a/divelist.c +++ b/divelist.c @@ -1396,7 +1396,7 @@ static void insert_trip_before_cb(GtkWidget *menuitem, GtkTreePath *path) turn_dive_into_trip(path); } -static void remove_from_trip_cb(GtkWidget *menuitem, GtkTreePath *path) +static void remove_from_trip(GtkTreePath *path) { GtkTreeIter iter, nextiter, *newiter, parent; GtkTreePath *nextpath; @@ -1406,7 +1406,6 @@ static void remove_from_trip_cb(GtkWidget *menuitem, GtkTreePath *path) gtk_tree_model_get_iter(MODEL(dive_list), &iter, path); if (!gtk_tree_model_iter_parent(MODEL(dive_list), &parent, &iter)) return; - /* if this isn't the last dive in a trip we simply split the trip in two right after this dive */ nextpath = gtk_tree_path_copy(path); @@ -1435,6 +1434,66 @@ static void remove_from_trip_cb(GtkWidget *menuitem, GtkTreePath *path) #endif } +static void remove_rowref_from_trip(gpointer data, gpointer user_data) +{ + GtkTreeRowReference *rowref = data; + GtkTreePath *path = gtk_tree_row_reference_get_path(rowref); + if (path) + remove_from_trip(path); +} + +static gboolean add_rowref_if_selected(GtkTreeModel *model, GtkTreePath *path, + GtkTreeIter *iter, gpointer data) +{ + GList **rowref_list = data; + int idx; + struct dive *dive; + + gtk_tree_model_get(MODEL(dive_list), iter, DIVE_INDEX, &idx, -1); + if (idx >=0 ) { + dive = get_dive(idx); + if (dive->selected) { + /* we need to store the Row References as those + stay valid across modifications of the model */ + GtkTreeRowReference *rowref; + rowref = gtk_tree_row_reference_new(TREEMODEL(dive_list), path); + *rowref_list = g_list_append(*rowref_list, rowref); + } + } + return FALSE; /* continue foreach loop */ +} + +static void remove_from_trip_cb(GtkWidget *menuitem, GtkTreePath *path) +{ + GtkTreeIter iter, parent; + struct dive *dive; + int idx; + + gtk_tree_model_get_iter(MODEL(dive_list), &iter, path); + if (!gtk_tree_model_iter_parent(MODEL(dive_list), &parent, &iter)) + return; + gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &idx, -1); + if (idx < 0 ) + return; + dive = get_dive(idx); + if (dive->selected) { + /* remove all the selected dives + since removing the dives from trips changes the model we need to + take the extra step of acquiring rowrefs before actually moving dives */ + GList *rowref_list = NULL; + gtk_tree_model_foreach(MODEL(dive_list), add_rowref_if_selected, &rowref_list); + /* We need to walk that list backwards as otherwise + the newly insered trips below dives that were + removed also mess with the validity */ + rowref_list = g_list_reverse(rowref_list); + g_list_foreach(rowref_list, remove_rowref_from_trip, NULL); + + } else { + /* just remove the dive the mouse pointer is on */ + remove_from_trip(path); + } +} + void remove_trip(GtkTreePath *trippath, gboolean force_no_trip) { GtkTreeIter newiter, parent, child, *lastiter = &parent; @@ -1588,7 +1647,10 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); } if (DIVE_IN_TRIP(dive)) { - menuitem = gtk_menu_item_new_with_label("Remove from trip"); + if (dive->selected && amount_selected > 1) + menuitem = gtk_menu_item_new_with_label("Remove selected dives from trip"); + else + menuitem = gtk_menu_item_new_with_label("Remove dive from trip"); g_signal_connect(menuitem, "activate", G_CALLBACK(remove_from_trip_cb), path); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); } -- cgit v1.2.3-70-g09d2 From 4679f4fbbc1f303b963b4eabebbbc9c684299619 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Wed, 5 Sep 2012 13:54:22 -0700 Subject: Avoid duplicate dive_trip entries When inserting a trip into the dive_trip_list we already check for duplicate trips, but we still kept the additional dive_trip around. With this change we instead replace it with the existing one. Signed-off-by: Dirk Hohndel --- dive.h | 10 ++++++---- divelist.c | 2 +- parse-xml.c | 7 +------ 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/dive.h b/dive.h index 384c7e4ca..29814c34e 100644 --- a/dive.h +++ b/dive.h @@ -305,14 +305,16 @@ static void dump_trip_list(void) /* 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 inline void insert_trip(struct dive *_trip) +static void inline insert_trip(struct dive **trip) { - GList *result = FIND_TRIP(_trip->when); + struct dive *dive_trip = *trip; + GList *result = FIND_TRIP(dive_trip->when); if (result) { if (! DIVE_TRIP(result)->location) - DIVE_TRIP(result)->location = _trip->location; + DIVE_TRIP(result)->location = dive_trip->location; + *trip = DIVE_TRIP(result); } else { - dive_trip_list = g_list_insert_sorted(dive_trip_list, (_trip), dive_date_cmp); + dive_trip_list = g_list_insert_sorted(dive_trip_list, dive_trip, dive_date_cmp); } #ifdef DEBUG_TRIP dump_trip_list(); diff --git a/divelist.c b/divelist.c index 33a421076..c52a94191 100644 --- a/divelist.c +++ b/divelist.c @@ -921,7 +921,7 @@ static struct dive *create_and_hookup_trip_from_dive(struct dive *dive) dive_trip->when = dive->when; if (dive->location) dive_trip->location = strdup(dive->location); - insert_trip(dive_trip); + insert_trip(&dive_trip); dive->divetrip = dive_trip; dive->tripflag = IN_TRIP; return dive_trip; diff --git a/parse-xml.c b/parse-xml.c index 1569c8c5c..a1eb21070 100644 --- a/parse-xml.c +++ b/parse-xml.c @@ -39,11 +39,6 @@ void record_dive(struct dive *dive) dive_table.nr = nr+1; } -void record_trip(struct dive *trip) -{ - insert_trip(trip); -} - static void delete_dive_renumber(struct dive **dives, int i, int nr) { struct dive *dive = dives[i]; @@ -1213,7 +1208,7 @@ static void trip_end(void) { if (!cur_trip) return; - record_trip(cur_trip); + insert_trip(&cur_trip); cur_trip = NULL; } -- cgit v1.2.3-70-g09d2