]> git.tdb.fi Git - ext/subsurface.git/commitdiff
Merge branch 'tree2' of git://git.hohndel.org/subsurface
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 17 Aug 2012 03:39:49 +0000 (20:39 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 17 Aug 2012 03:39:49 +0000 (20:39 -0700)
Pull selection tracking fixes from Dirk Hohndel:
 "I just gave up on gtk tracking our selection.  Way too much pain.  The
  implementation below has seen some testing with the debugging code
  enabled and seems to work - but it needs more banging onto it, I'm
  sure.

  Ideally I'd like to leave the debug code in, ask people on the mailing
  list to play with it and report any inconsistencies.  After that I'll
  be happy to remove it again."

* 'tree2' of git://git.hohndel.org/subsurface:
  Stop relying on gtk to track which dives are selected

1  2 
divelist.c

diff --combined divelist.c
index de64bd88ceecf2b30ab91831382f30ee00666d8a,19ab600e8d6dec95121eb69b9221b4a74dc6dfab..0e1b40dd6f71abb64f9acd32082b6df06585875f
@@@ -26,7 -26,7 +26,7 @@@ struct DiveList 
        GtkWidget    *container_widget;
        GtkTreeStore *model, *listmodel, *treemodel;
        GtkTreeViewColumn *nr, *date, *stars, *depth, *duration, *location;
 -      GtkTreeViewColumn *temperature, *cylinder, *nitrox, *sac, *otu;
 +      GtkTreeViewColumn *temperature, *cylinder, *totalweight, *suit, *nitrox, *sac, *otu;
        int changed;
  };
  
@@@ -44,8 -44,6 +44,8 @@@ enum 
        DIVE_DEPTH,             /* int: dive->maxdepth in mm */
        DIVE_DURATION,          /* int: in seconds */
        DIVE_TEMPERATURE,       /* int: in mkelvin */
 +      DIVE_TOTALWEIGHT,       /* int: in grams */
 +      DIVE_SUIT,              /* "wet, 3mm" */
        DIVE_CYLINDER,
        DIVE_NITROX,            /* int: dummy */
        DIVE_SAC,               /* int: in ml/min */
@@@ -79,6 -77,79 +79,78 @@@ static void dump_model(GtkListStore *st
  #endif
  
  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
@@@ -97,6 -168,7 +169,7 @@@ static void first_leaf(GtkTreeModel *mo
                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);
        }
  }
  
@@@ -106,15 -178,21 +179,21 @@@ static void select_children(GtkTreeMode
                        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);
                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;
@@@ -136,6 -226,11 +227,11 @@@ gboolean modify_selection_cb(GtkTreeSel
  
        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);
                }
  /* 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[] = {
@@@ -405,38 -459,6 +460,38 @@@ newmax
        *o2low_p = mino2;
  }
  
 +static int total_weight(struct dive *dive)
 +{
 +      int i, total_grams = 0;
 +
 +      if (dive)
 +              for (i=0; i< MAX_WEIGHTSYSTEMS; i++)
 +                      total_grams += dive->weightsystem[i].weight.grams;
 +      return total_grams;
 +}
 +
 +static void weight_data_func(GtkTreeViewColumn *col,
 +                           GtkCellRenderer *renderer,
 +                           GtkTreeModel *model,
 +                           GtkTreeIter *iter,
 +                           gpointer data)
 +{
 +      int indx, decimals;
 +      double value;
 +      char buffer[80];
 +      struct dive *dive;
 +
 +      gtk_tree_model_get(model, iter, DIVE_INDEX, &indx, -1);
 +      dive = get_dive(indx);
 +      value = get_weight_units(total_weight(dive), &decimals, NULL);
 +      if (value == 0.0)
 +              *buffer = '\0';
 +      else
 +              snprintf(buffer, sizeof(buffer), "%.*f", decimals, value);
 +
 +      g_object_set(renderer, "text", buffer, NULL);
 +}
 +
  static gint nitrox_sort_func(GtkTreeModel *model,
        GtkTreeIter *iter_a,
        GtkTreeIter *iter_b,
@@@ -671,11 -693,6 +726,11 @@@ static void get_cylinder(struct dive *d
        get_string(str, dive->cylinder[0].type.description);
  }
  
 +static void get_suit(struct dive *dive, char **str)
 +{
 +      get_string(str, dive->suit);
 +}
 +
  /*
   * Set up anything that could have changed due to editing
   * of dive information; we need to do this for both models,
@@@ -691,12 -708,11 +746,12 @@@ static void fill_one_dive(struct dive *
                          GtkTreeModel *model,
                          GtkTreeIter *iter)
  {
 -      char *location, *cylinder;
 +      char *location, *cylinder, *suit;
        GtkTreeStore *othermodel;
  
        get_cylinder(dive, &cylinder);
        get_location(dive, &location);
 +      get_suit(dive, &suit);
  
        gtk_tree_store_set(GTK_TREE_STORE(model), iter,
                DIVE_NR, dive->number,
                DIVE_RATING, dive->rating,
                DIVE_SAC, dive->sac,
                DIVE_OTU, dive->otu,
 +              DIVE_TOTALWEIGHT, total_weight(dive),
 +              DIVE_SUIT, suit,
                -1);
 +
 +      free(location);
 +      free(cylinder);
 +      free(suit);
 +
        if (model == GTK_TREE_MODEL(dive_list.treemodel))
                othermodel = dive_list.listmodel;
        else
@@@ -769,9 -778,6 +824,9 @@@ void update_dive_list_units(void
        (void) get_temp_units(0, &unit);
        gtk_tree_view_column_set_title(dive_list.temperature, unit);
  
 +      (void) get_weight_units(0, NULL, &unit);
 +      gtk_tree_view_column_set_title(dive_list.totalweight, unit);
 +
        gtk_tree_model_foreach(model, set_one_dive, NULL);
  }
  
@@@ -779,8 -785,6 +834,8 @@@ void update_dive_list_col_visibility(vo
  {
        gtk_tree_view_column_set_visible(dive_list.cylinder, visible_cols.cylinder);
        gtk_tree_view_column_set_visible(dive_list.temperature, visible_cols.temperature);
 +      gtk_tree_view_column_set_visible(dive_list.totalweight, visible_cols.totalweight);
 +      gtk_tree_view_column_set_visible(dive_list.suit, visible_cols.suit);
        gtk_tree_view_column_set_visible(dive_list.nitrox, visible_cols.nitrox);
        gtk_tree_view_column_set_visible(dive_list.sac, visible_cols.sac);
        gtk_tree_view_column_set_visible(dive_list.otu, visible_cols.otu);
@@@ -872,8 -876,6 +927,8 @@@ static void fill_dive_list(void
                        DIVE_LOCATION, dive->location,
                        DIVE_RATING, dive->rating,
                        DIVE_TEMPERATURE, dive->watertemp.mkelvin,
 +                      DIVE_TOTALWEIGHT, 0,
 +                      DIVE_SUIT, dive->suit,
                        DIVE_SAC, 0,
                        -1);
        }
                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;
        }
  }
  
@@@ -913,8 -913,6 +966,8 @@@ static struct divelist_column 
        [DIVE_DEPTH] = { "ft", depth_data_func, NULL, ALIGN_RIGHT },
        [DIVE_DURATION] = { "min", duration_data_func, NULL, ALIGN_RIGHT },
        [DIVE_TEMPERATURE] = { UTF8_DEGREE "F", temperature_data_func, NULL, ALIGN_RIGHT, &visible_cols.temperature },
 +      [DIVE_TOTALWEIGHT] = { "lbs", weight_data_func, NULL, ALIGN_RIGHT, &visible_cols.totalweight },
 +      [DIVE_SUIT] = { "Suit", NULL, NULL, ALIGN_LEFT, &visible_cols.suit },
        [DIVE_CYLINDER] = { "Cyl", NULL, NULL, 0, &visible_cols.cylinder },
        [DIVE_NITROX] = { "O" UTF8_SUBSCRIPT_2 "%", nitrox_data_func, nitrox_sort_func, 0, &visible_cols.nitrox },
        [DIVE_SAC] = { "SAC", sac_data_func, NULL, 0, &visible_cols.sac },
@@@ -1142,8 -1140,6 +1195,8 @@@ GtkWidget *dive_list_create(void
                                G_TYPE_INT,                     /* Depth */
                                G_TYPE_INT,                     /* Duration */
                                G_TYPE_INT,                     /* Temperature */
 +                              G_TYPE_INT,                     /* Total weight */
 +                              G_TYPE_STRING,                  /* Suit */
                                G_TYPE_STRING,                  /* Cylinder */
                                G_TYPE_INT,                     /* Nitrox */
                                G_TYPE_INT,                     /* SAC */
                                G_TYPE_INT,                     /* Depth */
                                G_TYPE_INT,                     /* Duration */
                                G_TYPE_INT,                     /* Temperature */
 +                              G_TYPE_INT,                     /* Total weight */
 +                              G_TYPE_STRING,                  /* Suit */
                                G_TYPE_STRING,                  /* Cylinder */
                                G_TYPE_INT,                     /* Nitrox */
                                G_TYPE_INT,                     /* SAC */
        dive_list.depth = divelist_column(&dive_list, dl_column + DIVE_DEPTH);
        dive_list.duration = divelist_column(&dive_list, dl_column + DIVE_DURATION);
        dive_list.temperature = divelist_column(&dive_list, dl_column + DIVE_TEMPERATURE);
 +      dive_list.totalweight = divelist_column(&dive_list, dl_column + DIVE_TOTALWEIGHT);
 +      dive_list.suit = divelist_column(&dive_list, dl_column + DIVE_SUIT);
        dive_list.cylinder = divelist_column(&dive_list, dl_column + DIVE_CYLINDER);
        dive_list.nitrox = divelist_column(&dive_list, dl_column + DIVE_NITROX);
        dive_list.sac = divelist_column(&dive_list, dl_column + DIVE_SAC);
  
        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);