]> git.tdb.fi Git - ext/subsurface.git/commitdiff
Fix selecting and unselecting summary items
authorDirk Hohndel <dirk@hohndel.org>
Tue, 14 Aug 2012 04:11:09 +0000 (21:11 -0700)
committerDirk Hohndel <dirk@hohndel.org>
Tue, 14 Aug 2012 20:22:31 +0000 (13:22 -0700)
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 <dirk@hohndel.org>
divelist.c
statistics.c

index ea59b08758528b7aac5acf121902285111653db1..112307a1c28fbc89d7d96f8899b99f0767d7fdfc 100644 (file)
@@ -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);
index adfc9c77ac4f471922178d01de73c6d122b742c6..3a260066a259d58c2305ace1255f88e7f829e66f 100644 (file)
@@ -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, ...)