From 822b6409d752133090df24f5ca38f69656ff82b7 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Mon, 13 Aug 2012 21:11:09 -0700 Subject: [PATCH] Fix selecting and unselecting summary items The dive list now seems to behave intuitively. In order to do this we had to intercept the select function in addition to having a selection-changed callback. That way we can simulate the multi-level selection and unselection that was missing. Signed-off-by: Dirk Hohndel --- divelist.c | 85 +++++++++++++++++++++++++++++++++++++++------------- statistics.c | 23 +++++++++----- 2 files changed, 81 insertions(+), 27 deletions(-) diff --git a/divelist.c b/divelist.c index ea59b08..112307a 100644 --- a/divelist.c +++ b/divelist.c @@ -81,10 +81,9 @@ static void dump_model(GtkListStore *store) static GList *selected_dives; static int *selectiontracker; -/* if we are sorting by date and are using a tree model, we don't want the selection - to be a summary entry, but instead the first child below that entry. So we descend - down the tree until we find a leaf (entry with non-negative index) - */ +/* 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 + DIVE_INDEX) */ static void first_leaf(GtkTreeModel *model, GtkTreeIter *iter, int *diveidx) { GtkTreeIter parent; @@ -96,15 +95,57 @@ static void first_leaf(GtkTreeModel *model, GtkTreeIter *iter, int *diveidx) if (!gtk_tree_model_iter_children(model, iter, &parent)) /* we should never have a parent without child */ return; - /* clicking on a parent should toggle expand status */ - if(gtk_tree_view_row_expanded(GTK_TREE_VIEW(dive_list.tree_view), tpath)) - gtk_tree_view_collapse_row(GTK_TREE_VIEW(dive_list.tree_view), tpath); - else + 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); } } +/* if we click on a summary dive, we actually want to select / unselect + all the dives "below" it */ +static void select_children(GtkTreeModel *model, GtkTreeSelection * selection, + GtkTreeIter *iter, gboolean was_selected) +{ + int i, nr_children; + 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); + + 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); + if (was_selected) + gtk_tree_selection_unselect_iter(selection, iter); + else + gtk_tree_selection_select_iter(selection, iter); + } +} + +/* this is called _before_ the selection is changed, for every single entry; + * we simply have it call down the tree to make sure that summary items toggle + * their children */ +gboolean modify_selection_cb(GtkTreeSelection *selection, GtkTreeModel *model, + GtkTreePath *path, gboolean was_selected, gpointer userdata) +{ + GtkTreeIter iter; + int dive_idx; + + if (gtk_tree_model_get_iter(model, &iter, path)) { + gtk_tree_model_get(model, &iter, DIVE_INDEX, &dive_idx, -1); + if (dive_idx < 0) { + select_children(model, selection, &iter, was_selected); + } + } + /* allow this selection to proceed */ + return TRUE; +} + +/* this is called when gtk thinks that the selection has changed */ static void selection_cb(GtkTreeSelection *selection, gpointer userdata) { GtkTreeIter iter; @@ -120,7 +161,9 @@ static void selection_cb(GtkTreeSelection *selection, gpointer userdata) selectiontracker = realloc(selectiontracker, nr_selected * sizeof(int)); switch (nr_selected) { - case 0: /* keep showing the last selected dive */ + 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 */ @@ -128,21 +171,21 @@ static void selection_cb(GtkTreeSelection *selection, gpointer userdata) 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); - /* make sure we're not on a summary entry */ - first_leaf (GTK_TREE_MODEL(dive_list.model), &iter, &selected_dive); + /* 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? At this point I - * don't want to change the selected dive unless - * there is exactly one dive selected; not sure this + 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. - * I do however want to keep around which dives have - * been selected */ - /* TODO: - this also does not handle the case if a summary row is selected; - We should iterate and select all dives under that row */ + * 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(); @@ -792,8 +835,8 @@ static void fill_dive_list(void) if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(dive_list.model), &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); - /* make sure it's an actual dive that is selected */ 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); @@ -1093,6 +1136,8 @@ GtkWidget *dive_list_create(void) g_signal_connect(dive_list.listmodel, "sort-column-changed", G_CALLBACK(sort_column_change_cb), NULL); g_signal_connect(dive_list.treemodel, "sort-column-changed", G_CALLBACK(sort_column_change_cb), NULL); + gtk_tree_selection_set_select_function(selection, modify_selection_cb, NULL, NULL); + dive_list.container_widget = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(dive_list.container_widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); diff --git a/statistics.c b/statistics.c index adfc9c7..3a26006 100644 --- a/statistics.c +++ b/statistics.c @@ -142,30 +142,39 @@ static void process_all_dives(struct dive *dive, struct dive **prev_dive) } } +/* make sure we skip the selected summary entries */ void process_selected_dives(GList *selected_dives, int *selectiontracker, GtkTreeModel *model) { struct dive *dp; - unsigned int i; + unsigned int i, j; int idx; GtkTreeIter iter; GtkTreePath *path; memset(&stats_selection, 0, sizeof(stats_selection)); - stats_selection.selection_size = amount_selected; - for (i = 0; i < amount_selected; ++i) { + /* adjust amount_selected and remove negative index entries from list */ + for (i = 0, j = 0; j < amount_selected; ++i) { GValue value = {0, }; path = g_list_nth_data(selected_dives, i); if (gtk_tree_model_get_iter(model, &iter, path)) { gtk_tree_model_get_value(model, &iter, 0, &value); idx = g_value_get_int(&value); - dp = get_dive(idx); - if (dp) { - selectiontracker[i] = idx; - process_dive(dp, &stats_selection); + if (idx > 0) { + dp = get_dive(idx); + if (dp) { + selectiontracker[j] = idx; + process_dive(dp, &stats_selection); + j++; + continue; + } } } + /* we didn't process it, so shorten the list */ + amount_selected--; } + /* record the actual number of dives selected */ + stats_selection.selection_size = amount_selected; } static void set_label(GtkWidget *w, const char *fmt, ...) -- 2.43.0