X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=divelist.c;h=19ab600e8d6dec95121eb69b9221b4a74dc6dfab;hb=7cf0f6d5e19f57449078901a3730f9e40de3a012;hp=a4221f7b95b6dd5b410fa42c46eeb62aab4b57d0;hpb=621761233b2e1b139c07987b562ef2aa299ff35e;p=ext%2Fsubsurface.git diff --git a/divelist.c b/divelist.c index a4221f7..19ab600 100644 --- a/divelist.c +++ b/divelist.c @@ -53,10 +53,8 @@ enum { }; /* magic numbers that indicate (as negative values) model entries that - * are summary entries for day / month / year */ -#define NEW_DAY 1 -#define NEW_MON 2 -#define NEW_YR 3 + * are summary entries for a divetrip */ +#define NEW_TRIP 1 #ifdef DEBUG_MODEL static gboolean dump_model_entry(GtkTreeModel *model, GtkTreePath *path, @@ -80,6 +78,78 @@ static void dump_model(GtkListStore *store) static GList *selected_dives; static int *selectiontracker; +static int st_size = 0; + +gboolean is_in_st(int idx, int *atpos) +{ + int i; + + for (i = 0; i < amount_selected; i++) + if (selectiontracker[i] == idx) { + if (atpos) + *atpos = i; + return TRUE; + } + return FALSE; +} + +#if DEBUG_SELECTION_TRACKING +void dump_selection(void) +{ + int i; + + printf("currently selected are "); + for (i = 0; i < amount_selected; i++) + printf("%d ", selectiontracker[i]); + printf("\n"); +} +#endif + +void track_select(int idx) +{ + if (idx < 0) + return; + +#if DEBUG_SELECTION_TRACKING + printf("add %d to selection of %d entries\n", idx, amount_selected); +#endif + if (is_in_st(idx, NULL)) + return; + if (amount_selected >= st_size) { + selectiontracker = realloc(selectiontracker, dive_table.nr * sizeof(int)); + st_size = dive_table.nr; + } + selectiontracker[amount_selected] = idx; + amount_selected++; + if (amount_selected == 1) + selected_dive = idx; +#if DEBUG_SELECTION_TRACKING + printf("increased amount_selected to %d\n", amount_selected); + dump_selection(); +#endif +} + +void track_unselect(int idx) +{ + if (idx < 0) + return; + +#if DEBUG_SELECTION_TRACKING + printf("remove %d from selection of %d entries\n", idx, amount_selected); +#endif + int atpos; + + if (! is_in_st(idx, &atpos)) + return; + memmove(selectiontracker + atpos, + selectiontracker + atpos + 1, + (amount_selected - atpos - 1) * sizeof(int)); + amount_selected--; +#if DEBUG_SELECTION_TRACKING + printf("removed %d at pos %d and decreased amount_selected to %d\n", idx, atpos, amount_selected); + dump_selection(); +#endif +} /* when subsurface starts we want to have the last dive selected. So we simply walk to the first leaf (and skip the summary entries - which have negative @@ -98,6 +168,7 @@ static void first_leaf(GtkTreeModel *model, GtkTreeIter *iter, int *diveidx) 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); + track_select(*diveidx); } } @@ -107,15 +178,21 @@ static void select_children(GtkTreeModel *model, GtkTreeSelection * selection, GtkTreeIter *iter, gboolean was_selected) { int i, nr_children; + gboolean unexpand = FALSE; GtkTreeIter parent; GtkTreePath *tpath; memcpy(&parent, iter, sizeof(parent)); tpath = gtk_tree_model_get_path(model, &parent); - 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); + /* stupid gtk doesn't allow us to select rows that are invisible; so if the + user clicks on a row that isn't expanded, we briefly expand it, select the + children, and then unexpand it again */ + if(!gtk_tree_view_row_expanded(GTK_TREE_VIEW(dive_list.tree_view), tpath)) { + unexpand = TRUE; + gtk_tree_view_expand_row(GTK_TREE_VIEW(dive_list.tree_view), tpath, FALSE); + } nr_children = gtk_tree_model_iter_n_children(model, &parent); for (i = 0; i < nr_children; i++) { gtk_tree_model_iter_nth_child(model, iter, &parent, i); @@ -124,6 +201,18 @@ static void select_children(GtkTreeModel *model, GtkTreeSelection * selection, else gtk_tree_selection_select_iter(selection, iter); } + if (unexpand) + gtk_tree_view_collapse_row(GTK_TREE_VIEW(dive_list.tree_view), tpath); +} + +/* make sure that if we expand a summary row that is selected, the children show + up as selected, too */ +void row_expanded_cb(GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer data) +{ + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view)); + + if (gtk_tree_selection_path_is_selected(selection, path)) + select_children(GTK_TREE_MODEL(dive_list.model), selection, iter, FALSE); } /* this is called _before_ the selection is changed, for every single entry; @@ -137,6 +226,11 @@ gboolean modify_selection_cb(GtkTreeSelection *selection, GtkTreeModel *model, if (gtk_tree_model_get_iter(model, &iter, path)) { gtk_tree_model_get(model, &iter, DIVE_INDEX, &dive_idx, -1); + /* turns out we need to move the selectiontracker here */ + if (was_selected) + track_unselect(dive_idx); + else + track_select(dive_idx); if (dive_idx < 0) { select_children(model, selection, &iter, was_selected); } @@ -148,49 +242,8 @@ gboolean modify_selection_cb(GtkTreeSelection *selection, GtkTreeModel *model, /* this is called when gtk thinks that the selection has changed */ static void selection_cb(GtkTreeSelection *selection, gpointer userdata) { - GtkTreeIter iter; - GtkTreePath *path; - - int nr_selected = gtk_tree_selection_count_selected_rows(selection); - - if (selected_dives) { - g_list_foreach (selected_dives, (GFunc) gtk_tree_path_free, NULL); - g_list_free (selected_dives); - } - selected_dives = gtk_tree_selection_get_selected_rows(selection, NULL); - selectiontracker = realloc(selectiontracker, nr_selected * sizeof(int)); - - switch (nr_selected) { - case 0: /* there is no clear way to figure out which dive to show */ - amount_selected = 0; - selected_dive = -1; - return; - case 1: - /* just pick that dive as selected */ - amount_selected = 1; - path = g_list_nth_data(selected_dives, 0); - if (gtk_tree_model_get_iter(GTK_TREE_MODEL(dive_list.model), &iter, path)) { - gtk_tree_model_get(GTK_TREE_MODEL(dive_list.model), &iter, DIVE_INDEX, &selected_dive, -1); - /* due to the way this callback gets invoked it is possible that - in the process of unselecting a summary dive we get here with - just one summary dive selected - ignore that case */ - if (selected_dive < 0) { - amount_selected = 0; - return; - } - selectiontracker[0] = selected_dive; - repaint_dive(); - } - return; - default: /* multiple selections - what now? - * We don't change the selected dive unless there is exactly one dive selected; not sure this - * is the most intuitive solution. - * The dives that have been selected are processed */ - amount_selected = g_list_length(selected_dives); - process_selected_dives(selected_dives, selectiontracker, GTK_TREE_MODEL(dive_list.model)); - repaint_dive(); - return; - } + process_selected_dives(selected_dives, selectiontracker, GTK_TREE_MODEL(dive_list.model)); + repaint_dive(); } const char *star_strings[] = { @@ -240,23 +293,13 @@ static void date_data_func(GtkTreeViewColumn *col, tm = gmtime(&when); switch(idx) { - case -NEW_DAY: + case -NEW_TRIP: snprintf(buffer, sizeof(buffer), - "%s, %s %d, %d", + "Trip %s, %s %d, %d", weekday(tm->tm_wday), monthname(tm->tm_mon), tm->tm_mday, tm->tm_year + 1900); break; - case -NEW_MON: - snprintf(buffer, sizeof(buffer), - "%s %d", - monthname(tm->tm_mon), - tm->tm_year + 1900); - break; - case -NEW_YR: - snprintf(buffer, sizeof(buffer), - "%d", tm->tm_year + 1900); - break; default: snprintf(buffer, sizeof(buffer), "%s, %s %d, %d %02d:%02d", @@ -748,22 +791,20 @@ void update_dive_list_col_visibility(void) return; } -static int new_date(struct dive *dive, struct dive **last_dive, const int flag, time_t *tm_date) +/* random heuristic - not diving in three days implies new dive trip */ +#define TRIP_THRESHOLD 3600*24*3 +static int new_group(struct dive *dive, struct dive **last_dive, time_t *tm_date) { if (!last_dive) return TRUE; if (*last_dive) { struct dive *ldive = *last_dive; - struct tm tm1, tm2; - (void) gmtime_r(&dive->when, &tm1); - (void) gmtime_r(&ldive->when, &tm2); - if (tm1.tm_year == tm2.tm_year && - (tm1.tm_mon == tm2.tm_mon || flag > NEW_MON) && - (tm1.tm_mday == tm2.tm_mday || flag > NEW_DAY)) + if (abs(dive->when - ldive->when) < TRIP_THRESHOLD) { + *last_dive = dive; return FALSE; + } } - if (flag == NEW_DAY) - *last_dive = dive; + *last_dive = dive; if (tm_date) { struct tm *tm1 = gmtime(&dive->when); tm1->tm_sec = 0; @@ -776,10 +817,12 @@ static int new_date(struct dive *dive, struct dive **last_dive, const int flag, static void fill_dive_list(void) { - int i, j; - GtkTreeIter iter, parent_iter[NEW_YR + 2], *parents[NEW_YR + 2] = {NULL, }; + int i; + GtkTreeIter iter, parent_iter; GtkTreeStore *liststore, *treestore; struct dive *last_dive = NULL; + struct dive *first_trip_dive = NULL; + struct dive *last_trip_dive = NULL; time_t dive_date; treestore = GTK_TREE_STORE(dive_list.treemodel); @@ -789,23 +832,29 @@ static void fill_dive_list(void) while (--i >= 0) { struct dive *dive = dive_table.dives[i]; - for (j = NEW_YR; j >= NEW_DAY; j--) { - if (new_date(dive, &last_dive, j, &dive_date)) - { - gtk_tree_store_append(treestore, &parent_iter[j], parents[j+1]); - parents[j] = &parent_iter[j]; - gtk_tree_store_set(treestore, parents[j], - DIVE_INDEX, -j, - DIVE_NR, -j, - DIVE_DATE, dive_date, - DIVE_LOCATION, "", - DIVE_TEMPERATURE, 0, - DIVE_SAC, 0, + if (new_group(dive, &last_dive, &dive_date)) + { + /* make sure we display the first date of the trip in previous summary */ + if (first_trip_dive && last_trip_dive && last_trip_dive->when < first_trip_dive->when) + gtk_tree_store_set(treestore, &parent_iter, + DIVE_DATE, last_trip_dive->when, + DIVE_LOCATION, last_trip_dive->location, -1); - } + first_trip_dive = dive; + + gtk_tree_store_append(treestore, &parent_iter, NULL); + gtk_tree_store_set(treestore, &parent_iter, + DIVE_INDEX, -NEW_TRIP, + DIVE_NR, -NEW_TRIP, + DIVE_DATE, dive_date, + DIVE_LOCATION, dive->location, + DIVE_TEMPERATURE, 0, + DIVE_SAC, 0, + -1); } + last_trip_dive = dive; update_cylinder_related_info(dive); - gtk_tree_store_append(treestore, &iter, parents[NEW_DAY]); + gtk_tree_store_append(treestore, &iter, &parent_iter); gtk_tree_store_set(treestore, &iter, DIVE_INDEX, i, DIVE_NR, dive->number, @@ -840,8 +889,6 @@ static void fill_dive_list(void) first_leaf(GTK_TREE_MODEL(dive_list.model), &iter, &selected_dive); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view)); gtk_tree_selection_select_iter(selection, &iter); - selectiontracker = realloc(selectiontracker, sizeof(int)); - *selectiontracker = selected_dive; } } @@ -1143,6 +1190,7 @@ GtkWidget *dive_list_create(void) g_signal_connect_after(dive_list.tree_view, "realize", G_CALLBACK(realize_cb), NULL); g_signal_connect(dive_list.tree_view, "row-activated", G_CALLBACK(row_activated_cb), NULL); + g_signal_connect(dive_list.tree_view, "row-expanded", G_CALLBACK(row_expanded_cb), NULL); g_signal_connect(dive_list.tree_view, "button-press-event", G_CALLBACK(button_press_cb), NULL); g_signal_connect(dive_list.tree_view, "popup-menu", G_CALLBACK(popup_menu_cb), NULL); g_signal_connect(selection, "changed", G_CALLBACK(selection_cb), NULL);